001: package soot.jimple.toolkits.thread.transaction;
002:
003: /* Soot - a J*va Optimization Framework
004: * Copyright (C) 2003 Ondrej Lhotak
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the
018: * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
019: * Boston, MA 02111-1307, USA.
020: */
021:
022: import soot.*;
023: import soot.jimple.*;
024: import soot.jimple.toolkits.callgraph.*;
025: import soot.jimple.toolkits.pointer.*;
026: import soot.jimple.toolkits.thread.*;
027: import soot.toolkits.scalar.*;
028:
029: import java.util.*;
030:
031: /** Generates side-effect information from a PointsToAnalysis.
032: * Uses various heuristic rules to filter out side-effects that
033: * are not visible to other threads in a Transactional program.
034: */
035: class WholeObject {
036: Type type;
037:
038: public WholeObject(Type type) {
039: this .type = type;
040: }
041:
042: public WholeObject() {
043: this .type = null;
044: }
045:
046: public String toString() {
047: return "All Fields" + (type == null ? "" : " (" + type + ")");
048: }
049:
050: public int hashCode() {
051: if (type == null)
052: return 1;
053: return type.hashCode();
054: }
055:
056: public boolean equals(Object o) {
057: if (type == null)
058: return true;
059: if (o instanceof WholeObject) {
060: WholeObject other = (WholeObject) o;
061: if (other.type == null)
062: return true;
063: else
064: return (type == other.type);
065: } else if (o instanceof FieldRef) {
066: return type == ((FieldRef) o).getType();
067: } else if (o instanceof SootFieldRef) {
068: return type == ((SootFieldRef) o).type();
069: } else if (o instanceof SootField) {
070: return type == ((SootField) o).getType();
071: } else {
072: return true;
073: }
074: }
075: }
076:
077: public class TransactionAwareSideEffectAnalysis {
078: PointsToAnalysis pa;
079: CallGraph cg;
080: Map<SootMethod, CodeBlockRWSet> methodToNTReadSet = new HashMap<SootMethod, CodeBlockRWSet>();
081: Map<SootMethod, CodeBlockRWSet> methodToNTWriteSet = new HashMap<SootMethod, CodeBlockRWSet>();
082: int rwsetcount = 0;
083: TransactionVisibleEdgesPred tve;
084: TransitiveTargets tt;
085: TransitiveTargets normaltt;
086: SideEffectAnalysis normalsea;
087: Collection<Transaction> transactions;
088: EncapsulatedObjectAnalysis eoa;
089: ThreadLocalObjectsAnalysis tlo;
090:
091: public Vector sigBlacklist;
092: public Vector sigReadGraylist;
093: public Vector sigWriteGraylist;
094: public Vector subSigBlacklist;
095:
096: public void findNTRWSets(SootMethod method) {
097: if (methodToNTReadSet.containsKey(method)
098: && methodToNTWriteSet.containsKey(method))
099: return;
100:
101: CodeBlockRWSet read = null;
102: CodeBlockRWSet write = null;
103: for (Iterator sIt = method.retrieveActiveBody().getUnits()
104: .iterator(); sIt.hasNext();) {
105: final Stmt s = (Stmt) sIt.next();
106:
107: boolean ignore = false;
108:
109: // Ignore Reads/Writes inside another transaction
110: if (transactions != null) {
111: Iterator<Transaction> tnIt = transactions.iterator();
112: while (tnIt.hasNext()) {
113: Transaction tn = tnIt.next();
114: if (tn.units.contains(s) || tn.prepStmt == s) {
115: ignore = true;
116: break;
117: }
118: }
119: }
120:
121: if (!ignore) {
122: RWSet ntr = ntReadSet(method, s);
123: if (ntr != null) {
124: if (read == null)
125: read = new CodeBlockRWSet();
126: read.union(ntr);
127: }
128: RWSet ntw = ntWriteSet(method, s);
129: if (ntw != null) {
130: if (write == null)
131: write = new CodeBlockRWSet();
132: write.union(ntw);
133: }
134: if (s.containsInvokeExpr()) {
135: InvokeExpr ie = s.getInvokeExpr();
136: SootMethod calledMethod = ie.getMethod();
137:
138: // if it's an invoke on certain lib methods
139: if (calledMethod.getDeclaringClass().toString()
140: .startsWith("java.util")
141: || calledMethod.getDeclaringClass()
142: .toString().startsWith("java.lang")) {
143: // then it gets approximated
144: Local base = null;
145: if (ie instanceof InstanceInvokeExpr)
146: base = (Local) ((InstanceInvokeExpr) ie)
147: .getBase();
148:
149: if (tlo == null
150: || base == null
151: || !tlo.isObjectThreadLocal(base,
152: method)) {
153: // add its approximated read set to read
154: RWSet r;
155: // String InvokeSig = calledMethod.getSubSignature();
156: // if( InvokeSig.equals("void notify()") || InvokeSig.equals("void notifyAll()") ||
157: // InvokeSig.equals("void wait()") || InvokeSig.equals("void wait(long)") || InvokeSig.equals("void wait(long,int)"))
158: // r = approximatedReadSet(method, s, base, true);
159: // else
160: r = approximatedReadSet(method, s, base,
161: true);
162: if (read == null)
163: read = new CodeBlockRWSet();
164: if (r != null)
165: read.union(r);
166:
167: // add its approximated write set to write
168: RWSet w;
169: // if( InvokeSig.equals("void notify()") || InvokeSig.equals("void notifyAll()") ||
170: // InvokeSig.equals("void wait()") || InvokeSig.equals("void wait(long)") || InvokeSig.equals("void wait(long,int)"))
171: // w = approximatedWriteSet(method, s, base, true);
172: // else
173: w = approximatedWriteSet(method, s, base,
174: true);
175: if (write == null)
176: write = new CodeBlockRWSet();
177: if (w != null)
178: write.union(w);
179: }
180: }
181: }
182: }
183: }
184: methodToNTReadSet.put(method, read);
185: methodToNTWriteSet.put(method, write);
186: }
187:
188: public void setExemptTransaction(Transaction tn) {
189: tve.setExemptTransaction(tn);
190: }
191:
192: public RWSet nonTransitiveReadSet(SootMethod method) {
193: findNTRWSets(method);
194: return methodToNTReadSet.get(method);
195: }
196:
197: public RWSet nonTransitiveWriteSet(SootMethod method) {
198: findNTRWSets(method);
199: return methodToNTWriteSet.get(method);
200: }
201:
202: public TransactionAwareSideEffectAnalysis(PointsToAnalysis pa,
203: CallGraph cg, Collection<Transaction> transactions,
204: ThreadLocalObjectsAnalysis tlo) {
205: this .pa = pa;
206: this .cg = cg;
207: this .tve = new TransactionVisibleEdgesPred(transactions);
208: this .tt = new TransitiveTargets(cg, new Filter(tve));
209: this .normaltt = new TransitiveTargets(cg, null);
210: this .normalsea = new SideEffectAnalysis(pa, cg);
211: this .transactions = transactions;
212: this .eoa = new EncapsulatedObjectAnalysis();
213: this .tlo = tlo; // can be null
214:
215: sigBlacklist = new Vector(); // Signatures of methods known to have effective read/write sets of size 0
216: // Math does not have any synchronization risks, we think :-)
217: /* sigBlacklist.add("<java.lang.Math: double abs(double)>");
218: sigBlacklist.add("<java.lang.Math: double min(double,double)>");
219: sigBlacklist.add("<java.lang.Math: double sqrt(double)>");
220: sigBlacklist.add("<java.lang.Math: double pow(double,double)>");
221: //*/
222: // sigBlacklist.add("");
223: sigReadGraylist = new Vector(); // Signatures of methods whose effects must be approximated
224: sigWriteGraylist = new Vector();
225:
226: /* sigReadGraylist.add("<java.util.Vector: boolean remove(java.lang.Object)>");
227: sigWriteGraylist.add("<java.util.Vector: boolean remove(java.lang.Object)>");
228:
229: sigReadGraylist.add("<java.util.Vector: boolean add(java.lang.Object)>");
230: sigWriteGraylist.add("<java.util.Vector: boolean add(java.lang.Object)>");
231:
232: sigReadGraylist.add("<java.util.Vector: java.lang.Object clone()>");
233: // sigWriteGraylist.add("<java.util.Vector: java.lang.Object clone()>");
234:
235: sigReadGraylist.add("<java.util.Vector: java.lang.Object get(int)>");
236: // sigWriteGraylist.add("<java.util.Vector: java.lang.Object get(int)>");
237:
238: sigReadGraylist.add("<java.util.Vector: java.util.List subList(int,int)>");
239: // sigWriteGraylist.add("<java.util.Vector: java.util.List subList(int,int)>");
240:
241: sigReadGraylist.add("<java.util.List: void clear()>");
242: sigWriteGraylist.add("<java.util.List: void clear()>");
243: //*/
244: subSigBlacklist = new Vector(); // Subsignatures of methods on all objects known to have read/write sets of size 0
245: /* subSigBlacklist.add("java.lang.Class class$(java.lang.String)");
246: subSigBlacklist.add("void notify()");
247: subSigBlacklist.add("void notifyAll()");
248: subSigBlacklist.add("void wait()");
249: subSigBlacklist.add("void <clinit>()");
250: //*/
251:
252: }
253:
254: private RWSet ntReadSet(SootMethod method, Stmt stmt) {
255: if (stmt instanceof AssignStmt) {
256: AssignStmt a = (AssignStmt) stmt;
257: Value r = a.getRightOp();
258: if (r instanceof NewExpr) // IGNORE NEW STATEMENTS
259: return null;
260: return addValue(r, method, stmt);
261: }
262: return null;
263: }
264:
265: private HashMap<Stmt, RWSet> RCache = new HashMap<Stmt, RWSet>();
266:
267: public RWSet approximatedReadSet(SootMethod method, Stmt stmt,
268: Value specialRead, boolean allFields) {// used for stmts with method calls where the effect of the method call should be approximated by 0 or 1 reads (plus reads of all args)
269: CodeBlockRWSet ret = new CodeBlockRWSet();
270: if (specialRead != null) {
271: if (specialRead instanceof Local) {
272: Local vLocal = (Local) specialRead;
273: PointsToSet base = pa.reachingObjects(vLocal);
274:
275: // Get an RWSet containing all fields
276: // Set possibleTypes = base.possibleTypes();
277: // for(Iterator pTypeIt = possibleTypes.iterator(); pTypeIt.hasNext(); )
278: // {
279: Type pType = vLocal.getType(); //(Type) pTypeIt.next();
280: if (pType instanceof RefType) {
281: SootClass baseTypeClass = ((RefType) pType)
282: .getSootClass();
283: if (!baseTypeClass.isInterface()) {
284: List<SootClass> baseClasses = Scene.v()
285: .getActiveHierarchy()
286: .getSuperclassesOfIncluding(
287: baseTypeClass);
288: if (!baseClasses.contains(RefType.v(
289: "java.lang.Exception").getSootClass())) {
290: for (SootClass baseClass : baseClasses) {
291: for (Iterator baseFieldIt = baseClass
292: .getFields().iterator(); baseFieldIt
293: .hasNext();) {
294: SootField baseField = (SootField) baseFieldIt
295: .next();
296: if (!baseField.isStatic())
297: ret
298: .addFieldRef(base,
299: baseField);
300: }
301: }
302: }
303: }
304: }
305: // }
306:
307: // If desired, prune to just actually-read fields
308: if (!allFields) {
309: // Should actually get a list of fields of this object that are read/written
310: // make fake RW set of <base, all fields> (use a special class)
311: // intersect with the REAL RW set of this stmt
312: CodeBlockRWSet allRW = ret;
313: ret = new CodeBlockRWSet();
314: RWSet normalRW;
315: if (RCache.containsKey(stmt)) {
316: normalRW = RCache.get(stmt);
317: } else {
318: normalRW = normalsea.readSet(method, stmt);
319: RCache.put(stmt, normalRW);
320: }
321: if (normalRW != null) {
322: for (Iterator fieldsIt = normalRW.getFields()
323: .iterator(); fieldsIt.hasNext();) {
324: Object field = fieldsIt.next();
325: if (allRW.containsField(field)) {
326: PointsToSet otherBase = normalRW
327: .getBaseForField(field);
328: if (otherBase instanceof FullObjectSet) {
329: ret.addFieldRef(otherBase, field);
330: } else {
331: if (base
332: .hasNonEmptyIntersection(otherBase))
333: ret.addFieldRef(base, field); // should use intersection of bases!!!
334: }
335: }
336: }
337: }
338: }
339: } else if (specialRead instanceof FieldRef) {
340: ret.union(addValue(specialRead, method, stmt));
341: }
342: }
343: if (stmt.containsInvokeExpr()) {
344: int argCount = stmt.getInvokeExpr().getArgCount();
345: for (int i = 0; i < argCount; i++)
346: ret.union(addValue(stmt.getInvokeExpr().getArg(i),
347: method, stmt));
348: }
349: if (stmt instanceof AssignStmt) {
350: AssignStmt a = (AssignStmt) stmt;
351: Value r = a.getRightOp();
352: ret.union(addValue(r, method, stmt));
353: }
354: return ret;
355: }
356:
357: public RWSet readSet(SootMethod method, Stmt stmt, Transaction tn,
358: HashSet uses) {
359: boolean ignore = false;
360: if (stmt.containsInvokeExpr()) {
361: InvokeExpr ie = stmt.getInvokeExpr();
362: SootMethod calledMethod = ie.getMethod();
363: if (ie instanceof StaticInvokeExpr) {
364: // ignore = false;
365: } else if (ie instanceof InstanceInvokeExpr) {
366: if (calledMethod.getSubSignature().startsWith(
367: "void <init>")
368: && eoa.isInitMethodPureOnObject(calledMethod)) {
369: ignore = true;
370: } else if (tlo != null
371: && !tlo.hasNonThreadLocalEffects(method, ie)) {
372: ignore = true;
373: }
374: }
375: }
376:
377: boolean inaccessibleUses = false;
378: RWSet ret = new CodeBlockRWSet();
379: tve.setExemptTransaction(tn);
380: Iterator<MethodOrMethodContext> targets = tt.iterator(stmt);
381: while (!ignore && targets.hasNext()) {
382: SootMethod target = (SootMethod) targets.next();
383: // if( target.isNative() ) {
384: // if( ret == null ) ret = new SiteRWSet();
385: // ret.setCallsNative();
386: // } else
387: if (target.isConcrete()) {
388:
389: // Special treatment for java.util and java.lang... their children are filtered out by the ThreadVisibleEdges filter
390: // An approximation of their behavior must be performed here
391: if (target.getDeclaringClass().toString().startsWith(
392: "java.util")
393: || target.getDeclaringClass().toString()
394: .startsWith("java.lang")) {
395: /* RWSet ntr;
396: if(stmt.getInvokeExpr() instanceof InstanceInvokeExpr)
397: {
398: Local base = (Local)((InstanceInvokeExpr)stmt.getInvokeExpr()).getBase();
399:
400: // Add base object and args to set of possibly contributing uses at this stmt
401: if(!inaccessibleUses)
402: {
403: uses.add(base);
404: int argCount = stmt.getInvokeExpr().getArgCount();
405: for(int i = 0; i < argCount; i++)
406: {
407: if(addValue( stmt.getInvokeExpr().getArg(i), method, stmt ) != null)
408: uses.add(stmt.getInvokeExpr().getArg(i));
409: }
410: }
411:
412: // Add base object to read set
413: String InvokeSig = target.getSubSignature();
414: if( InvokeSig.equals("void notify()") || InvokeSig.equals("void notifyAll()") ||
415: InvokeSig.equals("void wait()") || InvokeSig.equals("void wait(long)") || InvokeSig.equals("void wait(long,int)"))
416: {
417: ntr = approximatedReadSet(method, stmt, base, target, true);
418: }
419: else
420: {
421: ntr = approximatedReadSet(method, stmt, base, target, false);
422: }
423: }
424: else
425: {
426: ntr = approximatedReadSet(method, stmt, null, target, false);
427: }
428: ret.union(ntr);
429: */} else {// note that all library functions have already been filtered out (by name) via the filter
430: // passed to the TransitiveTargets constructor.
431: RWSet ntr = nonTransitiveReadSet(target);
432: if (ntr != null) {
433: // uses.clear();
434: // inaccessibleUses = true;
435: ret.union(ntr);
436: }
437: }
438: }
439: }
440: RWSet ntr = ntReadSet(method, stmt);
441: if (inaccessibleUses == false && ntr != null
442: && stmt instanceof AssignStmt) {
443: AssignStmt a = (AssignStmt) stmt;
444: Value r = a.getRightOp();
445: if (r instanceof InstanceFieldRef) {
446: uses.add(((InstanceFieldRef) r).getBase());
447: } else if (r instanceof StaticFieldRef) {
448: uses.add(r);
449: } else if (r instanceof ArrayRef) {
450: uses.add(((ArrayRef) r).getBase());
451: }
452: }
453: ret.union(ntr);
454:
455: if (stmt.containsInvokeExpr()) {
456: InvokeExpr ie = stmt.getInvokeExpr();
457: SootMethod calledMethod = ie.getMethod();
458:
459: // if it's an invoke on certain lib methods
460: if (calledMethod.getDeclaringClass().toString().startsWith(
461: "java.util")
462: || calledMethod.getDeclaringClass().toString()
463: .startsWith("java.lang")) {
464: // then it gets approximated as a NTReadSet
465: Local base = null;
466: if (ie instanceof InstanceInvokeExpr)
467: base = (Local) ((InstanceInvokeExpr) ie).getBase();
468:
469: if (tlo == null || base == null
470: || !tlo.isObjectThreadLocal(base, method)) {
471: // add its approximated read set to read
472: RWSet r;
473: // String InvokeSig = calledMethod.getSubSignature();
474: // if( InvokeSig.equals("void notify()") || InvokeSig.equals("void notifyAll()") ||
475: // InvokeSig.equals("void wait()") || InvokeSig.equals("void wait(long)") || InvokeSig.equals("void wait(long,int)"))
476: // r = approximatedReadSet(method, stmt, base, true);
477: // else
478: r = approximatedReadSet(method, stmt, base, true);
479: if (r != null)
480: ret.union(r);
481:
482: int argCount = stmt.getInvokeExpr().getArgCount();
483: for (int i = 0; i < argCount; i++)
484: uses.add(ie.getArg(i));
485: if (base != null)
486: uses.add(base);
487: }
488: }
489: }
490:
491: return ret;
492: }
493:
494: private RWSet ntWriteSet(SootMethod method, Stmt stmt) {
495: if (stmt instanceof AssignStmt) {
496: AssignStmt a = (AssignStmt) stmt;
497: Value l = a.getLeftOp();
498: return addValue(l, method, stmt);
499: }
500: return null;
501: }
502:
503: private HashMap<Stmt, RWSet> WCache = new HashMap<Stmt, RWSet>();
504:
505: public RWSet approximatedWriteSet(SootMethod method, Stmt stmt,
506: Value v, boolean allFields) {// used for stmts with method calls where the effect of the method call should be approximated by 0 or 1 writes
507: CodeBlockRWSet ret = new CodeBlockRWSet();
508: if (v != null) {
509: if (v instanceof Local) {
510: Local vLocal = (Local) v;
511: PointsToSet base = pa.reachingObjects(vLocal);
512:
513: // Get an RWSet containing all fields
514: // Set possibleTypes = base.possibleTypes();
515: // for(Iterator pTypeIt = possibleTypes.iterator(); pTypeIt.hasNext(); )
516: // {
517: Type pType = vLocal.getType(); //(Type) pTypeIt.next();
518: if (pType instanceof RefType) {
519: SootClass baseTypeClass = ((RefType) pType)
520: .getSootClass();
521: if (!baseTypeClass.isInterface()) {
522: List<SootClass> baseClasses = Scene.v()
523: .getActiveHierarchy()
524: .getSuperclassesOfIncluding(
525: baseTypeClass);
526: if (!baseClasses.contains(RefType.v(
527: "java.lang.Exception").getSootClass())) {
528: for (SootClass baseClass : baseClasses) {
529: for (Iterator baseFieldIt = baseClass
530: .getFields().iterator(); baseFieldIt
531: .hasNext();) {
532: SootField baseField = (SootField) baseFieldIt
533: .next();
534: if (!baseField.isStatic())
535: ret
536: .addFieldRef(base,
537: baseField);
538: }
539: }
540: }
541: }
542: }
543: // }
544:
545: // If desired, prune to just actually-written fields
546: if (!allFields) {
547: // Should actually get a list of fields of this object that are read/written
548: // make fake RW set of <base, all fields> (use a special class)
549: // intersect with the REAL RW set of this stmt
550: CodeBlockRWSet allRW = ret;
551: ret = new CodeBlockRWSet();
552: RWSet normalRW;
553: if (WCache.containsKey(stmt)) {
554: normalRW = WCache.get(stmt);
555: } else {
556: normalRW = normalsea.writeSet(method, stmt);
557: WCache.put(stmt, normalRW);
558: }
559: if (normalRW != null) {
560: for (Iterator fieldsIt = normalRW.getFields()
561: .iterator(); fieldsIt.hasNext();) {
562: Object field = fieldsIt.next();
563: if (allRW.containsField(field)) {
564: PointsToSet otherBase = normalRW
565: .getBaseForField(field);
566: if (otherBase instanceof FullObjectSet) {
567: ret.addFieldRef(otherBase, field);
568: } else {
569: if (base
570: .hasNonEmptyIntersection(otherBase))
571: ret.addFieldRef(base, field); // should use intersection of bases!!!
572: }
573: }
574: }
575: }
576: }
577: } else if (v instanceof FieldRef) {
578: ret.union(addValue(v, method, stmt));
579: }
580: }
581: if (stmt instanceof AssignStmt) {
582: AssignStmt a = (AssignStmt) stmt;
583: Value l = a.getLeftOp();
584: ret.union(addValue(l, method, stmt));
585: }
586: return ret;
587: }
588:
589: public RWSet writeSet(SootMethod method, Stmt stmt, Transaction tn,
590: Set uses) {
591: boolean ignore = false;
592: if (stmt.containsInvokeExpr()) {
593: InvokeExpr ie = stmt.getInvokeExpr();
594: SootMethod calledMethod = ie.getMethod();
595: if (ie instanceof StaticInvokeExpr) {
596: // ignore = false;
597: } else if (ie instanceof InstanceInvokeExpr) {
598: if (calledMethod.getSubSignature().startsWith(
599: "void <init>")
600: && eoa.isInitMethodPureOnObject(calledMethod)) {
601: ignore = true;
602: } else if (tlo != null
603: && !tlo.hasNonThreadLocalEffects(method, ie)) {
604: ignore = true;
605: }
606: }
607: }
608:
609: boolean inaccessibleUses = false;
610: RWSet ret = new CodeBlockRWSet();
611: tve.setExemptTransaction(tn);
612: Iterator<MethodOrMethodContext> targets = tt.iterator(stmt);
613: while (!ignore && targets.hasNext()) {
614: SootMethod target = (SootMethod) targets.next();
615: // if( target.isNative() ) {
616: // if( ret == null ) ret = new SiteRWSet();
617: // ret.setCallsNative();
618: // } else
619: if (target.isConcrete()) {
620: if (target.getDeclaringClass().toString().startsWith(
621: "java.util")
622: || target.getDeclaringClass().toString()
623: .startsWith("java.lang")) {
624: /* RWSet ntw;
625: if(stmt.getInvokeExpr() instanceof InstanceInvokeExpr)
626: {
627: Local base = (Local)((InstanceInvokeExpr)stmt.getInvokeExpr()).getBase();
628:
629: // Add base object to set of possibly contributing uses at this stmt
630: if(!inaccessibleUses)
631: uses.add(base);
632:
633: // Add base object to write set
634: String InvokeSig = target.getSubSignature();
635: if( InvokeSig.equals("void notify()") || InvokeSig.equals("void notifyAll()") ||
636: InvokeSig.equals("void wait()") || InvokeSig.equals("void wait(long)") || InvokeSig.equals("void wait(long,int)"))
637: {
638: ntw = approximatedWriteSet(method, stmt, base, true);
639: }
640: else
641: {
642: ntw = approximatedWriteSet(method, stmt, base, false);
643: }
644: }
645: else
646: {
647: ntw = approximatedWriteSet(method, stmt, null, false);
648: }
649: ret.union(ntw);
650: */
651: } else {
652: RWSet ntw = nonTransitiveWriteSet(target);
653: if (ntw != null) {
654: // inaccessibleUses = true;
655: // uses.clear();
656: ret.union(ntw);
657: }
658: }
659: }
660: }
661:
662: RWSet ntw = ntWriteSet(method, stmt);
663: if (!inaccessibleUses && ntw != null
664: && stmt instanceof AssignStmt) {
665: AssignStmt a = (AssignStmt) stmt;
666: Value l = a.getLeftOp();
667: if (l instanceof InstanceFieldRef) {
668: uses.add(((InstanceFieldRef) l).getBase());
669: } else if (l instanceof StaticFieldRef) {
670: uses.add(l);
671: } else if (l instanceof ArrayRef) {
672: uses.add(((ArrayRef) l).getBase());
673: }
674: }
675: ret.union(ntw);
676:
677: if (stmt.containsInvokeExpr()) {
678: InvokeExpr ie = stmt.getInvokeExpr();
679: SootMethod calledMethod = ie.getMethod();
680:
681: // if it's an invoke on certain lib methods
682: if (calledMethod.getDeclaringClass().toString().startsWith(
683: "java.util")
684: || calledMethod.getDeclaringClass().toString()
685: .startsWith("java.lang")) {
686: // then it gets approximated as a NTReadSet
687: Local base = null;
688: if (ie instanceof InstanceInvokeExpr)
689: base = (Local) ((InstanceInvokeExpr) ie).getBase();
690:
691: if (tlo == null || base == null
692: || !tlo.isObjectThreadLocal(base, method)) {
693: // add its approximated read set to read
694: RWSet w;
695: // String InvokeSig = calledMethod.getSubSignature();
696: // if( InvokeSig.equals("void notify()") || InvokeSig.equals("void notifyAll()") ||
697: // InvokeSig.equals("void wait()") || InvokeSig.equals("void wait(long)") || InvokeSig.equals("void wait(long,int)"))
698: // w = approximatedWriteSet(method, stmt, base, true);
699: // else
700: w = approximatedWriteSet(method, stmt, base, true);
701: if (w != null)
702: ret.union(w);
703:
704: if (base != null)
705: uses.add(base);
706: }
707: }
708: }
709:
710: return ret;
711: }
712:
713: public RWSet valueRWSet(Value v, SootMethod m, Stmt s,
714: Transaction tn) {
715: RWSet ret = null;
716:
717: if (tlo != null) {
718: // fields/elements of local objects may be read/written w/o visible
719: // side effects if the base object is local, or if the base is "this"
720: // and the field itself is local (since "this" is always assumed shared)
721: if (v instanceof InstanceFieldRef) {
722: InstanceFieldRef ifr = (InstanceFieldRef) v;
723: if (m.isConcrete()
724: && !m.isStatic()
725: && m.retrieveActiveBody().getThisLocal()
726: .equivTo(ifr.getBase())
727: && tlo.isObjectThreadLocal(ifr, m))
728: return null;
729: else if (tlo.isObjectThreadLocal(ifr.getBase(), m))
730: return null;
731: } else if (v instanceof ArrayRef
732: && tlo.isObjectThreadLocal(
733: ((ArrayRef) v).getBase(), m))
734: return null;
735: }
736:
737: if (v instanceof InstanceFieldRef) {
738: InstanceFieldRef ifr = (InstanceFieldRef) v;
739: PointsToSet base = pa
740: .reachingObjects((Local) ifr.getBase());
741: ret = new StmtRWSet();
742: ret.addFieldRef(base, ifr.getField());
743: } else if (v instanceof StaticFieldRef) {
744: StaticFieldRef sfr = (StaticFieldRef) v;
745: ret = new StmtRWSet();
746: ret.addGlobal(sfr.getField());
747: } else if (v instanceof ArrayRef) {
748: ArrayRef ar = (ArrayRef) v;
749: PointsToSet base = pa.reachingObjects((Local) ar.getBase());
750: ret = new StmtRWSet();
751: ret.addFieldRef(base, PointsToAnalysis.ARRAY_ELEMENTS_NODE);
752: } else if (v instanceof Local) {
753: Local vLocal = (Local) v;
754: PointsToSet base = pa.reachingObjects(vLocal);
755: ret = new CodeBlockRWSet();
756: CodeBlockRWSet stmtRW = new CodeBlockRWSet();
757: RWSet rSet = readSet(m, s, tn, new HashSet());
758: if (rSet != null)
759: stmtRW.union(rSet);
760: RWSet wSet = writeSet(m, s, tn, new HashSet());
761: if (wSet != null)
762: stmtRW.union(wSet);
763: // Should actually get a list of fields of this object that are read/written
764: // make fake RW set of <base, all fields> (use a special class)
765: // intersect with the REAL RW set of this stmt
766: for (Iterator fieldsIt = stmtRW.getFields().iterator(); fieldsIt
767: .hasNext();) {
768: Object field = fieldsIt.next();
769: PointsToSet fieldBase = stmtRW.getBaseForField(field);
770: if (base.hasNonEmptyIntersection(fieldBase))
771: ret.addFieldRef(base, field); // should use intersection of bases!!!
772: }
773: } else {
774: return null;
775: }
776: return ret;
777: }
778:
779: protected RWSet addValue(Value v, SootMethod m, Stmt s) {
780: RWSet ret = null;
781:
782: if (tlo != null) {
783: // fields/elements of local objects may be read/written w/o visible
784: // side effects if the base object is local, or if the base is "this"
785: // and the field itself is local (since "this" is always assumed shared)
786: if (v instanceof InstanceFieldRef) {
787: InstanceFieldRef ifr = (InstanceFieldRef) v;
788: if (m.isConcrete()
789: && !m.isStatic()
790: && m.retrieveActiveBody().getThisLocal()
791: .equivTo(ifr.getBase())
792: && tlo.isObjectThreadLocal(ifr, m))
793: return null;
794: else if (tlo.isObjectThreadLocal(ifr.getBase(), m))
795: return null;
796: } else if (v instanceof ArrayRef
797: && tlo.isObjectThreadLocal(
798: ((ArrayRef) v).getBase(), m))
799: return null;
800: }
801:
802: // if(tlo != null &&
803: // (( v instanceof InstanceFieldRef && tlo.isObjectThreadLocal(((InstanceFieldRef)v).getBase(), m) ) ||
804: // ( v instanceof ArrayRef && tlo.isObjectThreadLocal(((ArrayRef)v).getBase(), m) )))
805: // return null;
806:
807: if (v instanceof InstanceFieldRef) {
808: InstanceFieldRef ifr = (InstanceFieldRef) v;
809: Local baseLocal = (Local) ifr.getBase();
810: PointsToSet base = pa.reachingObjects(baseLocal);
811: if (baseLocal.getType() instanceof RefType) {
812: SootClass baseClass = ((RefType) baseLocal.getType())
813: .getSootClass();
814: if (Scene.v().getActiveHierarchy()
815: .isClassSubclassOfIncluding(
816: baseClass,
817: RefType.v("java.lang.Exception")
818: .getSootClass()))
819: return null;
820: }
821: ret = new StmtRWSet();
822: ret.addFieldRef(base, ifr.getField());
823: } else if (v instanceof StaticFieldRef) {
824: StaticFieldRef sfr = (StaticFieldRef) v;
825: ret = new StmtRWSet();
826: ret.addGlobal(sfr.getField());
827: } else if (v instanceof ArrayRef) {
828: ArrayRef ar = (ArrayRef) v;
829: PointsToSet base = pa.reachingObjects((Local) ar.getBase());
830: ret = new StmtRWSet();
831: ret.addFieldRef(base, PointsToAnalysis.ARRAY_ELEMENTS_NODE);
832: }
833: return ret;
834: }
835:
836: public String toString() {
837: return "TransactionAwareSideEffectAnalysis: PA=" + pa + " CG="
838: + cg;
839: }
840: }
|