Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the ConstantValueToInitializerTransformer & Performance optimizations for type resolver #2138

Merged
merged 4 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 49 additions & 7 deletions src/main/java/soot/jimple/toolkits/typing/fast/TypeResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import soot.ArrayType;
import soot.BooleanType;
Expand Down Expand Up @@ -69,6 +72,7 @@
import soot.jimple.SpecialInvokeExpr;
import soot.jimple.Stmt;
import soot.jimple.toolkits.typing.Util;
import soot.jimple.toolkits.typing.fast.UseChecker.UseCheckerCache;
import soot.toolkits.scalar.LocalDefs;

/**
Expand All @@ -83,17 +87,22 @@
* @author Ben Bellamy
*/
public class TypeResolver {
private static final int SINGLE_THREAD_LIMIT = 100000;
private static int NUM_CORES = Math.max(1, Runtime.getRuntime().availableProcessors() - 2);

protected final JimpleBody jb;

private List<DefinitionStmt> assignments;
private HashMap<Local, BitSet> depends;
private Set<Local> singleAssignments;
private BitSet simple;
private final LocalGenerator localGenerator;
private final UseCheckerCache useCheckerCache;

public TypeResolver(JimpleBody jb) {
this.jb = jb;
this.localGenerator = Scene.v().createLocalGenerator(jb);
this.useCheckerCache = new UseCheckerCache(jb);

}

Expand Down Expand Up @@ -402,7 +411,7 @@ private ITyping typePromotion(ITyping tg) {
}

protected UseChecker createUseChecker(JimpleBody jb) {
return new UseChecker(jb);
return new UseChecker(jb, useCheckerCache);
}

protected TypePromotionUseVisitor createTypePromotionUseVisitor(JimpleBody jb, ITyping tg) {
Expand Down Expand Up @@ -453,14 +462,47 @@ protected CastInsertionUseVisitor createCastInsertionUseVisitor(ITyping tg, IHie
private ITyping minCasts(Collection<ITyping> sigma, IHierarchy h, int[] count) {
count[0] = -1;
ITyping r = null;
for (ITyping tg : sigma) {
int n = this.insertCasts(tg, h, true);
if (count[0] == -1 || n < count[0]) {
count[0] = n;
r = tg;
if (sigma.size() <= SINGLE_THREAD_LIMIT) {
for (ITyping tg : sigma) {
int n = this.insertCasts(tg, h, true);
if (count[0] == -1 || n < count[0]) {
count[0] = n;
r = tg;
}
}
return r;
} else {
ExecutorService executionService = Executors.newFixedThreadPool(NUM_CORES);
ITyping[] minTyping = new ITyping[1];
try {
for (ITyping tg : sigma) {
executionService.submit(new Runnable() {

@Override
public void run() {
int n = insertCasts(tg, h, true);
if (count[0] == -1 || n < count[0]) {
synchronized (count) {
if (count[0] == -1 || n < count[0]) {
count[0] = n;
minTyping[0] = tg;
}
}
}
}

});
}
} finally {
executionService.shutdown();
try {
executionService.awaitTermination(100, TimeUnit.DAYS);
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted during type resolving", e);
}
}
return minTyping[0];
}
return r;
}

static class WorklistElement {
Expand Down
97 changes: 70 additions & 27 deletions src/main/java/soot/jimple/toolkits/typing/fast/UseChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,53 @@ public class UseChecker extends AbstractStmtSwitch {
private ITyping tg;
private IUseVisitor uv;

private LocalDefs defs = null;
private LocalUses uses = null;

private static final Logger logger = LoggerFactory.getLogger(UseChecker.class);

public static class UseCheckerCache {
private LocalDefs defs = null;
private LocalUses uses = null;

private final Type objectType = Scene.v().getObjectType();
private final JimpleBody body;

public UseCheckerCache(JimpleBody body) {
this.body = body;
}

public Type getObjectType() {
return objectType;
}

public LocalDefs getDefs() {
LocalDefs d = defs;
if (d == null) {
d = G.v().soot_toolkits_scalar_LocalDefsFactory().newLocalDefs(body);
defs = d;
}
return d;
}

public LocalUses getUses() {
LocalUses u = uses;
if (u != null) {
return u;
}
u = LocalUses.Factory.newLocalUses(body, getDefs());
uses = u;
return u;
}
}

private UseCheckerCache cache;

public UseChecker(JimpleBody jb) {
this.jb = jb;
cache = new UseCheckerCache(jb);
}

public UseChecker(JimpleBody jb, UseCheckerCache cache) {
this.jb = jb;
this.cache = cache;
}

public void check(ITyping tg, IUseVisitor uv) {
Expand Down Expand Up @@ -203,6 +243,9 @@ public void caseAssignStmt(AssignStmt stmt) {
Value lhs = stmt.getLeftOp();
Value rhs = stmt.getRightOp();
Type tlhs = null;
LocalDefs defs = cache.defs;
LocalUses uses = cache.uses;
final IUseVisitor uv = this.uv;

if (lhs instanceof Local) {
tlhs = this.tg.get((Local) lhs);
Expand All @@ -221,10 +264,10 @@ public void caseAssignStmt(AssignStmt stmt) {
// is java.lang.Object
if (rhs instanceof Local) {
Type rhsType = this.tg.get((Local) rhs);
if ((tgType == Scene.v().getObjectType() && rhsType instanceof PrimType) || tgType instanceof WeakObjectType) {
if ((tgType == cache.getObjectType() && rhsType instanceof PrimType) || tgType instanceof WeakObjectType) {
if (defs == null) {
defs = G.v().soot_toolkits_scalar_LocalDefsFactory().newLocalDefs(jb);
uses = LocalUses.Factory.newLocalUses(jb, defs);
defs = cache.getDefs();
uses = cache.getUses();
}

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

this.handleArrayRef(aref, stmt);

aref.setBase((Local) this.uv.visit(aref.getBase(), at, stmt));
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
stmt.setLeftOp(this.uv.visit(lhs, tlhs, stmt));
aref.setBase((Local) uv.visit(aref.getBase(), at, stmt));
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
stmt.setLeftOp(uv.visit(lhs, tlhs, stmt));
} else if (lhs instanceof FieldRef) {
tlhs = ((FieldRef) lhs).getFieldRef().type();
if (lhs instanceof InstanceFieldRef) {
Expand All @@ -269,7 +312,7 @@ public void caseAssignStmt(AssignStmt stmt) {
rhs = stmt.getRightOp();

if (rhs instanceof Local) {
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
} else if (rhs instanceof ArrayRef) {
ArrayRef aref = (ArrayRef) rhs;
Local base = (Local) aref.getBase();
Expand All @@ -287,11 +330,11 @@ public void caseAssignStmt(AssignStmt stmt) {
// For some fixed type T, we assume that we can fix the array to T[].
if (bt instanceof RefType || bt instanceof NullType) {
String btName = bt instanceof NullType ? null : ((RefType) bt).getSootClass().getName();
if (btName == null || Scene.v().getObjectType().toString().equals(btName) || "java.io.Serializable".equals(btName)
if (btName == null || cache.getObjectType().toString().equals(btName) || "java.io.Serializable".equals(btName)
|| "java.lang.Cloneable".equals(btName)) {
if (defs == null) {
defs = G.v().soot_toolkits_scalar_LocalDefsFactory().newLocalDefs(jb);
uses = LocalUses.Factory.newLocalUses(jb, defs);
defs = cache.getDefs();
uses = cache.getUses();
}
// First, we check the definitions. If we can see the definitions and know the array type
// that way, we are safe.
Expand Down Expand Up @@ -409,39 +452,39 @@ public void caseAssignStmt(AssignStmt stmt) {

this.handleArrayRef(aref, stmt);

aref.setBase((Local) this.uv.visit(aref.getBase(), at, stmt));
stmt.setRightOp(this.uv.visit(rhs, trhs, stmt));
aref.setBase((Local) uv.visit(aref.getBase(), at, stmt));
stmt.setRightOp(uv.visit(rhs, trhs, stmt));
} else if (rhs instanceof InstanceFieldRef) {
this.handleInstanceFieldRef((InstanceFieldRef) rhs, stmt);
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
} else if (rhs instanceof BinopExpr) {
this.handleBinopExpr((BinopExpr) rhs, stmt, tlhs);
} else if (rhs instanceof InvokeExpr) {
this.handleInvokeExpr((InvokeExpr) rhs, stmt);
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
} else if (rhs instanceof CastExpr) {
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
} else if (rhs instanceof InstanceOfExpr) {
InstanceOfExpr ioe = (InstanceOfExpr) rhs;
ioe.setOp(this.uv.visit(ioe.getOp(), Scene.v().getObjectType(), stmt));
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
ioe.setOp(uv.visit(ioe.getOp(), Scene.v().getObjectType(), stmt));
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
} else if (rhs instanceof NewArrayExpr) {
NewArrayExpr nae = (NewArrayExpr) rhs;
nae.setSize(this.uv.visit(nae.getSize(), IntType.v(), stmt));
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
nae.setSize(uv.visit(nae.getSize(), IntType.v(), stmt));
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
} else if (rhs instanceof NewMultiArrayExpr) {
NewMultiArrayExpr nmae = (NewMultiArrayExpr) rhs;
for (int i = 0, e = nmae.getSizeCount(); i < e; i++) {
nmae.setSize(i, this.uv.visit(nmae.getSize(i), IntType.v(), stmt));
nmae.setSize(i, uv.visit(nmae.getSize(i), IntType.v(), stmt));
}
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
} else if (rhs instanceof LengthExpr) {
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
} else if (rhs instanceof NegExpr) {
((NegExpr) rhs).setOp(this.uv.visit(((NegExpr) rhs).getOp(), tlhs, stmt));
((NegExpr) rhs).setOp(uv.visit(((NegExpr) rhs).getOp(), tlhs, stmt));
} else if (rhs instanceof Constant) {
if (!(rhs instanceof NullConstant)) {
stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
stmt.setRightOp(uv.visit(rhs, tlhs, stmt));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,10 @@
import soot.Type;
import soot.Unit;
import soot.UnitPatchingChain;
import soot.Value;
import soot.ValueBox;
import soot.VoidType;
import soot.jimple.AssignStmt;
import soot.jimple.Constant;
import soot.jimple.DoubleConstant;
import soot.jimple.FieldRef;
import soot.jimple.FloatConstant;
import soot.jimple.InstanceFieldRef;
import soot.jimple.IntConstant;
Expand Down Expand Up @@ -123,7 +120,7 @@ public void transformClass(SootClass sc) {
if (sf.isStatic()) {
Stmt initStmt = jimp.newAssignStmt(jimp.newStaticFieldRef(sf.makeRef()), constant);
if (smInit == null) {
smInit = getOrCreateInitializer(sc, alreadyInitialized);
smInit = getOrCreateInitializer(sc);
}
if (smInit != null) {
smInit.getActiveBody().getUnits().addFirst(initStmt);
Expand Down Expand Up @@ -196,7 +193,7 @@ private boolean isInstanceFieldAssignedConstantInBody(SootField sf, Constant con
return false;
}

private SootMethod getOrCreateInitializer(SootClass sc, Set<SootField> alreadyInitialized) {
private SootMethod getOrCreateInitializer(SootClass sc) {
// Create a static initializer if we don't already have one
SootMethod smInit = sc.getMethodByNameUnsafe(SootMethod.staticInitializerName);
if (smInit == null) {
Expand All @@ -206,17 +203,6 @@ private SootMethod getOrCreateInitializer(SootClass sc, Set<SootField> alreadyIn
smInit.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
} else if (smInit.isPhantom()) {
return null;
} else {
// We need to collect those variables that are already initialized somewhere
for (Unit u : smInit.retrieveActiveBody().getUnits()) {
Stmt s = (Stmt) u;
for (ValueBox vb : s.getDefBoxes()) {
Value value = vb.getValue();
if (value instanceof FieldRef) {
alreadyInitialized.add(((FieldRef) value).getField());
}
}
}
}
return smInit;
}
Expand Down
Loading