use of soot.jimple.InstanceInvokeExpr in project robovm by robovm.
the class MethodCompiler method invokeExpr.
private Value invokeExpr(Stmt stmt, InvokeExpr expr) {
SootMethodRef methodRef = expr.getMethodRef();
ArrayList<Value> args = new ArrayList<Value>();
args.add(env);
if (!(expr instanceof StaticInvokeExpr)) {
Value base = immediate(stmt, (Immediate) ((InstanceInvokeExpr) expr).getBase());
checkNull(stmt, base);
args.add(base);
}
int i = 0;
for (soot.Value sootArg : (List<soot.Value>) expr.getArgs()) {
Value arg = immediate(stmt, (Immediate) sootArg);
args.add(narrowFromI32Value(stmt, getType(methodRef.parameterType(i)), arg));
i++;
}
Value result = null;
FunctionRef functionRef = config.isDebug() ? null : Intrinsics.getIntrinsic(sootMethod, stmt, expr);
if (functionRef == null) {
Trampoline trampoline = null;
String targetClassName = getInternalName(methodRef.declaringClass());
String methodName = methodRef.name();
String methodDesc = getDescriptor(methodRef);
if (expr instanceof SpecialInvokeExpr) {
soot.Type runtimeType = ((SpecialInvokeExpr) expr).getBase().getType();
String runtimeClassName = runtimeType == NullType.v() ? targetClassName : getInternalName(runtimeType);
trampoline = new Invokespecial(this.className, targetClassName, methodName, methodDesc, runtimeClassName);
} else if (expr instanceof StaticInvokeExpr) {
trampoline = new Invokestatic(this.className, targetClassName, methodName, methodDesc);
} else if (expr instanceof VirtualInvokeExpr) {
soot.Type runtimeType = ((VirtualInvokeExpr) expr).getBase().getType();
String runtimeClassName = runtimeType == NullType.v() ? targetClassName : getInternalName(runtimeType);
trampoline = new Invokevirtual(this.className, targetClassName, methodName, methodDesc, runtimeClassName);
} else if (expr instanceof InterfaceInvokeExpr) {
trampoline = new Invokeinterface(this.className, targetClassName, methodName, methodDesc);
}
trampolines.add(trampoline);
if (canCallDirectly(expr)) {
SootMethod method = this.sootMethod.getDeclaringClass().getMethod(methodRef.name(), methodRef.parameterTypes(), methodRef.returnType());
if (method.isSynchronized()) {
functionRef = FunctionBuilder.synchronizedWrapper(method).ref();
} else {
functionRef = createMethodFunction(method).ref();
}
} else {
functionRef = trampoline.getFunctionRef();
}
}
result = call(stmt, functionRef, args.toArray(new Value[0]));
if (result != null) {
return widenToI32Value(stmt, result, methodRef.returnType().equals(CharType.v()));
} else {
return null;
}
}
use of soot.jimple.InstanceInvokeExpr in project soot by Sable.
the class GeomPointsTo method preprocess.
/**
* Read in the program facts generated by SPARK.
* We also construct our own call graph and pointer variables.
*/
private void preprocess() {
int id;
int s, t;
// Build the call graph
n_func = Scene.v().getReachableMethods().size() + 1;
call_graph = new CgEdge[n_func];
n_calls = 0;
n_reach_spark_user_methods = 0;
id = 1;
QueueReader<MethodOrMethodContext> smList = Scene.v().getReachableMethods().listener();
CallGraph soot_callgraph = Scene.v().getCallGraph();
while (smList.hasNext()) {
final SootMethod func = smList.next().method();
func2int.put(func, id);
int2func.put(id, func);
/*
* We cannot identify all entry methods since some entry methods call themselves.
* In that case, the Soot CallGraph.isEntryMethod() function returns false.
*/
if (soot_callgraph.isEntryMethod(func) || func.isEntryMethod()) {
CgEdge p = new CgEdge(Constants.SUPER_MAIN, id, null, call_graph[Constants.SUPER_MAIN]);
call_graph[Constants.SUPER_MAIN] = p;
n_calls++;
}
if (!func.isJavaLibraryMethod())
++n_reach_spark_user_methods;
id++;
}
// Next, we scan all the call edges and rebuild the call graph in our own vocabulary
QueueReader<Edge> edgeList = Scene.v().getCallGraph().listener();
while (edgeList.hasNext()) {
Edge edge = edgeList.next();
if (edge.isClinit()) {
continue;
}
SootMethod src_func = edge.src();
SootMethod tgt_func = edge.tgt();
s = func2int.get(src_func);
t = func2int.get(tgt_func);
// Create a new call edge in our own format
CgEdge p = new CgEdge(s, t, edge, call_graph[s]);
call_graph[s] = p;
edgeMapping.put(edge, p);
// We collect callsite information
Stmt callsite = edge.srcStmt();
if (edge.isThreadRunCall() || edge.kind().isExecutor() || edge.kind().isAsyncTask()) {
// We don't modify the treatment to the thread run() calls
thread_run_callsites.add(callsite);
} else if (edge.isInstance() && !edge.isSpecial()) {
// We try to refine the virtual callsites (virtual + interface) with multiple call targets
InstanceInvokeExpr expr = (InstanceInvokeExpr) callsite.getInvokeExpr();
if (expr.getMethodRef().getSignature().contains("<java.lang.Thread: void start()>")) {
// It is a thread start function
thread_run_callsites.add(callsite);
} else {
p.base_var = findLocalVarNode(expr.getBase());
if (SootInfo.countCallEdgesForCallsite(callsite, true) > 1 && p.base_var != null) {
multiCallsites.add(callsite);
}
}
}
++n_calls;
}
// We build the wrappers for all the pointers built by SPARK
for (Iterator<VarNode> it = getVarNodeNumberer().iterator(); it.hasNext(); ) {
VarNode vn = it.next();
IVarAbstraction pn = makeInternalNode(vn);
pointers.add(pn);
}
for (Iterator<AllocDotField> it = getAllocDotFieldNodeNumberer().iterator(); it.hasNext(); ) {
AllocDotField adf = it.next();
// Some allocdotfield is invalid, we check and remove them
SparkField field = adf.getField();
if (field instanceof SootField) {
// This is an instance field of a class
Type decType = ((SootField) field).getDeclaringClass().getType();
Type baseType = adf.getBase().getType();
// baseType must be a sub type of decType
if (!castNeverFails(baseType, decType))
continue;
}
IVarAbstraction pn = makeInternalNode(adf);
pointers.add(pn);
}
for (Iterator<AllocNode> it = getAllocNodeNumberer().iterator(); it.hasNext(); ) {
AllocNode obj = it.next();
IVarAbstraction pn = makeInternalNode(obj);
allocations.add(pn);
}
// The address constraints, new obj -> p
for (Object object : allocSources()) {
IVarAbstraction obj = makeInternalNode((AllocNode) object);
Node[] succs = allocLookup((AllocNode) object);
for (Node element0 : succs) {
PlainConstraint cons = new PlainConstraint();
IVarAbstraction p = makeInternalNode(element0);
cons.expr.setPair(obj, p);
cons.type = Constants.NEW_CONS;
constraints.add(cons);
}
}
// The assign constraints, p -> q
Pair<Node, Node> intercall = new Pair<Node, Node>();
for (Object object : simpleSources()) {
IVarAbstraction p = makeInternalNode((VarNode) object);
Node[] succs = simpleLookup((VarNode) object);
for (Node element0 : succs) {
PlainConstraint cons = new PlainConstraint();
IVarAbstraction q = makeInternalNode(element0);
cons.expr.setPair(p, q);
cons.type = Constants.ASSIGN_CONS;
intercall.setPair((VarNode) object, element0);
cons.interCallEdges = lookupEdgesForAssignment(intercall);
constraints.add(cons);
}
}
intercall = null;
assign2edges.clear();
// The load constraints, p.f -> q
for (Object object : loadSources()) {
FieldRefNode frn = (FieldRefNode) object;
IVarAbstraction p = makeInternalNode(frn.getBase());
Node[] succs = loadLookup(frn);
for (Node element0 : succs) {
PlainConstraint cons = new PlainConstraint();
IVarAbstraction q = makeInternalNode(element0);
cons.f = frn.getField();
cons.expr.setPair(p, q);
cons.type = Constants.LOAD_CONS;
constraints.add(cons);
}
}
// The store constraints, p -> q.f
for (Object object : storeSources()) {
IVarAbstraction p = makeInternalNode((VarNode) object);
Node[] succs = storeLookup((VarNode) object);
for (Node element0 : succs) {
PlainConstraint cons = new PlainConstraint();
FieldRefNode frn = (FieldRefNode) element0;
IVarAbstraction q = makeInternalNode(frn.getBase());
cons.f = frn.getField();
cons.expr.setPair(p, q);
cons.type = Constants.STORE_CONS;
constraints.add(cons);
}
}
n_init_constraints = constraints.size();
// Initialize other stuff
low_cg = new int[n_func];
vis_cg = new int[n_func];
rep_cg = new int[n_func];
indeg_cg = new int[n_func];
scc_size = new int[n_func];
block_num = new int[n_func];
context_size = new long[n_func];
max_context_size_block = new long[n_func];
}
use of soot.jimple.InstanceInvokeExpr in project soot by Sable.
the class GeomPointsTo method getCallTargets.
/**
* Obtain the set of possible call targets at given @param callsite.
*/
private void getCallTargets(IVarAbstraction pn, SootMethod src, Stmt callsite, ChunkedQueue<SootMethod> targetsQueue) {
InstanceInvokeExpr iie = (InstanceInvokeExpr) callsite.getInvokeExpr();
Local receiver = (Local) iie.getBase();
NumberedString subSig = iie.getMethodRef().getSubSignature();
// We first build the set of possible call targets
for (AllocNode an : pn.get_all_points_to_objects()) {
Type type = an.getType();
if (type == null)
continue;
VirtualCalls.v().resolve(type, receiver.getType(), subSig, src, targetsQueue);
}
}
use of soot.jimple.InstanceInvokeExpr in project soot by Sable.
the class AsmMethodSource method convertMethodInsn.
private void convertMethodInsn(MethodInsnNode insn) {
int op = insn.getOpcode();
boolean instance = op != INVOKESTATIC;
StackFrame frame = getFrame(insn);
Operand[] out = frame.out();
Operand opr;
Type returnType;
if (out == null) {
String clsName = AsmUtil.toQualifiedName(insn.owner);
if (clsName.charAt(0) == '[')
clsName = "java.lang.Object";
SootClass cls = Scene.v().getSootClass(clsName);
List<Type> sigTypes = AsmUtil.toJimpleDesc(insn.desc);
returnType = sigTypes.remove(sigTypes.size() - 1);
SootMethodRef ref = Scene.v().makeMethodRef(cls, insn.name, sigTypes, returnType, !instance);
int nrArgs = sigTypes.size();
final Operand[] args;
List<Value> argList = Collections.emptyList();
if (!instance) {
args = nrArgs == 0 ? null : new Operand[nrArgs];
if (args != null)
argList = new ArrayList<Value>(nrArgs);
} else {
args = new Operand[nrArgs + 1];
if (nrArgs != 0)
argList = new ArrayList<Value>(nrArgs);
}
while (nrArgs-- != 0) {
args[nrArgs] = popImmediate(sigTypes.get(nrArgs));
argList.add(args[nrArgs].stackOrValue());
}
if (argList.size() > 1)
Collections.reverse(argList);
if (instance)
args[args.length - 1] = popLocal();
ValueBox[] boxes = args == null ? null : new ValueBox[args.length];
InvokeExpr invoke;
if (!instance) {
invoke = Jimple.v().newStaticInvokeExpr(ref, argList);
} else {
Local base = (Local) args[args.length - 1].stackOrValue();
InstanceInvokeExpr iinvoke;
if (op == INVOKESPECIAL)
iinvoke = Jimple.v().newSpecialInvokeExpr(base, ref, argList);
else if (op == INVOKEVIRTUAL)
iinvoke = Jimple.v().newVirtualInvokeExpr(base, ref, argList);
else if (op == INVOKEINTERFACE)
iinvoke = Jimple.v().newInterfaceInvokeExpr(base, ref, argList);
else
throw new AssertionError("Unknown invoke op:" + op);
boxes[boxes.length - 1] = iinvoke.getBaseBox();
args[args.length - 1].addBox(boxes[boxes.length - 1]);
invoke = iinvoke;
}
if (boxes != null) {
for (int i = 0; i != sigTypes.size(); i++) {
boxes[i] = invoke.getArgBox(i);
args[i].addBox(boxes[i]);
}
frame.boxes(boxes);
frame.in(args);
}
opr = new Operand(insn, invoke);
frame.out(opr);
} else {
opr = out[0];
InvokeExpr expr = (InvokeExpr) opr.value;
List<Type> types = expr.getMethodRef().parameterTypes();
Operand[] oprs;
int nrArgs = types.size();
if (expr.getMethodRef().isStatic())
oprs = nrArgs == 0 ? null : new Operand[nrArgs];
else
oprs = new Operand[nrArgs + 1];
if (oprs != null) {
while (nrArgs-- != 0) {
oprs[nrArgs] = pop(types.get(nrArgs));
}
if (!expr.getMethodRef().isStatic())
oprs[oprs.length - 1] = pop();
frame.mergeIn(oprs);
nrArgs = types.size();
}
returnType = expr.getMethodRef().returnType();
}
if (AsmUtil.isDWord(returnType))
pushDual(opr);
else if (!(returnType instanceof VoidType))
push(opr);
else if (!units.containsKey(insn))
setUnit(insn, Jimple.v().newInvokeStmt(opr.value));
/*
* assign all read ops in case the method modifies any of the fields
*/
assignReadOps(null);
}
use of soot.jimple.InstanceInvokeExpr in project soot by Sable.
the class PAG method addCallTarget.
public final void addCallTarget(Edge e) {
if (!e.passesParameters())
return;
MethodPAG srcmpag = MethodPAG.v(this, e.src());
MethodPAG tgtmpag = MethodPAG.v(this, e.tgt());
Pair<Node, Node> pval;
if (e.isExplicit() || e.kind() == Kind.THREAD || e.kind() == Kind.ASYNCTASK) {
addCallTarget(srcmpag, tgtmpag, (Stmt) e.srcUnit(), e.srcCtxt(), e.tgtCtxt(), e);
} else if (e.kind() == Kind.EXECUTOR) {
InvokeExpr ie = e.srcStmt().getInvokeExpr();
boolean virtualCall = callAssigns.containsKey(ie);
Node parm = srcmpag.nodeFactory().getNode(ie.getArg(0));
parm = srcmpag.parameterize(parm, e.srcCtxt());
parm = parm.getReplacement();
Node thiz = tgtmpag.nodeFactory().caseThis();
thiz = tgtmpag.parameterize(thiz, e.tgtCtxt());
thiz = thiz.getReplacement();
addEdge(parm, thiz);
pval = addInterproceduralAssignment(parm, thiz, e);
callAssigns.put(ie, pval);
callToMethod.put(ie, srcmpag.getMethod());
if (virtualCall && !virtualCallsToReceivers.containsKey(ie)) {
virtualCallsToReceivers.put(ie, parm);
}
} else if (e.kind() == Kind.HANDLER) {
InvokeExpr ie = e.srcStmt().getInvokeExpr();
boolean virtualCall = callAssigns.containsKey(ie);
assert virtualCall == true;
Node base = srcmpag.nodeFactory().getNode(((VirtualInvokeExpr) ie).getBase());
base = srcmpag.parameterize(base, e.srcCtxt());
base = base.getReplacement();
Node thiz = tgtmpag.nodeFactory().caseThis();
thiz = tgtmpag.parameterize(thiz, e.tgtCtxt());
thiz = thiz.getReplacement();
addEdge(base, thiz);
pval = addInterproceduralAssignment(base, thiz, e);
callAssigns.put(ie, pval);
callToMethod.put(ie, srcmpag.getMethod());
virtualCallsToReceivers.put(ie, base);
} else if (e.kind() == Kind.PRIVILEGED) {
// Flow from first parameter of doPrivileged() invocation
// to this of target, and from return of target to the
// return of doPrivileged()
InvokeExpr ie = e.srcStmt().getInvokeExpr();
Node parm = srcmpag.nodeFactory().getNode(ie.getArg(0));
parm = srcmpag.parameterize(parm, e.srcCtxt());
parm = parm.getReplacement();
Node thiz = tgtmpag.nodeFactory().caseThis();
thiz = tgtmpag.parameterize(thiz, e.tgtCtxt());
thiz = thiz.getReplacement();
addEdge(parm, thiz);
pval = addInterproceduralAssignment(parm, thiz, e);
callAssigns.put(ie, pval);
callToMethod.put(ie, srcmpag.getMethod());
if (e.srcUnit() instanceof AssignStmt) {
AssignStmt as = (AssignStmt) e.srcUnit();
Node ret = tgtmpag.nodeFactory().caseRet();
ret = tgtmpag.parameterize(ret, e.tgtCtxt());
ret = ret.getReplacement();
Node lhs = srcmpag.nodeFactory().getNode(as.getLeftOp());
lhs = srcmpag.parameterize(lhs, e.srcCtxt());
lhs = lhs.getReplacement();
addEdge(ret, lhs);
pval = addInterproceduralAssignment(ret, lhs, e);
callAssigns.put(ie, pval);
callToMethod.put(ie, srcmpag.getMethod());
}
} else if (e.kind() == Kind.FINALIZE) {
Node srcThis = srcmpag.nodeFactory().caseThis();
srcThis = srcmpag.parameterize(srcThis, e.srcCtxt());
srcThis = srcThis.getReplacement();
Node tgtThis = tgtmpag.nodeFactory().caseThis();
tgtThis = tgtmpag.parameterize(tgtThis, e.tgtCtxt());
tgtThis = tgtThis.getReplacement();
addEdge(srcThis, tgtThis);
pval = addInterproceduralAssignment(srcThis, tgtThis, e);
} else if (e.kind() == Kind.NEWINSTANCE) {
Stmt s = (Stmt) e.srcUnit();
InstanceInvokeExpr iie = (InstanceInvokeExpr) s.getInvokeExpr();
Node cls = srcmpag.nodeFactory().getNode(iie.getBase());
cls = srcmpag.parameterize(cls, e.srcCtxt());
cls = cls.getReplacement();
Node newObject = nodeFactory.caseNewInstance((VarNode) cls);
Node initThis = tgtmpag.nodeFactory().caseThis();
initThis = tgtmpag.parameterize(initThis, e.tgtCtxt());
initThis = initThis.getReplacement();
addEdge(newObject, initThis);
if (s instanceof AssignStmt) {
AssignStmt as = (AssignStmt) s;
Node asLHS = srcmpag.nodeFactory().getNode(as.getLeftOp());
asLHS = srcmpag.parameterize(asLHS, e.srcCtxt());
asLHS = asLHS.getReplacement();
addEdge(newObject, asLHS);
}
pval = addInterproceduralAssignment(newObject, initThis, e);
callAssigns.put(s.getInvokeExpr(), pval);
callToMethod.put(s.getInvokeExpr(), srcmpag.getMethod());
} else if (e.kind() == Kind.REFL_INVOKE) {
// Flow (1) from first parameter of invoke(..) invocation
// to this of target, (2) from the contents of the second (array)
// parameter
// to all parameters of the target, and (3) from return of target to
// the
// return of invoke(..)
// (1)
InvokeExpr ie = e.srcStmt().getInvokeExpr();
Value arg0 = ie.getArg(0);
// if "null" is passed in, omit the edge
if (arg0 != NullConstant.v()) {
Node parm0 = srcmpag.nodeFactory().getNode(arg0);
parm0 = srcmpag.parameterize(parm0, e.srcCtxt());
parm0 = parm0.getReplacement();
Node thiz = tgtmpag.nodeFactory().caseThis();
thiz = tgtmpag.parameterize(thiz, e.tgtCtxt());
thiz = thiz.getReplacement();
addEdge(parm0, thiz);
pval = addInterproceduralAssignment(parm0, thiz, e);
callAssigns.put(ie, pval);
callToMethod.put(ie, srcmpag.getMethod());
}
// (2)
Value arg1 = ie.getArg(1);
SootMethod tgt = e.getTgt().method();
// edge
if (arg1 != NullConstant.v() && tgt.getParameterCount() > 0) {
Node parm1 = srcmpag.nodeFactory().getNode(arg1);
parm1 = srcmpag.parameterize(parm1, e.srcCtxt());
parm1 = parm1.getReplacement();
FieldRefNode parm1contents = makeFieldRefNode((VarNode) parm1, ArrayElement.v());
for (int i = 0; i < tgt.getParameterCount(); i++) {
// if no reference type, create no edge
if (!(tgt.getParameterType(i) instanceof RefLikeType))
continue;
Node tgtParmI = tgtmpag.nodeFactory().caseParm(i);
tgtParmI = tgtmpag.parameterize(tgtParmI, e.tgtCtxt());
tgtParmI = tgtParmI.getReplacement();
addEdge(parm1contents, tgtParmI);
pval = addInterproceduralAssignment(parm1contents, tgtParmI, e);
callAssigns.put(ie, pval);
}
}
// the return type of the callee is actually a reference type
if (e.srcUnit() instanceof AssignStmt && (tgt.getReturnType() instanceof RefLikeType)) {
AssignStmt as = (AssignStmt) e.srcUnit();
Node ret = tgtmpag.nodeFactory().caseRet();
ret = tgtmpag.parameterize(ret, e.tgtCtxt());
ret = ret.getReplacement();
Node lhs = srcmpag.nodeFactory().getNode(as.getLeftOp());
lhs = srcmpag.parameterize(lhs, e.srcCtxt());
lhs = lhs.getReplacement();
addEdge(ret, lhs);
pval = addInterproceduralAssignment(ret, lhs, e);
callAssigns.put(ie, pval);
}
} else if (e.kind() == Kind.REFL_CLASS_NEWINSTANCE || e.kind() == Kind.REFL_CONSTR_NEWINSTANCE) {
// (1) create a fresh node for the new object
// (2) create edge from this object to "this" of the constructor
// (3) if this is a call to Constructor.newInstance and not
// Class.newInstance,
// create edges passing the contents of the arguments array of the
// call
// to all possible parameters of the target
// (4) if we are inside an assign statement,
// assign the fresh object from (1) to the LHS of the assign
// statement
Stmt s = (Stmt) e.srcUnit();
InstanceInvokeExpr iie = (InstanceInvokeExpr) s.getInvokeExpr();
// (1)
Node cls = srcmpag.nodeFactory().getNode(iie.getBase());
cls = srcmpag.parameterize(cls, e.srcCtxt());
cls = cls.getReplacement();
if (cls instanceof ContextVarNode)
cls = findLocalVarNode(((VarNode) cls).getVariable());
VarNode newObject = makeGlobalVarNode(cls, RefType.v("java.lang.Object"));
SootClass tgtClass = e.getTgt().method().getDeclaringClass();
RefType tgtType = tgtClass.getType();
AllocNode site = makeAllocNode(new Pair<Node, SootClass>(cls, tgtClass), tgtType, null);
addEdge(site, newObject);
// (2)
Node initThis = tgtmpag.nodeFactory().caseThis();
initThis = tgtmpag.parameterize(initThis, e.tgtCtxt());
initThis = initThis.getReplacement();
addEdge(newObject, initThis);
addInterproceduralAssignment(newObject, initThis, e);
// (3)
if (e.kind() == Kind.REFL_CONSTR_NEWINSTANCE) {
Value arg = iie.getArg(0);
SootMethod tgt = e.getTgt().method();
// edge
if (arg != NullConstant.v() && tgt.getParameterCount() > 0) {
Node parm0 = srcmpag.nodeFactory().getNode(arg);
parm0 = srcmpag.parameterize(parm0, e.srcCtxt());
parm0 = parm0.getReplacement();
FieldRefNode parm1contents = makeFieldRefNode((VarNode) parm0, ArrayElement.v());
for (int i = 0; i < tgt.getParameterCount(); i++) {
// if no reference type, create no edge
if (!(tgt.getParameterType(i) instanceof RefLikeType))
continue;
Node tgtParmI = tgtmpag.nodeFactory().caseParm(i);
tgtParmI = tgtmpag.parameterize(tgtParmI, e.tgtCtxt());
tgtParmI = tgtParmI.getReplacement();
addEdge(parm1contents, tgtParmI);
pval = addInterproceduralAssignment(parm1contents, tgtParmI, e);
callAssigns.put(iie, pval);
}
}
}
// (4)
if (s instanceof AssignStmt) {
AssignStmt as = (AssignStmt) s;
Node asLHS = srcmpag.nodeFactory().getNode(as.getLeftOp());
asLHS = srcmpag.parameterize(asLHS, e.srcCtxt());
asLHS = asLHS.getReplacement();
addEdge(newObject, asLHS);
}
pval = addInterproceduralAssignment(newObject, initThis, e);
callAssigns.put(s.getInvokeExpr(), pval);
callToMethod.put(s.getInvokeExpr(), srcmpag.getMethod());
} else {
throw new RuntimeException("Unhandled edge " + e);
}
}
Aggregations