Java 8 suport enhancements, mostly to model lambdas compiled to

invokedynamic
This commit is contained in:
Julian Dolby 2015-08-12 15:20:21 -04:00
parent f760672215
commit 671bd98977
29 changed files with 609 additions and 82 deletions

View File

@ -470,12 +470,12 @@ public class JavaScriptLoader extends CAstAbstractModuleLoader {
}
@Override
public SSAInvokeInstruction InvokeInstruction(int iindex, int result, int[] params, int exception, CallSiteReference site) {
public SSAInvokeInstruction InvokeInstruction(int iindex, int result, int[] params, int exception, CallSiteReference site, BootstrapMethod bootstrap) {
throw new UnsupportedOperationException();
}
@Override
public SSAInvokeInstruction InvokeInstruction(int iindex, int[] params, int exception, CallSiteReference site) {
public SSAInvokeInstruction InvokeInstruction(int iindex, int[] params, int exception, CallSiteReference site, BootstrapMethod bootstrap) {
throw new UnsupportedOperationException();
}
@ -605,11 +605,6 @@ public class JavaScriptLoader extends CAstAbstractModuleLoader {
return new SetPrototype(iindex, object, prototype);
}
@Override
public SSAInstruction InvokeInstruction(int i, int[] js, int j, CallSiteReference site, BootstrapMethod bootstrap) {
throw new UnsupportedOperationException();
}
};
}

View File

@ -3,7 +3,7 @@ package lambda;
import java.util.Arrays;
import java.util.Comparator;
public class SortingExample {
public class SortingExample {
private final String[] strings;
public SortingExample(int n) {
@ -12,24 +12,43 @@ public class SortingExample {
strings[i] = "str" + i;
}
}
private String[] sort(Comparator<String> c) {
private String[] sort(Comparator<String> c) {
String[] strs = strings.clone();
Arrays.sort(strs, c);
return strs;
}
public String[] sortForward() {
return sort( (String l, String r) -> l.compareTo(r));
private static int id1(int x) { return x; }
public String[] sortForward() {
return sort( (String l, String r) -> id1(l.compareTo(r)));
}
private static int id2(int x) { return x; }
public String[] sort(int v) {
return sort( (String l, String r) -> id2(l.compareTo(r) * v));
}
private int id3(int x) { return x; }
public String[] sort(String v) {
return sort( (String l, String r) -> id3(l.compareTo(v) + v.compareTo(r)));
}
private static int id4(int x) { return x; }
public String[] sortBackward() {
return sort( (String l, String r) -> r.compareTo(l));
return sort( (String l, String r) -> id4(r.compareTo(l)));
}
public static void main(String[] args) {
SortingExample x = new SortingExample(10);
System.err.println( Arrays.toString( x.sortForward() ));
System.err.println( Arrays.toString( x.sort(1) ));
System.err.println( Arrays.toString( x.sortBackward() ));
System.err.println( Arrays.toString( x.sort(-1) ));
System.err.println( Arrays.toString( x.sort( "something" ) ));
}
}

View File

@ -19,6 +19,7 @@ import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.CallGraphBuilder;
import com.ibm.wala.ipa.callgraph.Entrypoint;
import com.ibm.wala.ipa.callgraph.impl.Util;
import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.config.AnalysisScopeReader;
@ -75,7 +76,7 @@ public class CallGraphTestUtil {
S.start();
}
CallGraphBuilder builder = Util.makeZeroCFABuilder(options, cache, cha, scope);
SSAPropagationCallGraphBuilder builder = Util.makeZeroCFABuilder(options, cache, cha, scope);
CallGraph cg = builder.makeCallGraph(options, null);
if (testPAtoString) {
builder.getPointerAnalysis().toString();

View File

@ -11,13 +11,10 @@
package com.ibm.wala.core.tests.callGraph;
import java.io.IOException;
import java.util.Iterator;
import java.util.Set;
import org.junit.Assert;
import org.junit.Test;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.core.tests.util.TestConstants;
import com.ibm.wala.core.tests.util.WalaTestCase;
import com.ibm.wala.ipa.callgraph.AnalysisCache;
@ -26,7 +23,6 @@ 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.impl.AllApplicationEntrypoints;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.ipa.cha.ClassHierarchyException;
import com.ibm.wala.types.ClassLoaderReference;

View File

@ -0,0 +1,82 @@
/*******************************************************************************
* Copyright (c) 2006 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.Iterator;
import java.util.Set;
import org.junit.Assert;
import org.junit.Test;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.core.tests.util.TestConstants;
import com.ibm.wala.core.tests.util.WalaTestCase;
import com.ibm.wala.ipa.callgraph.AnalysisCache;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
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.cha.ClassHierarchy;
import com.ibm.wala.ipa.cha.ClassHierarchyException;
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;
/**
* Check properties of a call to clone() in RTA
*/
public class LambdaTest extends WalaTestCase {
@Test public void testSortingExample() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException {
AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, CallGraphTestUtil.REGRESSION_EXCLUSIONS);
ClassHierarchy cha = ClassHierarchy.make(scope);
Iterable<Entrypoint> entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha,
"Llambda/SortingExample");
AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints);
CallGraph cg = CallGraphTestUtil.buildZeroCFA(options, new AnalysisCache(), cha, scope, false);
// Find compareTo
TypeReference str = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/String");
MethodReference ct = MethodReference.findOrCreate(str, Atom.findOrCreateUnicodeAtom("compareTo"), Descriptor.findOrCreateUTF8("(Ljava/lang/String;)I"));
Set<CGNode> ctnodes = cg.getNodes(ct);
checkCompareToCalls(cg, ctnodes, "id1", 1);
checkCompareToCalls(cg, ctnodes, "id2", 1);
checkCompareToCalls(cg, ctnodes, "id3", 2);
checkCompareToCalls(cg, ctnodes, "id4", 1);
}
protected void checkCompareToCalls(CallGraph cg, Set<CGNode> ctnodes, String x, int expected) {
// Find node corresponding to id1
TypeReference tid1 = TypeReference.findOrCreate(ClassLoaderReference.Application, "Llambda/SortingExample");
MethodReference mid1 = MethodReference.findOrCreate(tid1, x, "(I)I");
Assert.assertTrue("expect " + x + " node", cg.getNodes(mid1).iterator().hasNext());
CGNode id1node = cg.getNodes(mid1).iterator().next();
// caller of id1 is dynamic from sortForward, and has 1 compareTo
CGNode sfnode = cg.getPredNodes(id1node).next();
int count = 0;
for(Iterator<CallSiteReference> sites = sfnode.iterateCallSites(); sites.hasNext(); ) {
if (ctnodes.containsAll(cg.getPossibleTargets(sfnode, sites.next()))) {
count++;
}
}
Assert.assertEquals("expected one call to compareTo", expected, count);
System.err.println("found " + count + " compareTo calls in " + sfnode);
}
}

View File

@ -265,7 +265,7 @@ public abstract class AbstractReflectionInterpreter implements SSAContextInterpr
int[] params = new int[1];
params[0] = alloc;
int exc = getExceptionsForType(t);
SSAInvokeInstruction s = insts.InvokeInstruction(allInstructions.size(), params, exc, site);
SSAInvokeInstruction s = insts.InvokeInstruction(allInstructions.size(), params, exc, site, null);
calls.add(s);
allInstructions.add(s);
}

