001: /* Soot - a J*va Optimization Framework
002: * Copyright (C) 2003 Ondrej Lhotak
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the
016: * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
017: * Boston, MA 02111-1307, USA.
018: */
019:
020: package soot.jimple.toolkits.pointer;
021:
022: import soot.*;
023: import soot.jimple.*;
024: import soot.jimple.toolkits.callgraph.*;
025: import java.util.*;
026:
027: /** Generates side-effect information from a PointsToAnalysis. */
028: public class SideEffectAnalysis {
029: PointsToAnalysis pa;
030: CallGraph cg;
031: Map<SootMethod, MethodRWSet> methodToNTReadSet = new HashMap<SootMethod, MethodRWSet>();
032: Map<SootMethod, MethodRWSet> methodToNTWriteSet = new HashMap<SootMethod, MethodRWSet>();
033: int rwsetcount = 0;
034: TransitiveTargets tt;
035:
036: public void findNTRWSets(SootMethod method) {
037: if (methodToNTReadSet.containsKey(method)
038: && methodToNTWriteSet.containsKey(method))
039: return;
040:
041: MethodRWSet read = null;
042: MethodRWSet write = null;
043: for (Iterator sIt = method.retrieveActiveBody().getUnits()
044: .iterator(); sIt.hasNext();) {
045: final Stmt s = (Stmt) sIt.next();
046: RWSet ntr = ntReadSet(method, s);
047: if (ntr != null) {
048: if (read == null)
049: read = new MethodRWSet();
050: read.union(ntr);
051: }
052: RWSet ntw = ntWriteSet(method, s);
053: if (ntw != null) {
054: if (write == null)
055: write = new MethodRWSet();
056: write.union(ntw);
057: }
058: }
059: methodToNTReadSet.put(method, read);
060: methodToNTWriteSet.put(method, write);
061: SootClass c = method.getDeclaringClass();
062: }
063:
064: public RWSet nonTransitiveReadSet(SootMethod method) {
065: findNTRWSets(method);
066: return methodToNTReadSet.get(method);
067: }
068:
069: public RWSet nonTransitiveWriteSet(SootMethod method) {
070: findNTRWSets(method);
071: return methodToNTWriteSet.get(method);
072: }
073:
074: public SideEffectAnalysis(PointsToAnalysis pa, CallGraph cg) {
075: this .pa = pa;
076: this .cg = cg;
077: this .tt = new TransitiveTargets(cg);
078: }
079:
080: public SideEffectAnalysis(PointsToAnalysis pa, CallGraph cg,
081: Filter filter) {
082: // This constructor allows customization of call graph edges to
083: // consider via the use of a transitive targets filter.
084: // For example, using the NonClinitEdgesPred, you can create a
085: // SideEffectAnalysis that will ignore static initializers
086: // - R. Halpert 2006-12-02
087: this .pa = pa;
088: this .cg = cg;
089: this .tt = new TransitiveTargets(cg, filter);
090: }
091:
092: private RWSet ntReadSet(SootMethod method, Stmt stmt) {
093: if (stmt instanceof AssignStmt) {
094: AssignStmt a = (AssignStmt) stmt;
095: Value r = a.getRightOp();
096: return addValue(r, method, stmt);
097: }
098: return null;
099: }
100:
101: public RWSet readSet(SootMethod method, Stmt stmt) {
102: RWSet ret = null;
103: Iterator<MethodOrMethodContext> targets = tt.iterator(stmt);
104: while (targets.hasNext()) {
105: SootMethod target = (SootMethod) targets.next();
106: if (target.isNative()) {
107: if (ret == null)
108: ret = new SiteRWSet();
109: ret.setCallsNative();
110: } else if (target.isConcrete()) {
111: RWSet ntr = nonTransitiveReadSet(target);
112: if (ntr != null) {
113: if (ret == null)
114: ret = new SiteRWSet();
115: ret.union(ntr);
116: }
117: }
118: }
119: if (ret == null)
120: return ntReadSet(method, stmt);
121: ret.union(ntReadSet(method, stmt));
122: return ret;
123: }
124:
125: private RWSet ntWriteSet(SootMethod method, Stmt stmt) {
126: if (stmt instanceof AssignStmt) {
127: AssignStmt a = (AssignStmt) stmt;
128: Value l = a.getLeftOp();
129: return addValue(l, method, stmt);
130: }
131: return null;
132: }
133:
134: public RWSet writeSet(SootMethod method, Stmt stmt) {
135: RWSet ret = null;
136: Iterator<MethodOrMethodContext> targets = tt.iterator(stmt);
137: while (targets.hasNext()) {
138: SootMethod target = (SootMethod) targets.next();
139: if (target.isNative()) {
140: if (ret == null)
141: ret = new SiteRWSet();
142: ret.setCallsNative();
143: } else if (target.isConcrete()) {
144: RWSet ntw = nonTransitiveWriteSet(target);
145: if (ntw != null) {
146: if (ret == null)
147: ret = new SiteRWSet();
148: ret.union(ntw);
149: }
150: }
151: }
152: if (ret == null)
153: return ntWriteSet(method, stmt);
154: ret.union(ntWriteSet(method, stmt));
155: return ret;
156: }
157:
158: protected RWSet addValue(Value v, SootMethod m, Stmt s) {
159: RWSet ret = null;
160: if (v instanceof InstanceFieldRef) {
161: InstanceFieldRef ifr = (InstanceFieldRef) v;
162: PointsToSet base = pa
163: .reachingObjects((Local) ifr.getBase());
164: ret = new StmtRWSet();
165: ret.addFieldRef(base, ifr.getField());
166: } else if (v instanceof StaticFieldRef) {
167: StaticFieldRef sfr = (StaticFieldRef) v;
168: ret = new StmtRWSet();
169: ret.addGlobal(sfr.getField());
170: } else if (v instanceof ArrayRef) {
171: ArrayRef ar = (ArrayRef) v;
172: PointsToSet base = pa.reachingObjects((Local) ar.getBase());
173: ret = new StmtRWSet();
174: ret.addFieldRef(base, PointsToAnalysis.ARRAY_ELEMENTS_NODE);
175: }
176: return ret;
177: }
178:
179: public String toString() {
180: return "SideEffectAnalysis: PA=" + pa + " CG=" + cg;
181: }
182: }
|