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
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Improve type assigner performance
Parallelize minimize typing check and reuse local defs/uses.
MarcMil committed Jan 15, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 4047aae55472e871d7c4c100639e7e6abce4e424
55 changes: 48 additions & 7 deletions src/main/java/soot/jimple/toolkits/typing/fast/TypeResolver.java
Original file line number Diff line number Diff line change
@@ -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;
@@ -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;

/**
@@ -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);

}

@@ -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) {
@@ -453,14 +462,46 @@ 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) {
}
}
return minTyping[0];
}
return r;
}

static class WorklistElement {
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
@@ -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) {
@@ -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);
@@ -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
@@ -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) {
@@ -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();
@@ -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.
@@ -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));
}
}
}