View File

@ -176,7 +176,7 @@ public class CloneInterpreter implements SSAContextInterpreter {
int[] params = new int[2];
params[0] = 1;
params[1] = retValue;
SSAInvokeInstruction S = insts.InvokeInstruction(statements.size(), params, exceptionValue, ARRAYCOPY_SITE);
SSAInvokeInstruction S = insts.InvokeInstruction(statements.size(), params, exceptionValue, ARRAYCOPY_SITE, null);
statements.add(S);
} else {
// copy the fields over, one by one.

View File

@ -490,7 +490,7 @@ public class FactoryBypassInterpreter extends AbstractReflectionInterpreter {
int[] params = new int[1];
params[0] = alloc;
int exc = getExceptionsForType(T);
SSAInvokeInstruction s = insts.InvokeInstruction(allInstructions.size(), params, exc, site);
SSAInvokeInstruction s = insts.InvokeInstruction(allInstructions.size(), params, exc, site, null);
calls.add(s);
allInstructions.add(s);
}
@ -558,7 +558,7 @@ public class FactoryBypassInterpreter extends AbstractReflectionInterpreter {
CallSiteReference site = CallSiteReference.make(getCallSiteForType(T), init, IInvokeInstruction.Dispatch.SPECIAL);
int[] params = new int[1];
params[0] = i;
SSAInvokeInstruction s = insts.InvokeInstruction(allInstructions.size(), params, getExceptionsForType(T), site);
SSAInvokeInstruction s = insts.InvokeInstruction(allInstructions.size(), params, getExceptionsForType(T), site, null);
calls.add(s);
allInstructions.add(s);
}

View File

@ -201,17 +201,17 @@ public class ReflectiveInvocationInterpreter extends AbstractReflectionInterpret
// emit the dispatch and return instructions
if (method.getReference().equals(CTOR_NEW_INSTANCE)) {
m.addInstruction(null, insts.InvokeInstruction(m.allInstructions.size(), args, exceptions, CallSiteReference.make(pc++, target.getReference(),
IInvokeInstruction.Dispatch.SPECIAL)), false);
IInvokeInstruction.Dispatch.SPECIAL), null), false);
m.addInstruction(null, insts.ReturnInstruction(m.allInstructions.size(), args[0], false), false);
} else {
Dispatch d = target.isStatic() ? Dispatch.STATIC : Dispatch.VIRTUAL;
if (target.getReturnType().equals(TypeReference.Void)) {
m.addInstruction(null, insts.InvokeInstruction(m.allInstructions.size(), args, exceptions, CallSiteReference.make(pc++, target.getReference(), d)),
m.addInstruction(null, insts.InvokeInstruction(m.allInstructions.size(), args, exceptions, CallSiteReference.make(pc++, target.getReference(), d), null),
false);
} else {
result = nextLocal++;
m.addInstruction(null, insts.InvokeInstruction(m.allInstructions.size(), result, args, exceptions, CallSiteReference.make(pc++,
target.getReference(), d)), false);
target.getReference(), d), null), false);
m.addInstruction(null, insts.ReturnInstruction(m.allInstructions.size(), result, false), false);
}
}

