001: /* Soot - a J*va Optimization Framework
002: * Copyright (C) 2000 Feng Qian
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: /*
021: * Modified by the Sable Research Group and others 1997-1999.
022: * See the 'credits' file distributed with Soot for the complete list of
023: * contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot)
024: */
025:
026: package soot.jimple.toolkits.annotation.arraycheck;
027:
028: import soot.options.*;
029:
030: import soot.*;
031: import soot.jimple.*;
032: import soot.util.*;
033: import soot.toolkits.scalar.*;
034: import soot.toolkits.graph.*;
035: import java.util.*;
036:
037: public class ClassFieldAnalysis {
038: public ClassFieldAnalysis(Singletons.Global g) {
039: }
040:
041: public static ClassFieldAnalysis v() {
042: return G
043: .v()
044: .soot_jimple_toolkits_annotation_arraycheck_ClassFieldAnalysis();
045: }
046:
047: private final boolean final_in = true;
048: private final boolean private_in = true;
049:
050: /* A map hold class object to other information
051: *
052: * SootClass --> FieldInfoTable
053: */
054:
055: private final Map<SootClass, Hashtable<SootField, IntValueContainer>> classToFieldInfoMap = new HashMap<SootClass, Hashtable<SootField, IntValueContainer>>();
056:
057: protected void internalTransform(SootClass c) {
058: if (classToFieldInfoMap.containsKey(c))
059: return;
060:
061: /* Summerize class information here. */
062: Date start = new Date();
063: if (Options.v().verbose())
064: G.v().out.println("[] ClassFieldAnalysis started on : "
065: + start + " for " + c.getPackageName()
066: + c.getName());
067:
068: Hashtable<SootField, IntValueContainer> fieldInfoTable = new Hashtable<SootField, IntValueContainer>();
069: classToFieldInfoMap.put(c, fieldInfoTable);
070:
071: /* Who is the candidate for analysis?
072: Int, Array, field. Also it should be PRIVATE now.
073: */
074: HashSet<SootField> candidSet = new HashSet<SootField>();
075:
076: int arrayTypeFieldNum = 0;
077:
078: Iterator fieldIt = c.getFields().iterator();
079: while (fieldIt.hasNext()) {
080: SootField field = (SootField) fieldIt.next();
081: int modifiers = field.getModifiers();
082:
083: Type type = field.getType();
084: if (type instanceof ArrayType) {
085: if ((final_in && ((modifiers & Modifier.FINAL) != 0))
086: || (private_in && ((modifiers & Modifier.PRIVATE) != 0))) {
087: candidSet.add(field);
088: arrayTypeFieldNum++;
089: }
090: }
091: }
092:
093: if (arrayTypeFieldNum == 0) {
094: if (Options.v().verbose())
095: G.v().out
096: .println("[] ClassFieldAnalysis finished with nothing");
097: return;
098: }
099:
100: /* For FINAL field, it only needs to scan the <clinit> and <init> methods. */
101:
102: /* For PRIVATE field, <clinit> is scanned to make sure that it is always
103: assigned a value before other uses. And no other assignment in other methods.*/
104:
105: /* The fastest way to determine the value of one field may get.
106: Scan all method to get all definitions, and summerize the final value.
107: For PRIVATE STATIC field, if it is not always assigned value, it may count null pointer
108: exception before array exception */
109:
110: Iterator methodIt = c.methodIterator();
111: while (methodIt.hasNext()) {
112: ScanMethod((SootMethod) methodIt.next(), candidSet,
113: fieldInfoTable);
114: }
115:
116: Date finish = new Date();
117: if (Options.v().verbose()) {
118: long runtime = finish.getTime() - start.getTime();
119: long mins = runtime / 60000;
120: long secs = (runtime % 60000) / 1000;
121: G.v().out
122: .println("[] ClassFieldAnalysis finished normally. "
123: + "It took "
124: + mins
125: + " mins and "
126: + secs
127: + " secs.");
128: }
129: }
130:
131: public Object getFieldInfo(SootField field) {
132: SootClass c = field.getDeclaringClass();
133:
134: Hashtable fieldInfoTable = classToFieldInfoMap.get(c);
135:
136: if (fieldInfoTable == null) {
137: internalTransform(c);
138: fieldInfoTable = classToFieldInfoMap.get(c);
139: }
140:
141: return fieldInfoTable.get(field);
142: }
143:
144: /* method, to be scanned
145: candidates, the candidate set of fields, fields with value TOP are moved out of the set.
146: fieldinfo, keep the field -> value.
147: */
148:
149: public void ScanMethod(SootMethod method,
150: Set<SootField> candidates,
151: Hashtable<SootField, IntValueContainer> fieldinfo) {
152: if (!method.isConcrete())
153: return;
154:
155: Body body = method.retrieveActiveBody();
156:
157: if (body == null)
158: return;
159:
160: /* no array locals, then definitely it has no array type field references. */
161: {
162: boolean hasArrayLocal = false;
163:
164: Chain locals = body.getLocals();
165:
166: Iterator localIt = locals.iterator();
167: while (localIt.hasNext()) {
168: Local local = (Local) localIt.next();
169: Type type = local.getType();
170:
171: if (type instanceof ArrayType) {
172: hasArrayLocal = true;
173: break;
174: }
175: }
176:
177: if (!hasArrayLocal) {
178: return;
179: }
180: }
181:
182: /* only take care of the first dimension of array size */
183: /* check the assignment of fields. */
184:
185: /* Linearly scan the method body, if it has field references in candidate set. */
186: /* Only a.f = ... needs consideration.
187: this.f, or other.f are treated as same because we summerize the field as a class's field.
188: */
189:
190: HashMap<Stmt, SootField> stmtfield = new HashMap<Stmt, SootField>();
191:
192: {
193: Iterator unitIt = body.getUnits().iterator();
194: while (unitIt.hasNext()) {
195: Stmt stmt = (Stmt) unitIt.next();
196: if (stmt.containsFieldRef()) {
197: Value leftOp = ((AssignStmt) stmt).getLeftOp();
198: if (leftOp instanceof FieldRef) {
199: FieldRef fref = (FieldRef) leftOp;
200: SootField field = fref.getField();
201:
202: if (candidates.contains(field))
203: stmtfield.put(stmt, field);
204: }
205: }
206: }
207:
208: if (stmtfield.size() == 0) {
209: return;
210: }
211: }
212:
213: if (Options.v().verbose()) {
214: G.v().out.println("[] ScanMethod for field started.");
215: }
216:
217: /* build D/U web, find the value of each candidate */
218: {
219: UnitGraph g = new ExceptionalUnitGraph(body);
220: LocalDefs localDefs = new SmartLocalDefs(g,
221: new SimpleLiveLocals(g));
222:
223: Set entries = stmtfield.entrySet();
224:
225: Iterator entryIt = entries.iterator();
226: while (entryIt.hasNext()) {
227: Map.Entry entry = (Map.Entry) entryIt.next();
228: Stmt where = (Stmt) entry.getKey();
229: SootField which = (SootField) entry.getValue();
230:
231: IntValueContainer length = new IntValueContainer();
232:
233: // take out the right side of assign stmt
234: Value rightOp = ((AssignStmt) where).getRightOp();
235:
236: if (rightOp instanceof Local) {
237: // tracing down the defs of right side local.
238: Local local = (Local) rightOp;
239: DefinitionStmt usestmt = (DefinitionStmt) where;
240:
241: while (length.isBottom()) {
242: List<Unit> defs = localDefs.getDefsOfAt(local,
243: usestmt);
244: if (defs.size() == 1) {
245: usestmt = (DefinitionStmt) defs.get(0);
246:
247: if (Options.v().debug())
248: G.v().out.println(" " + usestmt);
249:
250: Value tmp_rhs = usestmt.getRightOp();
251: if ((tmp_rhs instanceof NewArrayExpr)
252: || (tmp_rhs instanceof NewMultiArrayExpr)) {
253: Value size;
254:
255: if (tmp_rhs instanceof NewArrayExpr)
256: size = ((NewArrayExpr) tmp_rhs)
257: .getSize();
258: else
259: size = ((NewMultiArrayExpr) tmp_rhs)
260: .getSize(0);
261:
262: if (size instanceof IntConstant)
263: length
264: .setValue(((IntConstant) size).value);
265: else if (size instanceof Local) {
266: local = (Local) size;
267:
268: // defs = localDefs.getDefsOfAt((Local)size, (Unit)usestmt);
269:
270: continue;
271: } else
272: length.setTop();
273: } else if (tmp_rhs instanceof IntConstant) {
274: length
275: .setValue(((IntConstant) tmp_rhs).value);
276: } else if (tmp_rhs instanceof Local) {
277: // defs = localDefs.getDefsOfAt((Local)tmp_rhs, usestmt);
278: local = (Local) tmp_rhs;
279:
280: continue;
281: } else
282: length.setTop();
283: } else
284: length.setTop();
285: }
286: } else
287: /* it could be null */
288: continue;
289:
290: IntValueContainer oldv = fieldinfo.get(which);
291:
292: /* the length is top, set the field to top */
293: if (length.isTop()) {
294: if (oldv == null)
295: fieldinfo.put(which, length.dup());
296: else
297: oldv.setTop();
298:
299: /* remove from the candidate set. */
300: candidates.remove(which);
301: } else if (length.isInteger()) {
302: if (oldv == null) {
303: fieldinfo.put(which, length.dup());
304: } else {
305: if (oldv.isInteger()
306: && oldv.getValue() != length.getValue()) {
307: oldv.setTop();
308: candidates.remove(which);
309: }
310: }
311: }
312: }
313: }
314:
315: if (Options.v().verbose()) {
316: G.v().out.println("[] ScanMethod finished.");
317: }
318: }
319: }
|