Skip to content

Commit 8d201bb

Browse files
authored
Merge pull request #2138 from MarcMil/mdev
Fix the ConstantValueToInitializerTransformer & Performance optimizations for type resolver
2 parents 8bf0272 + abed019 commit 8d201bb

File tree

3 files changed

+121
-50
lines changed

3 files changed

+121
-50
lines changed

src/main/java/soot/jimple/toolkits/typing/fast/TypeResolver.java

+49-7
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
import java.util.Map;
3737
import java.util.Map.Entry;
3838
import java.util.Set;
39+
import java.util.concurrent.ExecutorService;
40+
import java.util.concurrent.Executors;
41+
import java.util.concurrent.TimeUnit;
3942

4043
import soot.ArrayType;
4144
import soot.BooleanType;
@@ -69,6 +72,7 @@
6972
import soot.jimple.SpecialInvokeExpr;
7073
import soot.jimple.Stmt;
7174
import soot.jimple.toolkits.typing.Util;
75+
import soot.jimple.toolkits.typing.fast.UseChecker.UseCheckerCache;
7276
import soot.toolkits.scalar.LocalDefs;
7377

7478
/**
@@ -83,17 +87,22 @@
8387
* @author Ben Bellamy
8488
*/
8589
public class TypeResolver {
90+
private static final int SINGLE_THREAD_LIMIT = 100000;
91+
private static int NUM_CORES = Math.max(1, Runtime.getRuntime().availableProcessors() - 2);
92+
8693
protected final JimpleBody jb;
8794

8895
private List<DefinitionStmt> assignments;
8996
private HashMap<Local, BitSet> depends;
9097
private Set<Local> singleAssignments;
9198
private BitSet simple;
9299
private final LocalGenerator localGenerator;
100+
private final UseCheckerCache useCheckerCache;
93101

94102
public TypeResolver(JimpleBody jb) {
95103
this.jb = jb;
96104
this.localGenerator = Scene.v().createLocalGenerator(jb);
105+
this.useCheckerCache = new UseCheckerCache(jb);
97106

98107
}
99108

@@ -402,7 +411,7 @@ private ITyping typePromotion(ITyping tg) {
402411
}
403412

404413
protected UseChecker createUseChecker(JimpleBody jb) {
405-
return new UseChecker(jb);
414+
return new UseChecker(jb, useCheckerCache);
406415
}
407416

408417
protected TypePromotionUseVisitor createTypePromotionUseVisitor(JimpleBody jb, ITyping tg) {
@@ -453,14 +462,47 @@ protected CastInsertionUseVisitor createCastInsertionUseVisitor(ITyping tg, IHie
453462
private ITyping minCasts(Collection<ITyping> sigma, IHierarchy h, int[] count) {
454463
count[0] = -1;
455464
ITyping r = null;
456-
for (ITyping tg : sigma) {
457-
int n = this.insertCasts(tg, h, true);
458-
if (count[0] == -1 || n < count[0]) {
459-
count[0] = n;
460-
r = tg;
465+
if (sigma.size() <= SINGLE_THREAD_LIMIT) {
466+
for (ITyping tg : sigma) {
467+
int n = this.insertCasts(tg, h, true);
468+
if (count[0] == -1 || n < count[0]) {
469+
count[0] = n;
470+
r = tg;
471+
}
461472
}
473+
return r;
474+
} else {
475+
ExecutorService executionService = Executors.newFixedThreadPool(NUM_CORES);
476+
ITyping[] minTyping = new ITyping[1];
477+
try {
478+
for (ITyping tg : sigma) {
479+
executionService.submit(new Runnable() {
480+
481+
@Override
482+
public void run() {
483+
int n = insertCasts(tg, h, true);
484+
if (count[0] == -1 || n < count[0]) {
485+
synchronized (count) {
486+
if (count[0] == -1 || n < count[0]) {
487+
count[0] = n;
488+
minTyping[0] = tg;
489+
}
490+
}
491+
}
492+
}
493+
494+
});
495+
}
496+
} finally {
497+
executionService.shutdown();
498+
try {
499+
executionService.awaitTermination(100, TimeUnit.DAYS);
500+
} catch (InterruptedException e) {
501+
throw new RuntimeException("Interrupted during type resolving", e);
502+
}
503+
}
504+
return minTyping[0];
462505
}
463-
return r;
464506
}
465507

466508
static class WorklistElement {

src/main/java/soot/jimple/toolkits/typing/fast/UseChecker.java

+70-27
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,53 @@ public class UseChecker extends AbstractStmtSwitch {
117117
private ITyping tg;
118118
private IUseVisitor uv;
119119

120-
private LocalDefs defs = null;
121-
private LocalUses uses = null;
122-
123120
private static final Logger logger = LoggerFactory.getLogger(UseChecker.class);
124121

122+
public static class UseCheckerCache {
123+
private LocalDefs defs = null;
124+
private LocalUses uses = null;
125+
126+
private final Type objectType = Scene.v().getObjectType();
127+
private final JimpleBody body;
128+
129+
public UseCheckerCache(JimpleBody body) {
130+
this.body = body;
131+
}
132+
133+
public Type getObjectType() {
134+
return objectType;
135+
}
136+
137+
public LocalDefs getDefs() {
138+
LocalDefs d = defs;
139+
if (d == null) {
140+
d = G.v().soot_toolkits_scalar_LocalDefsFactory().newLocalDefs(body);
141+
defs = d;
142+
}
143+
return d;
144+
}
145+
146+
public LocalUses getUses() {
147+
LocalUses u = uses;
148+
if (u != null) {
149+
return u;
150+
}
151+
u = LocalUses.Factory.newLocalUses(body, getDefs());
152+
uses = u;
153+
return u;
154+
}
155+
}
156+
157+
private UseCheckerCache cache;
158+
125159
public UseChecker(JimpleBody jb) {
126160
this.jb = jb;
161+
cache = new UseCheckerCache(jb);
162+
}
163+
164+
public UseChecker(JimpleBody jb, UseCheckerCache cache) {
165+
this.jb = jb;
166+
this.cache = cache;
127167
}
128168

129169
public void check(ITyping tg, IUseVisitor uv) {
@@ -203,6 +243,9 @@ public void caseAssignStmt(AssignStmt stmt) {
203243
Value lhs = stmt.getLeftOp();
204244
Value rhs = stmt.getRightOp();
205245
Type tlhs = null;
246+
LocalDefs defs = cache.defs;
247+
LocalUses uses = cache.uses;
248+
final IUseVisitor uv = this.uv;
206249

207250
if (lhs instanceof Local) {
208251
tlhs = this.tg.get((Local) lhs);
@@ -221,10 +264,10 @@ public void caseAssignStmt(AssignStmt stmt) {
221264
// is java.lang.Object
222265
if (rhs instanceof Local) {
223266
Type rhsType = this.tg.get((Local) rhs);
224-
if ((tgType == Scene.v().getObjectType() && rhsType instanceof PrimType) || tgType instanceof WeakObjectType) {
267+
if ((tgType == cache.getObjectType() && rhsType instanceof PrimType) || tgType instanceof WeakObjectType) {
225268
if (defs == null) {
226-
defs = G.v().soot_toolkits_scalar_LocalDefsFactory().newLocalDefs(jb);
227-
uses = LocalUses.Factory.newLocalUses(jb, defs);
269+
defs = cache.getDefs();
270+
uses = cache.getUses();
228271
}
229272

230273
// Check the original type of the array from the alloc site
@@ -254,9 +297,9 @@ public void caseAssignStmt(AssignStmt stmt) {
254297

255298
this.handleArrayRef(aref, stmt);
256299

257-
aref.setBase((Local) this.uv.visit(aref.getBase(), at, stmt));
258-
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
259-
stmt.setLeftOp(this.uv.visit(lhs, tlhs, stmt));
300+
aref.setBase((Local) uv.visit(aref.getBase(), at, stmt));
301+
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
302+
stmt.setLeftOp(uv.visit(lhs, tlhs, stmt));
260303
} else if (lhs instanceof FieldRef) {
261304
tlhs = ((FieldRef) lhs).getFieldRef().type();
262305
if (lhs instanceof InstanceFieldRef) {
@@ -269,7 +312,7 @@ public void caseAssignStmt(AssignStmt stmt) {
269312
rhs = stmt.getRightOp();
270313

271314
if (rhs instanceof Local) {
272-
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
315+
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
273316
} else if (rhs instanceof ArrayRef) {
274317
ArrayRef aref = (ArrayRef) rhs;
275318
Local base = (Local) aref.getBase();
@@ -287,11 +330,11 @@ public void caseAssignStmt(AssignStmt stmt) {
287330
// For some fixed type T, we assume that we can fix the array to T[].
288331
if (bt instanceof RefType || bt instanceof NullType) {
289332
String btName = bt instanceof NullType ? null : ((RefType) bt).getSootClass().getName();
290-
if (btName == null || Scene.v().getObjectType().toString().equals(btName) || "java.io.Serializable".equals(btName)
333+
if (btName == null || cache.getObjectType().toString().equals(btName) || "java.io.Serializable".equals(btName)
291334
|| "java.lang.Cloneable".equals(btName)) {
292335
if (defs == null) {
293-
defs = G.v().soot_toolkits_scalar_LocalDefsFactory().newLocalDefs(jb);
294-
uses = LocalUses.Factory.newLocalUses(jb, defs);
336+
defs = cache.getDefs();
337+
uses = cache.getUses();
295338
}
296339
// First, we check the definitions. If we can see the definitions and know the array type
297340
// that way, we are safe.
@@ -409,39 +452,39 @@ public void caseAssignStmt(AssignStmt stmt) {
409452

410453
this.handleArrayRef(aref, stmt);
411454

412-
aref.setBase((Local) this.uv.visit(aref.getBase(), at, stmt));
413-
stmt.setRightOp(this.uv.visit(rhs, trhs, stmt));
455+
aref.setBase((Local) uv.visit(aref.getBase(), at, stmt));
456+
stmt.setRightOp(uv.visit(rhs, trhs, stmt));
414457
} else if (rhs instanceof InstanceFieldRef) {
415458
this.handleInstanceFieldRef((InstanceFieldRef) rhs, stmt);
416-
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
459+
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
417460
} else if (rhs instanceof BinopExpr) {
418461
this.handleBinopExpr((BinopExpr) rhs, stmt, tlhs);
419462
} else if (rhs instanceof InvokeExpr) {
420463
this.handleInvokeExpr((InvokeExpr) rhs, stmt);
421-
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
464+
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
422465
} else if (rhs instanceof CastExpr) {
423-
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
466+
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
424467
} else if (rhs instanceof InstanceOfExpr) {
425468
InstanceOfExpr ioe = (InstanceOfExpr) rhs;
426-
ioe.setOp(this.uv.visit(ioe.getOp(), Scene.v().getObjectType(), stmt));
427-
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
469+
ioe.setOp(uv.visit(ioe.getOp(), Scene.v().getObjectType(), stmt));
470+
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
428471
} else if (rhs instanceof NewArrayExpr) {
429472
NewArrayExpr nae = (NewArrayExpr) rhs;
430-
nae.setSize(this.uv.visit(nae.getSize(), IntType.v(), stmt));
431-
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
473+
nae.setSize(uv.visit(nae.getSize(), IntType.v(), stmt));
474+
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
432475
} else if (rhs instanceof NewMultiArrayExpr) {
433476
NewMultiArrayExpr nmae = (NewMultiArrayExpr) rhs;
434477
for (int i = 0, e = nmae.getSizeCount(); i < e; i++) {
435-
nmae.setSize(i, this.uv.visit(nmae.getSize(i), IntType.v(), stmt));
478+
nmae.setSize(i, uv.visit(nmae.getSize(i), IntType.v(), stmt));
436479
}
437-
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
480+
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
438481
} else if (rhs instanceof LengthExpr) {
439-
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
482+
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
440483
} else if (rhs instanceof NegExpr) {
441-
((NegExpr) rhs).setOp(this.uv.visit(((NegExpr) rhs).getOp(), tlhs, stmt));
484+
((NegExpr) rhs).setOp(uv.visit(((NegExpr) rhs).getOp(), tlhs, stmt));
442485
} else if (rhs instanceof Constant) {
443486
if (!(rhs instanceof NullConstant)) {
444-
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
487+
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
445488
}
446489
}
447490
}

src/main/java/soot/toolkits/scalar/ConstantValueToInitializerTransformer.java

+2-16
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,10 @@
3838
import soot.Type;
3939
import soot.Unit;
4040
import soot.UnitPatchingChain;
41-
import soot.Value;
42-
import soot.ValueBox;
4341
import soot.VoidType;
4442
import soot.jimple.AssignStmt;
4543
import soot.jimple.Constant;
4644
import soot.jimple.DoubleConstant;
47-
import soot.jimple.FieldRef;
4845
import soot.jimple.FloatConstant;
4946
import soot.jimple.InstanceFieldRef;
5047
import soot.jimple.IntConstant;
@@ -123,7 +120,7 @@ public void transformClass(SootClass sc) {
123120
if (sf.isStatic()) {
124121
Stmt initStmt = jimp.newAssignStmt(jimp.newStaticFieldRef(sf.makeRef()), constant);
125122
if (smInit == null) {
126-
smInit = getOrCreateInitializer(sc, alreadyInitialized);
123+
smInit = getOrCreateInitializer(sc);
127124
}
128125
if (smInit != null) {
129126
smInit.getActiveBody().getUnits().addFirst(initStmt);
@@ -196,7 +193,7 @@ private boolean isInstanceFieldAssignedConstantInBody(SootField sf, Constant con
196193
return false;
197194
}
198195

199-
private SootMethod getOrCreateInitializer(SootClass sc, Set<SootField> alreadyInitialized) {
196+
private SootMethod getOrCreateInitializer(SootClass sc) {
200197
// Create a static initializer if we don't already have one
201198
SootMethod smInit = sc.getMethodByNameUnsafe(SootMethod.staticInitializerName);
202199
if (smInit == null) {
@@ -206,17 +203,6 @@ private SootMethod getOrCreateInitializer(SootClass sc, Set<SootField> alreadyIn
206203
smInit.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
207204
} else if (smInit.isPhantom()) {
208205
return null;
209-
} else {
210-
// We need to collect those variables that are already initialized somewhere
211-
for (Unit u : smInit.retrieveActiveBody().getUnits()) {
212-
Stmt s = (Stmt) u;
213-
for (ValueBox vb : s.getDefBoxes()) {
214-
Value value = vb.getValue();
215-
if (value instanceof FieldRef) {
216-
alreadyInitialized.add(((FieldRef) value).getField());
217-
}
218-
}
219-
}
220206
}
221207
return smInit;
222208
}

0 commit comments

Comments
 (0)