View File

@ -272,7 +272,7 @@ public class MethodHandles {
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));
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();

View File

@ -228,44 +228,57 @@ public class JavaLanguage extends LanguageImpl implements BytecodeLanguage, Cons
}
@Override
public SSAInvokeInstruction InvokeInstruction(int iindex, int result, int[] params, int exception, CallSiteReference site) {
return new SSAInvokeInstruction(iindex, result, params, exception, site) {
@Override
public Collection<TypeReference> getExceptionTypes() {
if (!isStatic()) {
return getNullPointerException();
} else {
return Collections.emptySet();
public SSAInvokeInstruction InvokeInstruction(int iindex, int result, int[] params, int exception, CallSiteReference site, BootstrapMethod bootstrap) {
if (bootstrap != null) {
return new SSAInvokeDynamicInstruction(iindex, result, params, exception, site, bootstrap) {
@Override
public Collection<TypeReference> getExceptionTypes() {
if (!isStatic()) {
return getNullPointerException();
} else {
return Collections.emptySet();
}
}
}
};
}
public SSAInvokeDynamicInstruction InvokeInstruction(int result, int[] params, int exception, CallSiteReference site, BootstrapMethod bootstrap) {
return new SSAInvokeDynamicInstruction(result, params, exception, site, bootstrap) {
@Override
public Collection<TypeReference> getExceptionTypes() {
if (!isStatic()) {
return getNullPointerException();
} else {
return Collections.emptySet();
};
} else {
return new SSAInvokeInstruction(iindex, result, params, exception, site) {
@Override
public Collection<TypeReference> getExceptionTypes() {
if (!isStatic()) {
return getNullPointerException();
} else {
return Collections.emptySet();
}
}
}
};
};
}
}
@Override
public SSAInvokeInstruction InvokeInstruction(int iindex, int[] params, int exception, CallSiteReference site) {
return new SSAInvokeInstruction(iindex, params, exception, site) {
@Override
public Collection<TypeReference> getExceptionTypes() {
if (!isStatic()) {
return getNullPointerException();
} else {
return Collections.emptySet();
public SSAInvokeInstruction InvokeInstruction(int iindex, int[] params, int exception, CallSiteReference site, BootstrapMethod bootstrap) {
if (bootstrap != null) {
return new SSAInvokeDynamicInstruction(iindex, params, exception, site, bootstrap) {
@Override
public Collection<TypeReference> getExceptionTypes() {
if (!isStatic()) {
return getNullPointerException();
} else {
return Collections.emptySet();
}
}
}
};
};
} else {
return new SSAInvokeInstruction(iindex, params, exception, site) {
@Override
public Collection<TypeReference> getExceptionTypes() {
if (!isStatic()) {
return getNullPointerException();
} else {
return Collections.emptySet();
}
}
};
}
}
@Override

View File

@ -137,9 +137,9 @@ public abstract class AbstractRootMethod extends SyntheticMethod {
CallSiteReference newSite = CallSiteReference.make(statements.size(), site.getDeclaredTarget(), site.getInvocationCode());
SSAInvokeInstruction s = null;
if (newSite.getDeclaredTarget().getReturnType().equals(TypeReference.Void)) {
s = insts.InvokeInstruction(statements.size(), params, nextLocal++, newSite);
s = insts.InvokeInstruction(statements.size(), params, nextLocal++, newSite, null);
} else {
s = insts.InvokeInstruction(statements.size(), nextLocal++, params, nextLocal++, newSite);
s = insts.InvokeInstruction(statements.size(), nextLocal++, params, nextLocal++, newSite, null);
}
statements.add(s);
cache.invalidate(this, Everywhere.EVERYWHERE);

View File

@ -38,6 +38,7 @@ import com.ibm.wala.ipa.callgraph.propagation.rta.BasicRTABuilder;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ipa.summaries.BypassClassTargetSelector;
import com.ibm.wala.ipa.summaries.BypassMethodTargetSelector;
import com.ibm.wala.ipa.summaries.LambdaMethodTargetSelector;
import com.ibm.wala.ipa.summaries.XMLMethodSummaryReader;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.Descriptor;
@ -76,7 +77,7 @@ public class Util {
if (options == null) {
throw new IllegalArgumentException("options is null");
}
options.setSelector(new ClassHierarchyMethodTargetSelector(cha));
options.setSelector(new LambdaMethodTargetSelector(new ClassHierarchyMethodTargetSelector(cha)));
options.setSelector(new ClassHierarchyClassTargetSelector(cha));
}

View File

@ -0,0 +1,85 @@
/*******************************************************************************
* Copyright (c) 2007 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.ipa.summaries;
import java.util.WeakHashMap;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.classLoader.Language;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.MethodTargetSelector;
import com.ibm.wala.shrikeCT.BootstrapMethodsReader.BootstrapMethod;
import com.ibm.wala.ssa.SSAInstructionFactory;
import com.ibm.wala.ssa.SSAInvokeDynamicInstruction;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.strings.Atom;
public class LambdaMethodTargetSelector implements MethodTargetSelector {
private final WeakHashMap<BootstrapMethod, SummarizedMethod> summaries = new WeakHashMap<BootstrapMethod, SummarizedMethod>();
private final MethodTargetSelector base;
public LambdaMethodTargetSelector(MethodTargetSelector base) {
this.base = base;
}
@Override
public IMethod getCalleeTarget(CGNode caller, CallSiteReference site, IClass receiver) {
if (! site.getDeclaredTarget().getName().equals(MethodReference.clinitName) &&
caller.getClassHierarchy().lookupClass(TypeReference.LambdaMetaFactory) != null &&
caller.getClassHierarchy().lookupClass(TypeReference.LambdaMetaFactory).equals(
caller.getClassHierarchy().lookupClass(site.getDeclaredTarget().getDeclaringClass())))
{
SSAInvokeDynamicInstruction invoke = (SSAInvokeDynamicInstruction)caller.getIR().getCalls(site)[0];
if (!summaries.containsKey(invoke.getBootstrap())) {
String cls = caller.getMethod().getDeclaringClass().getName().toString().replace("/", "$").substring(1);
int bootstrapIndex = invoke.getBootstrap().getIndexInClassFile();
MethodReference ref =
MethodReference.findOrCreate(
site.getDeclaredTarget().getDeclaringClass(),
Atom.findOrCreateUnicodeAtom(site.getDeclaredTarget().getName().toString() +"$" + cls + "$" + bootstrapIndex),
site.getDeclaredTarget().getDescriptor());
MethodSummary summary = new MethodSummary(ref);
if (site.isStatic()) {
summary.setStatic(true);
}
int index = 0;
int v = site.getDeclaredTarget().getNumberOfParameters() + 2;
IClass lambda = LambdaSummaryClass.findOrCreate(caller, invoke);
SSAInstructionFactory insts = Language.JAVA.instructionFactory();
summary.addStatement(insts.NewInstruction(index, v, NewSiteReference.make(index, lambda.getReference())));
index++;
for(int i = 0; i < site.getDeclaredTarget().getNumberOfParameters(); i++) {
summary.addStatement(
insts.PutInstruction(index++, v, i+1, lambda.getField(Atom.findOrCreateUnicodeAtom("c" + i)).getReference()));
}
summary.addStatement(insts.ReturnInstruction(index++, v, false));
summaries.put(invoke.getBootstrap(), new SummarizedMethod(ref, summary, caller.getClassHierarchy().lookupClass(site.getDeclaredTarget().getDeclaringClass())));
}
return summaries.get(invoke.getBootstrap());
} else {
return base.getCalleeTarget(caller, site, receiver);
}
}
}

View File

@ -0,0 +1,304 @@
/*******************************************************************************
* Copyright (c) 2015 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.ipa.summaries;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IField;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.classLoader.SyntheticClass;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.shrikeBT.Constants;
import com.ibm.wala.shrikeBT.IInvokeInstruction.Dispatch;
import com.ibm.wala.shrikeCT.BootstrapMethodsReader.BootstrapMethod;
import com.ibm.wala.shrikeCT.InvalidClassFileException;
import com.ibm.wala.ssa.SSAInstructionFactory;
import com.ibm.wala.ssa.SSAInvokeDynamicInstruction;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.Descriptor;
import com.ibm.wala.types.FieldReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.Selector;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.types.annotations.Annotation;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.strings.Atom;
public class LambdaSummaryClass extends SyntheticClass {
private static WeakHashMap<BootstrapMethod, LambdaSummaryClass> summaries = new WeakHashMap<BootstrapMethod, LambdaSummaryClass>();
public static LambdaSummaryClass findOrCreate(CGNode caller, SSAInvokeDynamicInstruction inst) {
if (! summaries.containsKey(inst.getBootstrap())) {
String bootstrapCls = caller.getMethod().getDeclaringClass().getName().toString().replace("/", "$").substring(1);
int bootstrapIndex = inst.getBootstrap().getIndexInClassFile();
TypeReference ref = TypeReference.findOrCreate(ClassLoaderReference.Primordial, "Lwala/lambda" + "$" + bootstrapCls + "$" + bootstrapIndex);
LambdaSummaryClass cls = new LambdaSummaryClass(ref, caller.getClassHierarchy(), inst);
caller.getClassHierarchy().addClass(cls);
summaries.put(inst.getBootstrap(), cls);
}
return summaries.get(inst.getBootstrap());
}
private final SSAInvokeDynamicInstruction invoke;
private final Map<Atom,IField> fields;
private final Map<Selector,IMethod> methods;
public LambdaSummaryClass(TypeReference T, IClassHierarchy cha, SSAInvokeDynamicInstruction invoke) {
super(T, cha);
this.invoke = invoke;
this.fields = makeFields();
this.methods = Collections.singletonMap(trampoline().getSelector(), makeTrampoline());
}
@Override
public boolean isPublic() {
return false;
}
@Override
public boolean isPrivate() {
return false;
}
@Override
public int getModifiers() throws UnsupportedOperationException {
return Constants.ACC_FINAL | Constants.ACC_SUPER;
}
@Override
public IClass getSuperclass() {
return getClassHierarchy().getRootClass();
}
@Override
public Collection<? extends IClass> getDirectInterfaces() {
return Collections.singleton(getClassHierarchy().lookupClass(invoke.getDeclaredResultType()));
}
@Override
public Collection<IClass> getAllImplementedInterfaces() {
IClass iface = getClassHierarchy().lookupClass(invoke.getDeclaredResultType());
Set<IClass> result = HashSetFactory.make(iface.getAllImplementedInterfaces());
result.add(iface);
return result;
}
@Override
public IMethod getMethod(Selector selector) {
return methods.get(selector);
}
@Override
public IField getField(Atom name) {
return fields.get(name);
}
@Override
public IMethod getClassInitializer() {
return null;
}
@Override
public Collection<IMethod> getDeclaredMethods() {
return methods.values();
}
@Override
public Collection<IField> getAllInstanceFields() {
return fields.values();
}
@Override
public Collection<IField> getAllStaticFields() {
return Collections.emptySet();
}
@Override
public Collection<IField> getAllFields() {
return getAllInstanceFields();
}
@Override
public Collection<IMethod> getAllMethods() {
return methods.values();
}
@Override
public Collection<IField> getDeclaredInstanceFields() {
return fields.values();
}
private Map<Atom,IField> makeFields() {
Map<Atom,IField> result = HashMapFactory.make();
for(int i = 0; i < invoke.getNumberOfParameters(); i++) {
final int yuck = i;
result.put(Atom.findOrCreateUnicodeAtom("c" + yuck), new IField() {
@Override
public IClass getDeclaringClass() {
return LambdaSummaryClass.this;
}
@Override
public Atom getName() {
return Atom.findOrCreateUnicodeAtom("c" + yuck);
}
@Override
public Collection<Annotation> getAnnotations() {
return Collections.emptySet();
}
@Override
public IClassHierarchy getClassHierarchy() {
return LambdaSummaryClass.this.getClassHierarchy();
}
@Override
public TypeReference getFieldTypeReference() {
return invoke.getDeclaredTarget().getParameterType(yuck);
}
@Override
public FieldReference getReference() {
return FieldReference.findOrCreate(LambdaSummaryClass.this.getReference(), getName(), getFieldTypeReference());
}
@Override
public boolean isFinal() {
return true;
}
@Override
public boolean isPrivate() {
return true;
}
@Override
public boolean isProtected() {
return false;
}
@Override
public boolean isPublic() {
return false;
}
@Override
public boolean isStatic() {
return false;
}
@Override
public boolean isVolatile() {
return false;
}
});
}
return result;
}
private MethodReference trampoline() {
try {
return MethodReference.findOrCreate(LambdaSummaryClass.this.getReference(), invoke.getDeclaredTarget().getName(), Descriptor.findOrCreateUTF8(getLambdaDeclaredSignature()));
} catch (IllegalArgumentException | InvalidClassFileException e) {
assert false : e;
return null;
}
}
private String getLambdaCalleeClass() throws IllegalArgumentException, InvalidClassFileException {
int cpIndex = invoke.getBootstrap().callArgumentIndex(1);
return "L" + invoke.getBootstrap().getCP().getCPHandleClass(cpIndex);
}
private String getLambdaCalleeName() throws IllegalArgumentException, InvalidClassFileException {
int cpIndex = invoke.getBootstrap().callArgumentIndex(1);
return invoke.getBootstrap().getCP().getCPHandleName(cpIndex);
}
private String getLambdaCalleeSignature() throws IllegalArgumentException, InvalidClassFileException {
int cpIndex = invoke.getBootstrap().callArgumentIndex(1);
return invoke.getBootstrap().getCP().getCPHandleType(cpIndex);
}
private String getLambdaDeclaredSignature() throws IllegalArgumentException, InvalidClassFileException {
int cpIndex = invoke.getBootstrap().callArgumentIndex(0);
return invoke.getBootstrap().getCP().getCPMethodType(cpIndex);
}
private int getLambdaCalleeKind() throws IllegalArgumentException, InvalidClassFileException {
int cpIndex = invoke.getBootstrap().callArgumentIndex(1);
return invoke.getBootstrap().getCP().getCPHandleKind(cpIndex);
}
private IMethod makeTrampoline() {
SSAInstructionFactory insts = getClassLoader().getInstructionFactory();
MethodReference ref = trampoline();
MethodSummary summary = new MethodSummary(ref);
int inst = 0;
int args = invoke.getNumberOfParameters(), v = args + 1;
for(int i = 0; i < invoke.getNumberOfParameters(); i++) {
Atom f = Atom.findOrCreateUnicodeAtom("c" + i);
summary.addStatement(insts.GetInstruction(inst++, v++, 1, getField(f).getReference()));
}
try {
MethodReference callee = MethodReference.findOrCreate(ClassLoaderReference.Application, getLambdaCalleeClass(), getLambdaCalleeName(), getLambdaCalleeSignature());
Dispatch code;
int kind = getLambdaCalleeKind();
switch (kind) {
case 5: code = Dispatch.VIRTUAL; break;
case 6: code = Dispatch.STATIC; break;
case 7: code = Dispatch.SPECIAL; break;
case 9: code = Dispatch.INTERFACE; break;
default:
throw new Error("unexpected dynamic invoke type " + kind);
}
int numParams = getClassHierarchy().resolveMethod(callee).getNumberOfParameters();
int params[] = new int[ numParams ];
for(int i = 0; i < invoke.getNumberOfParameters(); i++) {
params[i] = args + i + 1;
}
for(int n = 2, i = invoke.getNumberOfParameters(); i < numParams; i++) {
params[i] = n++;
}
if (callee.getReturnType().equals(TypeReference.Void)) {
summary.addStatement(insts.InvokeInstruction(inst++, params, v++, CallSiteReference.make(inst, callee, code), null));
} else {
int ret = v++;
summary.addStatement(insts.InvokeInstruction(inst++, ret, params, v++, CallSiteReference.make(inst, callee, code), null));
summary.addStatement(insts.ReturnInstruction(inst++, ret, callee.getReturnType().isPrimitiveType()));
}
} catch (IllegalArgumentException | InvalidClassFileException e) {
assert false : e.toString();
}
SummarizedMethod method = new SummarizedMethod(ref, summary, LambdaSummaryClass.this);
return method;
}
@Override
public Collection<IField> getDeclaredStaticFields() {
return Collections.emptySet();
}
@Override
public boolean isReferenceType() {
return true;
}
}

View File

@ -485,10 +485,10 @@ public class XMLMethodSummaryReader implements BytecodeConstants {
int defNum = nextLocal;
symbolTable.put(defVar, new Integer(nextLocal++));
governingMethod.addStatement(insts.InvokeInstruction(governingMethod.getNumberOfStatements(), defNum, params, exceptionValue, site));
governingMethod.addStatement(insts.InvokeInstruction(governingMethod.getNumberOfStatements(), defNum, params, exceptionValue, site, null));
} else {
// ignore return value, if any
governingMethod.addStatement(insts.InvokeInstruction(governingMethod.getNumberOfStatements(), params, exceptionValue, site));
governingMethod.addStatement(insts.InvokeInstruction(governingMethod.getNumberOfStatements(), params, exceptionValue, site, null));
}
}

View File

@ -41,11 +41,13 @@ import com.ibm.wala.shrikeBT.IStoreInstruction;
import com.ibm.wala.shrikeBT.ITypeTestInstruction;
import com.ibm.wala.shrikeBT.IUnaryOpInstruction;
import com.ibm.wala.shrikeBT.IndirectionData;
import com.ibm.wala.shrikeBT.InvokeDynamicInstruction;
import com.ibm.wala.shrikeBT.MonitorInstruction;
import com.ibm.wala.shrikeBT.NewInstruction;
import com.ibm.wala.shrikeBT.ReturnInstruction;
import com.ibm.wala.shrikeBT.SwitchInstruction;
import com.ibm.wala.shrikeBT.ThrowInstruction;
import com.ibm.wala.shrikeCT.BootstrapMethodsReader.BootstrapMethod;
import com.ibm.wala.shrikeCT.InvalidClassFileException;
import com.ibm.wala.ssa.ShrikeIndirectionData.ShrikeLocalName;
import com.ibm.wala.types.ClassLoaderReference;
@ -588,12 +590,18 @@ public class SSABuilder extends AbstractIntStackMachine {
IInvokeInstruction.IDispatch code = instruction.getInvocationCode();
CallSiteReference site = CallSiteReference.make(getCurrentProgramCounter(), m, code);
int exc = reuseOrCreateException();
BootstrapMethod bootstrap = null;
if (instruction instanceof InvokeDynamicInstruction) {
bootstrap = ((InvokeDynamicInstruction)instruction).getBootstrap();
}
if (instruction.getPushedWordSize() > 0) {
int result = reuseOrCreateDef();
workingState.push(result);
emitInstruction(insts.InvokeInstruction(getCurrentInstructionIndex(), result, params, exc, site));
emitInstruction(insts.InvokeInstruction(getCurrentInstructionIndex(), result, params, exc, site, bootstrap));
} else {
emitInstruction(insts.InvokeInstruction(getCurrentInstructionIndex(), params, exc, site));
emitInstruction(insts.InvokeInstruction(getCurrentInstructionIndex(), params, exc, site, bootstrap));
}
doIndirectWrites(bytecodeIndirections.indirectlyWrittenLocals(getCurrentInstructionIndex()), -1);
}

View File

@ -66,9 +66,9 @@ public interface SSAInstructionFactory {
SSAInstanceofInstruction InstanceofInstruction(int iindex, int result, int ref, TypeReference checkedType);
SSAInvokeInstruction InvokeInstruction(int iindex, int result, int[] params, int exception, CallSiteReference site);
SSAInvokeInstruction InvokeInstruction(int iindex, int result, int[] params, int exception, CallSiteReference site, BootstrapMethod bootstrap);
SSAInvokeInstruction InvokeInstruction(int iindex, int[] params, int exception, CallSiteReference site);
SSAInvokeInstruction InvokeInstruction(int iindex, int[] params, int exception, CallSiteReference site, BootstrapMethod bootstrap);
SSALoadIndirectInstruction LoadIndirectInstruction(int iindex, int lval, TypeReference t, int addressVal);
@ -100,6 +100,4 @@ public interface SSAInstructionFactory {
SSAUnaryOpInstruction UnaryOpInstruction(int iindex, IUnaryOpInstruction.IOperator operator, int result, int val);
SSAInstruction InvokeInstruction(int i, int[] js, int j, CallSiteReference site, BootstrapMethod bootstrap);
}

View File

@ -32,5 +32,8 @@ public class SSAInvokeDynamicInstruction extends SSAInvokeInstruction {
defs == null ? exception : defs[result == -1 ? 0 : 1], site, bootstrap);
}
public BootstrapMethod getBootstrap() {
return bootstrap;
}
}

View File

@ -45,7 +45,7 @@ public abstract class SSAInvokeInstruction extends SSAAbstractInvokeInstruction
// result == -1 for void-returning methods, which are the only calls
// that have a single value def.
return insts.InvokeInstruction(iindex, defs == null || result == -1 ? result : defs[0], uses == null ? params : uses,
defs == null ? exception : defs[result == -1 ? 0 : 1], site);
defs == null ? exception : defs[result == -1 ? 0 : 1], site, null);
}
public static void assertParamsKosher(int result, int[] params, CallSiteReference site) throws IllegalArgumentException {

View File

@ -72,6 +72,12 @@ public final class MethodReference extends MemberReference {
public final static Selector equalsSelector = new Selector(equalsAtom, equalsDesc);
public final static MethodReference lambdaMetafactory =
findOrCreate(
TypeReference.LambdaMetaFactory,
Atom.findOrCreateUnicodeAtom("metafactory"),
Descriptor.findOrCreateUTF8("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;"));
/**
* types of parameters to this method.
*/

View File

@ -344,6 +344,8 @@ public final class TypeReference implements Serializable {
public final static TypeReference Unknown = findOrCreate(ClassLoaderReference.Primordial, UnknownName);
public final static TypeReference LambdaMetaFactory = findOrCreate(ClassLoaderReference.Primordial, "Ljava/lang/invoke/LambdaMetafactory");
private static TypeReference makePrimitive(TypeName n) {
return makePrimitive(ClassLoaderReference.Primordial, n);
}

View File

@ -202,7 +202,7 @@ public class TypeSafeInstructionFactory {
// TODO somehow check exception?
result.setAssigned();
return insts.InvokeInstruction(iindex, result.getNumber(), aParams, exception.getNumber(), site);
return insts.InvokeInstruction(iindex, result.getNumber(), aParams, exception.getNumber(), site, null);
}
/**
@ -300,7 +300,7 @@ public class TypeSafeInstructionFactory {
// TODO somehow check exception?
return insts.InvokeInstruction(iindex, aParams, exception.getNumber(), site);
return insts.InvokeInstruction(iindex, aParams, exception.getNumber(), site, null);
}

View File

@ -855,7 +855,7 @@ public class DexSSABuilder extends AbstractIntRegisterMachine {
if(m.getReturnType().equals(TypeReference.Void))
{
SSAInstruction inst = insts.InvokeInstruction(getCurrentInstructionIndex(), params, exc, site);
SSAInstruction inst = insts.InvokeInstruction(getCurrentInstructionIndex(), params, exc, site, null);
//System.out.println("Emitting(1) InvokeInstruction: "+inst);
emitInstruction(inst);
} else {
@ -867,7 +867,7 @@ public class DexSSABuilder extends AbstractIntRegisterMachine {
int dest = dexCFG.getDexMethod().getReturnReg();
setLocal(dest, result);
SSAInstruction inst = insts.InvokeInstruction(getCurrentInstructionIndex(), result, params, exc, site);
SSAInstruction inst = insts.InvokeInstruction(getCurrentInstructionIndex(), result, params, exc, site, null);
//System.out.println("Emitting(2) InvokeInstruction: "+inst);
emitInstruction(inst);
}

View File

@ -431,9 +431,9 @@ public class AppModelMethod {
CallSiteReference newSite = CallSiteReference.make(methodSummary.getNumberOfStatements(), site.getDeclaredTarget(), site.getInvocationCode());
SSAInvokeInstruction s = null;
if (newSite.getDeclaredTarget().getReturnType().equals(TypeReference.Void)) {
s = insts.InvokeInstruction(methodSummary.getNumberOfStatements(), params, nextLocal++, newSite);
s = insts.InvokeInstruction(methodSummary.getNumberOfStatements(), params, nextLocal++, newSite, null);
} else {
s = insts.InvokeInstruction(methodSummary.getNumberOfStatements(), nextLocal++, params, nextLocal++, newSite);
s = insts.InvokeInstruction(methodSummary.getNumberOfStatements(), nextLocal++, params, nextLocal++, newSite, null);
}
methodSummary.addStatement(s);
// cache.invalidate(this, Everywhere.EVERYWHERE);

View File

@ -37,8 +37,9 @@ public class CodeScraper implements ClassFileTransformer {
sourceFile = reader.getCP().getCPUtf8(index);
}
}
if (className == null || sourceFile == null || !sourceFile.endsWith("java")) try {
if (className == null || sourceFile == null || !sourceFile.endsWith("java") || true) try {
String log = prefix + File.separator + reader.getName() + ".class";
(new File(log)).getParentFile().mkdirs();
FileOutputStream f = new FileOutputStream(log);
f.write(classfileBuffer);
f.close();
@ -54,7 +55,6 @@ public class CodeScraper implements ClassFileTransformer {
}
public static void premain(String agentArgs, Instrumentation inst) {
System.err.println("adding CodeScraper");
inst.addTransformer(new CodeScraper());
}
}

View File

@ -26,7 +26,7 @@ public class InvokeDynamicInstruction extends Instruction implements IInvokeInst
protected String methodName;
protected String methodType;
public InvokeDynamicInstruction(short opcode, BootstrapMethod bootstrap, String methodName, String methodType) {
private InvokeDynamicInstruction(short opcode, BootstrapMethod bootstrap, String methodName, String methodType) {
super(opcode);
this.bootstrap = bootstrap;
this.methodName = methodName;
@ -93,7 +93,7 @@ public class InvokeDynamicInstruction extends Instruction implements IInvokeInst
@Override
public String getClassType() {
return getBootstrap().methodClass();
return "L" + getBootstrap().methodClass();
}
@Override

View File

@ -19,6 +19,7 @@ import java.util.Arrays;
import java.util.HashMap;
import com.ibm.wala.shrikeBT.IInvokeInstruction.Dispatch;
import com.ibm.wala.shrikeCT.BootstrapMethodsReader.BootstrapMethod;
import com.ibm.wala.util.collections.Pair;
/**

View File

@ -29,6 +29,8 @@ public class BootstrapMethodsReader extends AttributeReader {
Object callArgument(ClassLoader cl, int i);
int callArgumentIndex(int i);
int callArgumentKind(int i);
ConstantPoolParser getCP();
int getIndexInClassFile();
}
private BootstrapMethod entries[];
@ -46,6 +48,7 @@ public class BootstrapMethodsReader extends AttributeReader {
for(int i = 0; i < entries.length; i++) {
final int methodHandleOffset = cr.getUShort(attr + base);
final int argsBase = attr + base + 4;
final int index = i;
final int argumentCount = cr.getUShort(attr + base + 2);
entries[i] = new BootstrapMethod() {
@ -119,10 +122,10 @@ public class BootstrapMethodsReader extends AttributeReader {
return cp.getCPLong(index);
case ClassConstants.CONSTANT_MethodHandle:
String className = cp.getCPHandleClass(index);
Class<?> cls = Class.forName(className.replace('/', '.'), false, cl);
String eltName = cp.getCPHandleName(index);
String eltDesc = cp.getCPHandleType(index);
MethodType type = MethodType.fromMethodDescriptorString(eltDesc, cl);
Class<?> cls = Class.forName(className.replace('/', '.'), false, cl);
Method m = cls.getDeclaredMethod(eltName, type.parameterList().toArray(new Class[type.parameterCount()]));
Lookup lk = MethodHandles.lookup().in(cls);
m.setAccessible(true);
@ -147,6 +150,16 @@ public class BootstrapMethodsReader extends AttributeReader {
}
return null;
}
@Override
public ConstantPoolParser getCP() {
return cp;
}
@Override
public int getIndexInClassFile() {
return index;
}
};
base += (argumentCount*2) + 4;