diff --git a/com.ibm.wala.cast.java/.settings/org.eclipse.jdt.core.prefs b/com.ibm.wala.cast.java/.settings/org.eclipse.jdt.core.prefs
index 5465e174f..169bc4376 100644
--- a/com.ibm.wala.cast.java/.settings/org.eclipse.jdt.core.prefs
+++ b/com.ibm.wala.cast.java/.settings/org.eclipse.jdt.core.prefs
@@ -10,6 +10,7 @@ org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nul
org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
diff --git a/com.ibm.wala.cast.java/META-INF/MANIFEST.MF b/com.ibm.wala.cast.java/META-INF/MANIFEST.MF
index 686671850..f638eae6f 100644
--- a/com.ibm.wala.cast.java/META-INF/MANIFEST.MF
+++ b/com.ibm.wala.cast.java/META-INF/MANIFEST.MF
@@ -21,3 +21,4 @@ Export-Package: com.ibm.wala.cast.java.analysis.typeInference,
com.ibm.wala.cast.java.types
Bundle-ClassPath: .
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Automatic-Module-Name: com.ibm.wala.cast.java
diff --git a/com.ibm.wala.core.testdata/build.gradle b/com.ibm.wala.core.testdata/build.gradle
index b3581630f..8a28e09c9 100644
--- a/com.ibm.wala.core.testdata/build.gradle
+++ b/com.ibm.wala.core.testdata/build.gradle
@@ -1,3 +1,8 @@
+buildscript {
+ repositories { mavenCentral() }
+ dependencies { classpath 'org.ajoberstar:gradle-git:0.2.3' }
+}
+
plugins {
id 'eclipse'
}
@@ -6,6 +11,121 @@ eclipse.project.natures 'org.eclipse.pde.PluginNature'
sourceSets.test.java.srcDirs = ['src']
+////////////////////////////////////////////////////////////////////////
+//
+// download and extract kawa 3.0 "kawa.jar"
+//
+
+task downloadKawa(type: Exec) {
+ commandLine "wget", "ftp://ftp.gnu.org/pub/gnu/kawa/kawa-3.0.zip"
+ workingDir "$temporaryDir"
+ def destination = file("$temporaryDir/kawa-3.0.zip")
+ enabled = !destination.exists() //to clone only once
+}
+
+task extractKawa(type: Copy, dependsOn: downloadKawa) {
+ from(zipTree("${downloadKawa.temporaryDir}/kawa-3.0.zip")) {
+ include "kawa-3.0/lib/kawa.jar"
+ eachFile {
+ relativePath new RelativePath(!directory, relativePath.lastName)
+ }
+ }
+ into projectDir
+ includeEmptyDirs false
+ outputs.file "kawa.jar"
+}
+
+task cleanExtractKawa(type: Delete) {
+ delete files(extractKawa)[0]
+}
+
+clean.dependsOn cleanExtractKawa
+
+////////////////////////////////////////////////////////////////////////
+//
+// build kawa chess
+//
+import org.ajoberstar.gradle.git.tasks.*
+
+task getKawaChess(type: GitClone) {
+ def destination = file("$temporaryDir/kawachess")
+ uri = "https://github.com/ttu-fpclub/kawa-chess"
+ destinationPath = destination
+ bare = false
+ enabled = !destination.exists() //to clone only once
+}
+
+task compileChessFiles(type: JavaExec) {
+ def kawaImg = file('kawa-chess/img.scm')
+ def kawaPos = file('kawa-chess/pos.scm')
+ def kawaChess = file('kawa-chess/chess.scm')
+ def kawaGui = file('kawa-chess/gui.scm')
+ inputs.file kawaImg
+ inputs.file kawaPos
+ inputs.file kawaChess
+ inputs.file kawaGui
+
+ workingDir = file('kawa-chess')
+
+ def kawaJar = new File("kawa.jar")
+ inputs.file kawaJar
+ classpath kawaJar
+
+ main 'kawa.repl'
+ args '-C', kawaImg, kawaPos, kawaChess, kawaGui
+}
+
+compileChessFiles.dependsOn extractKawa
+compileChessFiles.dependsOn getKawaChess
+
+task compileChessMain(type: JavaExec, dependsOn: compileChessFiles) {
+ def kawaMain = file('kawa-chess/main.scm')
+ inputs.file kawaMain
+
+ workingDir = file('kawa-chess')
+
+ def kawaJar = new File("kawa.jar")
+ inputs.file kawaJar
+ classpath kawaJar
+
+ main 'kawa.repl'
+ args '--main', '-C', kawaMain
+}
+
+task buildChessJar(type: Jar, dependsOn: compileChessMain) {
+ from file('kawa-chess')
+ baseName 'kawachess'
+ version null
+ destinationDir projectDir
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// build the kawa test jar
+//
+
+task compileKawaTestMain(type: JavaExec, dependsOn: extractKawa) {
+ def kawaMain = file('kawasrc/test.scm')
+ inputs.file kawaMain
+
+ workingDir = file('kawasrc')
+
+ def kawaJar = new File("kawa.jar")
+ inputs.file kawaJar
+ classpath kawaJar
+
+ main 'kawa.repl'
+ args '--main', '-C', kawaMain
+}
+
+task buildKawaTestJar(type: Jar, dependsOn: compileKawaTestMain) {
+ from file('kawasrc')
+ baseName 'kawatest'
+ version null
+ destinationDir projectDir
+}
+
////////////////////////////////////////////////////////////////////////
//
@@ -186,5 +306,7 @@ afterEclipseBuildshipImport {
downloadJavaCup,
extractBcel,
generateHelloHashJar,
+ buildChessJar,
+ buildKawaTestJar,
)
}
diff --git a/com.ibm.wala.core.testdata/build.properties b/com.ibm.wala.core.testdata/build.properties
index d61143dc0..c7386c4f6 100644
--- a/com.ibm.wala.core.testdata/build.properties
+++ b/com.ibm.wala.core.testdata/build.properties
@@ -2,6 +2,9 @@ source.. = src/
output.. = bin/test
bin.includes = META-INF/,\
.,\
+ kawa.jar,\
+ kawatest.jar,\
+ kawachess.jar,\
hello_hash.jar,\
JLex.jar,\
bcel-5.2.jar,\
diff --git a/com.ibm.wala.core.testdata/build.xml b/com.ibm.wala.core.testdata/build.xml
index 7342fea11..09929b2c6 100644
--- a/com.ibm.wala.core.testdata/build.xml
+++ b/com.ibm.wala.core.testdata/build.xml
@@ -88,13 +88,64 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/com.ibm.wala.core.tests/build.gradle b/com.ibm.wala.core.tests/build.gradle
index d3ed7bf15..9b356cb96 100644
--- a/com.ibm.wala.core.tests/build.gradle
+++ b/com.ibm.wala.core.tests/build.gradle
@@ -33,6 +33,9 @@ processTestResources {
from testdata.downloadJavaCup
from files(testdata.extractBcel)[0]
from testdata.generateHelloHashJar
+ from testdata.extractKawa
+ from testdata.buildChessJar
+ from testdata.buildKawaTestJar
}
test {
diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/Java7CallGraphTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/Java7CallGraphTest.java
index bff08aab2..d2c4b2b13 100644
--- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/Java7CallGraphTest.java
+++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/Java7CallGraphTest.java
@@ -59,8 +59,11 @@ public class Java7CallGraphTest extends DynamicCallGraphTestBase {
SSAPropagationCallGraphBuilder builder = Util.makeZeroOneContainerCFABuilder(options, cache, cha, scope);
+ options.setSelector(new MethodHandles.InvokeExactTargetSelector(options.getMethodTargetSelector()));
+
builder.setContextSelector(new MethodHandles.ContextSelectorImpl(builder.getContextSelector()));
- builder.setContextInterpreter(new DelegatingSSAContextInterpreter(new MethodHandles.ContextInterpreterImpl(), builder.getCFAContextInterpreter()));
+ builder.setContextInterpreter(new DelegatingSSAContextInterpreter(new MethodHandles.InvokeContextInterpreterImpl(), builder.getCFAContextInterpreter()));
+ builder.setContextInterpreter(new DelegatingSSAContextInterpreter(new MethodHandles.FindContextInterpreterImpl(), builder.getCFAContextInterpreter()));
CallGraph cg = builder.makeCallGraph(options, null);
diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/KawaCallGraphTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/KawaCallGraphTest.java
new file mode 100644
index 000000000..46a163b20
--- /dev/null
+++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/callGraph/KawaCallGraphTest.java
@@ -0,0 +1,97 @@
+/******************************************************************************
+ * Copyright (c) 2002 - 2014 IBM Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *****************************************************************************/
+
+package com.ibm.wala.core.tests.callGraph;
+
+import java.io.IOException;
+import java.util.Set;
+
+import org.junit.Test;
+
+import com.ibm.wala.analysis.reflection.java7.MethodHandles;
+import com.ibm.wala.classLoader.Language;
+import com.ibm.wala.classLoader.Module;
+import com.ibm.wala.classLoader.ResourceJarFileModule;
+import com.ibm.wala.core.tests.shrike.DynamicCallGraphTestBase;
+import com.ibm.wala.ipa.callgraph.AnalysisCacheImpl;
+import com.ibm.wala.ipa.callgraph.AnalysisOptions;
+import com.ibm.wala.ipa.callgraph.AnalysisOptions.ReflectionOptions;
+import com.ibm.wala.ipa.callgraph.AnalysisScope;
+import com.ibm.wala.ipa.callgraph.CGNode;
+import com.ibm.wala.ipa.callgraph.CallGraph;
+import com.ibm.wala.ipa.callgraph.Entrypoint;
+import com.ibm.wala.ipa.callgraph.IAnalysisCacheView;
+import com.ibm.wala.ipa.callgraph.impl.Util;
+import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder;
+import com.ibm.wala.ipa.callgraph.propagation.cfa.DelegatingSSAContextInterpreter;
+import com.ibm.wala.ipa.cha.ClassHierarchy;
+import com.ibm.wala.ipa.cha.ClassHierarchyException;
+import com.ibm.wala.ipa.cha.ClassHierarchyFactory;
+import com.ibm.wala.types.ClassLoaderReference;
+import com.ibm.wala.types.Descriptor;
+import com.ibm.wala.types.MethodReference;
+import com.ibm.wala.types.TypeReference;
+import com.ibm.wala.util.CancelException;
+import com.ibm.wala.util.strings.Atom;
+
+public class KawaCallGraphTest extends DynamicCallGraphTestBase {
+
+ @Test
+ public void testKawaChess() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException, SecurityException {
+ CallGraph CG = testKawa(new ResourceJarFileModule(getClass().getClassLoader().getResource("kawachess.jar")), "main");
+
+ Set status = getNodes(CG, "Lchess", "startingStatus", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+ assert ! status.isEmpty();
+
+ Set color = getNodes(CG, "Lchess", "startingColor", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+ assert ! color.isEmpty();
+
+ }
+
+ @Test
+ public void testKawaTest() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException, SecurityException {
+ CallGraph CG = testKawa(new ResourceJarFileModule(getClass().getClassLoader().getResource("kawatest.jar")), "test");
+
+ Set nodes = getNodes(CG, "Ltest", "plusish$V", "(Lgnu/lists/LList;)Ljava/lang/Object;");
+ assert ! nodes.isEmpty();
+ }
+
+ private static Set getNodes(CallGraph CG, String cls, String method, String descr) {
+ Set nodes = CG.getNodes(MethodReference.findOrCreate(TypeReference.find(ClassLoaderReference.Application, cls), Atom.findOrCreateUnicodeAtom(method), Descriptor.findOrCreateUTF8(descr)));
+ return nodes;
+ }
+
+ public CallGraph testKawa(Module code, String main) throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException, SecurityException {
+ AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope("base.txt", CallGraphTestUtil.REGRESSION_EXCLUSIONS_FOR_GUI);
+ scope.addToScope(ClassLoaderReference.Application, new ResourceJarFileModule(getClass().getClassLoader().getResource("kawa.jar")));
+ scope.addToScope(ClassLoaderReference.Application, code);
+
+ ClassHierarchy cha = ClassHierarchyFactory.make(scope);
+ Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, "L" + main);
+ AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints);
+ IAnalysisCacheView cache = new AnalysisCacheImpl();
+
+ options.setReflectionOptions(ReflectionOptions.NONE);
+ options.setTraceStringConstants(true);
+ options.setUseConstantSpecificKeys(true);
+
+ SSAPropagationCallGraphBuilder builder = Util.makeZeroCFABuilder(Language.JAVA, options, cache, cha, scope);
+
+ options.setSelector(new MethodHandles.InvokeExactTargetSelector(options.getMethodTargetSelector()));
+
+ builder.setContextSelector(new MethodHandles.ContextSelectorImpl(builder.getContextSelector()));
+ builder.setContextInterpreter(new DelegatingSSAContextInterpreter(new MethodHandles.InvokeContextInterpreterImpl(), builder.getCFAContextInterpreter()));
+ builder.setContextInterpreter(new DelegatingSSAContextInterpreter(new MethodHandles.FindContextInterpreterImpl(), builder.getCFAContextInterpreter()));
+
+ return builder.makeCallGraph(options, null);
+ }
+
+}
diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/java7/MethodHandles.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/java7/MethodHandles.java
index fb8544a0a..cfe234635 100644
--- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/java7/MethodHandles.java
+++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/java7/MethodHandles.java
@@ -20,11 +20,13 @@ import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.classLoader.NewSiteReference;
+import com.ibm.wala.classLoader.SyntheticMethod;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.Context;
import com.ibm.wala.ipa.callgraph.ContextItem;
import com.ibm.wala.ipa.callgraph.ContextKey;
import com.ibm.wala.ipa.callgraph.ContextSelector;
+import com.ibm.wala.ipa.callgraph.MethodTargetSelector;
import com.ibm.wala.ipa.callgraph.propagation.ConstantKey;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter;
@@ -53,8 +55,10 @@ import com.ibm.wala.util.intset.IntSetUtil;
public class MethodHandles {
+ private static final IntSet params = IntSetUtil.make(new int[] {1, 2});
+
private static final IntSet self = IntSetUtil.make(new int[0]);
-
+
private static ContextKey METHOD_KEY = new ContextKey() {
@Override
public String toString() {
@@ -62,23 +66,32 @@ public class MethodHandles {
}
};
- public static class MethodItem implements ContextItem {
- private final MethodReference method;
-
- public MethodItem(MethodReference method) {
- super();
- this.method = method;
+ private static ContextKey CLASS_KEY = new ContextKey() {
+ @Override
+ public String toString() {
+ return "CLASS_KEY";
}
+ };
+
+ private static ContextKey NAME_KEY = new ContextKey() {
+ @Override
+ public String toString() {
+ return "NAME_KEY";
+ }
+ };
+
+ private static class HandlesItem implements ContextItem {
+ private final T item;
- public MethodReference getMethod() {
- return method;
+ public HandlesItem(T method) {
+ this.item = method;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result + ((method == null) ? 0 : method.hashCode());
+ result = prime * result + ((item == null) ? 0 : item.hashCode());
return result;
}
@@ -90,15 +103,78 @@ public class MethodHandles {
return false;
if (getClass() != obj.getClass())
return false;
- MethodItem other = (MethodItem) obj;
- if (method == null) {
- if (other.method != null)
+ HandlesItem other = (HandlesItem) obj;
+ if (item == null) {
+ if (other.item != null)
return false;
- } else if (!method.equals(other.method))
+ } else if (!item.equals(other.item))
return false;
return true;
}
}
+
+ public static class FindContext implements Context {
+ private final Context base;
+ private final TypeReference cls;
+ private final String selector;
+
+ public FindContext(Context base, TypeReference cls, String methodName) {
+ this.base = base;
+ this.cls = cls;
+ this.selector = methodName;
+ }
+
+ @Override
+ public ContextItem get(ContextKey name) {
+ if (CLASS_KEY.equals(name)) {
+ return new HandlesItem<>(cls);
+ } else if (NAME_KEY.equals(name)) {
+ return new HandlesItem<>(selector);
+ } else {
+
+ return base.get(name);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((base == null) ? 0 : base.hashCode());
+ result = prime * result + ((cls == null) ? 0 : cls.hashCode());
+ result = prime * result + ((selector == null) ? 0 : selector.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ FindContext other = (FindContext) obj;
+ if (base == null) {
+ if (other.base != null)
+ return false;
+ } else if (!base.equals(other.base))
+ return false;
+ if (cls == null) {
+ if (other.cls != null)
+ return false;
+ } else if (!cls.equals(other.cls))
+ return false;
+ if (selector == null) {
+ if (other.selector != null)
+ return false;
+ } else if (!selector.equals(other.selector))
+ return false;
+ return true;
+ }
+
+
+ }
public static class MethodContext implements Context {
private final Context base;
@@ -112,7 +188,7 @@ public class MethodHandles {
@Override
public ContextItem get(ContextKey name) {
if (METHOD_KEY.equals(name)) {
- return new MethodItem(method);
+ return new HandlesItem<>(method);
} else {
return base.get(name);
}
@@ -165,7 +241,7 @@ public class MethodHandles {
@Override
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] actualParameters) {
Context baseContext = base.getCalleeTarget(caller, site, callee, actualParameters);
- if ((isInvoke(callee) || isType(callee)) && callee.getDeclaringClass().getReference().equals(TypeReference.JavaLangInvokeMethodHandle)) {
+ if ((isInvoke(callee) || isType(callee)) && callee.getReference().getDeclaringClass().getName().equals(TypeReference.JavaLangInvokeMethodHandle.getName())) {
if (actualParameters != null && actualParameters.length > 0) {
InstanceKey selfKey = actualParameters[0];
if (selfKey instanceof ConstantKey && ((ConstantKey)selfKey).getConcreteType().getReference().equals(TypeReference.JavaLangInvokeMethodHandle)) {
@@ -174,15 +250,64 @@ public class MethodHandles {
}
}
}
+
+ if (isFindStatic(callee) && callee.getDeclaringClass().getReference().equals(TypeReference.JavaLangInvokeMethodHandlesLookup)) {
+ if (actualParameters != null && actualParameters.length > 2) {
+ InstanceKey classKey = actualParameters[1];
+ InstanceKey nameKey = actualParameters[2];
+ if (classKey instanceof ConstantKey && ((ConstantKey)classKey).getConcreteType().getReference().equals(TypeReference.JavaLangClass) &&
+ nameKey instanceof ConstantKey && ((ConstantKey)nameKey).getConcreteType().getReference().equals(TypeReference.JavaLangString)) {
+ return new FindContext(baseContext, ((IClass)((ConstantKey)classKey).getValue()).getReference(), (String)((ConstantKey)nameKey).getValue());
+ }
+ }
+ }
+
return baseContext;
}
@Override
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
- return self;
+ return isFindStatic(site.getDeclaredTarget())? params: self;
}
}
+ public static class InvokeExactTargetSelector implements MethodTargetSelector {
+ private final MethodTargetSelector base;
+ private final Map impls = HashMapFactory.make();
+
+ public InvokeExactTargetSelector(MethodTargetSelector base) {
+ this.base = base;
+ }
+
+ @Override
+ public IMethod getCalleeTarget(CGNode caller, CallSiteReference site, IClass receiver) {
+ MethodReference target = site.getDeclaredTarget();
+ if (isInvokeExact(target)) {
+ if (! impls.containsKey(target)) {
+ SyntheticMethod invokeExactTrampoline = new SyntheticMethod(target, receiver.getClassHierarchy().lookupClass(TypeReference.JavaLangInvokeMethodHandle), false, false);
+ impls.put(target, invokeExactTrampoline);
+ }
+
+ return impls.get(target);
+ }
+
+ return base.getCalleeTarget(caller, site, receiver);
+ }
+ }
+
+ private static boolean isInvokeExact(MethodReference target) {
+ return target.getDeclaringClass().getName().equals(TypeReference.JavaLangInvokeMethodHandle.getName()) &&
+ target.getName().toString().equals("invokeExact");
+ }
+
+ private static boolean isFindStatic(MethodReference node) {
+ return node.getName().toString().startsWith("findStatic");
+ }
+
+ private static boolean isFindStatic(IMethod node) {
+ return isFindStatic(node.getReference());
+ }
+
private static boolean isInvoke(IMethod node) {
return node.getName().toString().startsWith("invoke");
}
@@ -199,8 +324,12 @@ public class MethodHandles {
return isType(node.getMethod());
}
- public static class ContextInterpreterImpl implements SSAContextInterpreter {
- private final Map> irs = HashMapFactory.make();
+ private static boolean isFindStatic(CGNode node) {
+ return isFindStatic(node.getMethod());
+ }
+
+ private abstract static class HandlersContextInterpreterImpl implements SSAContextInterpreter {
+ protected final Map> irs = HashMapFactory.make();
@Override
public Iterator iterateNewSites(CGNode node) {
@@ -229,52 +358,11 @@ public class MethodHandles {
return false;
}
- @Override
- public boolean understands(CGNode node) {
- return (isInvoke(node) || isType(node)) && node.getContext() instanceof MethodContext;
- }
-
@Override
public Iterator iterateCallSites(CGNode node) {
return getIR(node).iterateCallSites();
}
- @Override
- public IR getIR(CGNode node) {
- if (!irs.containsKey(node) || irs.get(node).get() == null) {
- MethodSummary code = new MethodSummary(node.getMethod().getReference());
- SummarizedMethod m = new SummarizedMethod(node.getMethod().getReference(), code, node.getMethod().getDeclaringClass());
- SSAInstructionFactory insts = node.getMethod().getDeclaringClass().getClassLoader().getLanguage().instructionFactory();
- assert node.getContext() instanceof MethodContext;
- MethodReference ref = ((MethodContext)node.getContext()).method;
- boolean isStatic = node.getClassHierarchy().resolveMethod(ref).isStatic();
- if (isInvoke(node)) {
- String name = node.getMethod().getName().toString();
- if ("invokeWithArguments".equals(name)) {
- int nargs = ref.getNumberOfParameters();
- int params[] = new int[nargs];
- for(int i = 0; i < nargs; i++) {
- code.addConstant(i+nargs+3, new ConstantValue(i));
- code.addStatement(insts.ArrayLoadInstruction(code.getNextProgramCounter(), i+3, 1, i+nargs+3, TypeReference.JavaLangObject));
- params[i] = i+3;
- }
- CallSiteReference site = CallSiteReference.make(nargs+1, ref, isStatic? Dispatch.STATIC: Dispatch.SPECIAL);
- code.addStatement(insts.InvokeInstruction(code.getNextProgramCounter(), 2*nargs+3, params, 2*nargs+4, site, null));
- code.addStatement(insts.ReturnInstruction(code.getNextProgramCounter(), 2*nargs+3, false));
- } else {
- // int nargs = node.getMethod().getNumberOfParameters();
- }
- } else {
- assert isType(node);
- code.addStatement(insts.LoadMetadataInstruction(code.getNextProgramCounter(), 2, TypeReference.JavaLangInvokeMethodType, ref.getDescriptor()));
- code.addStatement(insts.ReturnInstruction(code.getNextProgramCounter(), 2, false));
- }
- irs.put(node, new SoftReference<>(m.makeIR(node.getContext(), SSAOptions.defaultOptions())));
- }
-
- return irs.get(node).get();
- }
-
@Override
public IRView getIRView(CGNode node) {
return getIR(node);
@@ -294,6 +382,100 @@ public class MethodHandles {
public ControlFlowGraph getCFG(CGNode n) {
return getIR(n).getControlFlowGraph();
}
+
+ }
+
+ public static class FindContextInterpreterImpl extends HandlersContextInterpreterImpl {
+
+ @Override
+ public boolean understands(CGNode node) {
+ return isFindStatic(node) && node.getContext() instanceof FindContext;
+ }
+
+ @Override
+ public IR getIR(CGNode node) {
+ if (!irs.containsKey(node) || irs.get(node).get() == null) {
+ MethodSummary code = new MethodSummary(node.getMethod().getReference());
+ SummarizedMethod m = new SummarizedMethod(node.getMethod().getReference(), code, node.getMethod().getDeclaringClass());
+ SSAInstructionFactory insts = node.getMethod().getDeclaringClass().getClassLoader().getLanguage().instructionFactory();
+ assert node.getContext() instanceof FindContext;
+
+ @SuppressWarnings("unchecked")
+ IClass cls = node.getClassHierarchy().lookupClass(((HandlesItem)node.getContext().get(CLASS_KEY)).item);
+ @SuppressWarnings("unchecked")
+ String selector = ((HandlesItem)node.getContext().get(NAME_KEY)).item;
+
+ int vn = 10;
+ for(IMethod handleMethod : cls.getAllMethods()) {
+ if (handleMethod.getName().toString().contains(selector)) {
+ code.addStatement(insts.LoadMetadataInstruction(code.getNextProgramCounter(), vn, TypeReference.JavaLangInvokeMethodHandle, handleMethod.getReference()));
+ code.addStatement(insts.ReturnInstruction(code.getNextProgramCounter(), vn , false));
+ vn++;
+ }
+ }
+ irs.put(node, new SoftReference<>(m.makeIR(node.getContext(), SSAOptions.defaultOptions())));
+ }
+
+ return irs.get(node).get();
+ }
+ }
+
+ public static class InvokeContextInterpreterImpl extends HandlersContextInterpreterImpl {
+
+ @Override
+ public boolean understands(CGNode node) {
+ return (isInvoke(node) || isType(node)) && node.getContext() instanceof MethodContext;
+ }
+
+ @Override
+ public IR getIR(CGNode node) {
+ if (!irs.containsKey(node) || irs.get(node).get() == null) {
+ MethodSummary code = new MethodSummary(node.getMethod().getReference());
+ SummarizedMethod m = new SummarizedMethod(node.getMethod().getReference(), code, node.getMethod().getDeclaringClass());
+ SSAInstructionFactory insts = node.getMethod().getDeclaringClass().getClassLoader().getLanguage().instructionFactory();
+ assert node.getContext() instanceof MethodContext;
+ MethodReference ref = ((MethodContext)node.getContext()).method;
+ boolean isStatic = node.getClassHierarchy().resolveMethod(ref).isStatic();
+ boolean isVoid = ref.getReturnType().equals(TypeReference.Void);
+ if (isInvoke(node)) {
+ String name = node.getMethod().getName().toString();
+ if ("invokeWithArguments".equals(name)) {
+ int nargs = ref.getNumberOfParameters();
+ int params[] = new int[nargs];
+ for(int i = 0; i < nargs; i++) {
+ code.addConstant(i+nargs+3, new ConstantValue(i));
+ code.addStatement(insts.ArrayLoadInstruction(code.getNextProgramCounter(), i+3, 1, i+nargs+3, TypeReference.JavaLangObject));
+ params[i] = i+3;
+ }
+ CallSiteReference site = CallSiteReference.make(nargs+1, ref, isStatic? Dispatch.STATIC: Dispatch.SPECIAL);
+ code.addStatement(insts.InvokeInstruction(code.getNextProgramCounter(), 2*nargs+3, params, 2*nargs+4, site, null));
+ code.addStatement(insts.ReturnInstruction(code.getNextProgramCounter(), 2*nargs+3, false));
+ } else if ("invokeExact".equals(name)) {
+ int nargs = node.getMethod().getReference().getNumberOfParameters();
+ int params[] = new int[nargs];
+ if (nargs == ref.getNumberOfParameters() + (isStatic? 0: 1)) {
+ for(int i = 0; i < nargs; i++) {
+ params[i] = i+2;
+ }
+ CallSiteReference site = CallSiteReference.make(0, ref, isStatic? Dispatch.STATIC: Dispatch.SPECIAL);
+ if (isVoid) {
+ code.addStatement(insts.InvokeInstruction(code.getNextProgramCounter(), params, nargs+2, site, null));
+ } else {
+ code.addStatement(insts.InvokeInstruction(code.getNextProgramCounter(), nargs+2, params, nargs+3, site, null));
+ code.addStatement(insts.ReturnInstruction(code.getNextProgramCounter(), nargs+2, false));
+ }
+ }
+ }
+ } else {
+ assert isType(node);
+ code.addStatement(insts.LoadMetadataInstruction(code.getNextProgramCounter(), 2, TypeReference.JavaLangInvokeMethodType, ref.getDescriptor()));
+ code.addStatement(insts.ReturnInstruction(code.getNextProgramCounter(), 2, false));
+ }
+ irs.put(node, new SoftReference<>(m.makeIR(node.getContext(), SSAOptions.defaultOptions())));
+ }
+
+ return irs.get(node).get();
+ }
}
}
diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationCallGraphBuilder.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationCallGraphBuilder.java
index 9b8d8a7d2..8d403695c 100644
--- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationCallGraphBuilder.java
+++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationCallGraphBuilder.java
@@ -711,7 +711,6 @@ public abstract class PropagationCallGraphBuilder implements CallGraphBuilder new CrossProductRec(constParams, call, node,
+
+ currentObjs.foreachExcluding(oldObjs, x -> new CrossProductRec(constParams, call, node,
v -> {
IClass recv = null;
if (call.getCallSite().isDispatch()) {
recv = v[0].getConcreteType();
}
+
CGNode target = getTargetForCall(node, call.getCallSite(), recv, v);
if (target != null) {
changed.b = true;
diff --git a/com.ibm.wala.core/src/com/ibm/wala/types/TypeReference.java b/com.ibm.wala.core/src/com/ibm/wala/types/TypeReference.java
index 563c68275..eb37e8a2d 100644
--- a/com.ibm.wala.core/src/com/ibm/wala/types/TypeReference.java
+++ b/com.ibm.wala.core/src/com/ibm/wala/types/TypeReference.java
@@ -158,6 +158,10 @@ public final class TypeReference implements Serializable {
public final static TypeReference JavaLangInvokeMethodHandle = findOrCreate(ClassLoaderReference.Primordial, JavaLangInvokeMethodHandleName);
+ private final static TypeName JavaLangInvokeMethodHandlesLookupName = TypeName.string2TypeName("Ljava/lang/invoke/MethodHandles$Lookup");
+
+ public final static TypeReference JavaLangInvokeMethodHandlesLookup = findOrCreate(ClassLoaderReference.Primordial, JavaLangInvokeMethodHandlesLookupName);
+
private final static TypeName JavaLangInvokeMethodTypeName = TypeName.string2TypeName("Ljava/lang/invoke/MethodType");
public final static TypeReference JavaLangInvokeMethodType = findOrCreate(ClassLoaderReference.Primordial, JavaLangInvokeMethodTypeName);