lambda reloading, invokeinterface support - fixes #82

This commit is contained in:
Andy Clement
2015-03-07 22:11:49 -08:00
parent ad81779bff
commit 1eb033f7e6
14 changed files with 292 additions and 5 deletions

View File

@@ -252,14 +252,17 @@ public class ClassRenamer {
String owner = oldHandle.getOwner();
String name = oldHandle.getName();
String desc = oldHandle.getDesc();
// System.out.println("handle: owner: "+owner);
// System.out.println("handle: name: "+name);
// System.out.println("handle: desc: "+desc);
owner = renameRetargetIfNecessary(owner);
desc = renameRetargetIfNecessary(desc);
Handle newHandle = new Handle(tag,owner,name,desc);
return newHandle;
}
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
// System.out.println("visitInvokeDynamicInsn(name="+name+",desc="+desc+",bsm="+toString(bsm)+",bsmArgs="+toString(bsmArgs)+")");
// Example:
// visitInvokeDynamicInsn(name=m,desc=()Lbasic/LambdaA2$Foo;,
// bsm=[6]java/lang/invoke/LambdaMetafactory.metafactory(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;,

View File

@@ -1571,7 +1571,7 @@ public class TypeRegistry {
// TODO Currently leaking entries in bsmmap with reloads (new ones get added, old ones not removed)
ReloadableType rtype = TypeRegistry.getReloadableType(typeRegistryId, classId);
BsmInfo bsmi = bsmmap.get(rtype.getSlashedName())[bsmId];
return Java8.emulateInvokeDynamic(rtype.getLatestExecutorClass(),bsmi.bsm,bsmi.bsmArgs,caller,nameAndDescriptor, indyParams);
return Java8.emulateInvokeDynamic(rtype,rtype.getLatestExecutorClass(),bsmi.bsm,bsmi.bsmArgs,caller,nameAndDescriptor, indyParams);
}
/**

View File

@@ -20,10 +20,12 @@ import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.springsource.loaded.ReloadableType;
/**
* This class encapsulates dependencies on Java 8 APIs (e.g. LambdaMetafactory).
@@ -89,9 +91,9 @@ public class Java8 {
* @param indyParams parameters when the invokedynamic call is made
* @return the result of the invokedynamic call
*/
public static Object emulateInvokeDynamic(Class<?> executorClass, Handle handle, Object[] bsmArgs, Object lookup, String indyNameAndDescriptor, Object[] indyParams) {
public static Object emulateInvokeDynamic(ReloadableType rtype, Class<?> executorClass, Handle handle, Object[] bsmArgs, Object lookup, String indyNameAndDescriptor, Object[] indyParams) {
try {
CallSite callsite = callLambdaMetaFactory(bsmArgs,lookup,indyNameAndDescriptor,executorClass);
CallSite callsite = callLambdaMetaFactory(rtype, bsmArgs,lookup,indyNameAndDescriptor,executorClass);
return callsite.dynamicInvoker().invokeWithArguments(indyParams);
} catch (Throwable t) {
throw new RuntimeException(t);
@@ -100,7 +102,7 @@ public class Java8 {
// TODO [perf] How about a table of CallSites indexed by invokedynamic number through the class file. Computed on first reference but cleared on reload. Possibly extend this to all invoke types!
// TODO [lambda] Need to handle altMetaFactory which is used when the lambdas are more 'complex' (e.g. Serializable)
public static CallSite callLambdaMetaFactory(Object[] bsmArgs, Object lookup, String indyNameAndDescriptor,Class<?> executorClass) throws Exception {
public static CallSite callLambdaMetaFactory(ReloadableType rtype, Object[] bsmArgs, Object lookup, String indyNameAndDescriptor,Class<?> executorClass) throws Exception {
MethodHandles.Lookup caller = (MethodHandles.Lookup)lookup;
ClassLoader callerLoader = caller.lookupClass().getClassLoader();
@@ -146,6 +148,15 @@ public class Java8 {
implMethod = caller.findStatic(caller.lookupClass(), name, MethodType.fromMethodDescriptorString("(L"+owner+";"+descriptor.substring(1),callerLoader));
}
break;
case Opcodes.H_INVOKEINTERFACE:
Handle h = (Handle)bsmArgs[1];
String interfaceOwner = h.getOwner();
// TODO Should there not be a more direct way to this than classloading?
// TODO What about when this is a method added to the interface on a reload? It won't really exist, should we point
// to the executor? or something else? (maybe just directly the real method that will satisfy the interface - if it can be worked out)
Class<?> interfaceClass = callerLoader.loadClass(interfaceOwner.replace('/','.')); // interface type, eg StreamB$Foo
implMethod = caller.findVirtual(interfaceClass, name, implMethodType);
break;
default:
throw new IllegalStateException("nyi "+bsmArgsHandle.getTag());
}