convert FunctionRef/Def usage to methodhandles.

This commit is contained in:
Robert Muir 2016-06-07 10:23:49 -04:00
parent 3108c399f0
commit 32965f043a
3 changed files with 30 additions and 24 deletions

View File

@ -246,28 +246,24 @@ public final class Def {
int separator = signature.indexOf('.'); int separator = signature.indexOf('.');
FunctionRef ref = new FunctionRef(clazz, signature.substring(0, separator), signature.substring(separator+1)); FunctionRef ref = new FunctionRef(clazz, signature.substring(0, separator), signature.substring(separator+1));
final CallSite callSite; final CallSite callSite;
// XXX: clean all this up to use handles in FunctionRef, deal with ASM in EFunctionRef differently if (ref.interfaceType.equals(ref.samType)) {
MethodType invokedType = MethodType.fromMethodDescriptorString(ref.invokedType.getDescriptor(), Def.class.getClassLoader());
MethodType samMethodType = MethodType.fromMethodDescriptorString(ref.samMethodType.getDescriptor(), Def.class.getClassLoader());
MethodType interfaceType = MethodType.fromMethodDescriptorString(ref.interfaceType.getDescriptor(), Def.class.getClassLoader());
if (ref.interfaceType.equals(ref.samMethodType)) {
callSite = LambdaMetafactory.altMetafactory(lookup, callSite = LambdaMetafactory.altMetafactory(lookup,
ref.invokedName, ref.invokedName,
invokedType, ref.invokedMethodType,
samMethodType, ref.samMethodType,
ref.implMethodHandle, ref.implMethodHandle,
samMethodType, ref.samMethodType,
0); 0);
} else { } else {
callSite = LambdaMetafactory.altMetafactory(lookup, callSite = LambdaMetafactory.altMetafactory(lookup,
ref.invokedName, ref.invokedName,
invokedType, ref.invokedMethodType,
samMethodType, ref.samMethodType,
ref.implMethodHandle, ref.implMethodHandle,
samMethodType, ref.samMethodType,
LambdaMetafactory.FLAG_BRIDGES, LambdaMetafactory.FLAG_BRIDGES,
1, 1,
interfaceType); ref.interfaceMethodType);
} }
// we could actually invoke and cache here (in non-capturing cases), but this is not a speedup. // we could actually invoke and cache here (in non-capturing cases), but this is not a speedup.
MethodHandle factory = callSite.dynamicInvoker().asType(MethodType.methodType(clazz.clazz)); MethodHandle factory = callSite.dynamicInvoker().asType(MethodType.methodType(clazz.clazz));

View File

@ -25,6 +25,7 @@ import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
/** /**
@ -32,15 +33,19 @@ import java.lang.reflect.Modifier;
* and reference class + method name * and reference class + method name
*/ */
public class FunctionRef { public class FunctionRef {
// XXX: this is a mess, because of ASM versus MethodHandle types
// clean all this up, move reflection out of here into definition, etc etc
public final String invokedName; public final String invokedName;
public final Type invokedType;
public final Handle implMethod;
public final Type samMethodType;
public final Type interfaceType;
public final Type invokedType;
public final MethodType invokedMethodType;
public final Handle implMethod;
public final MethodHandle implMethodHandle; public final MethodHandle implMethodHandle;
public final Type samType;
public final MethodType samMethodType;
public final Type interfaceType;
public final MethodType interfaceMethodType;
public FunctionRef(Definition.Type expected, String type, String call) { public FunctionRef(Definition.Type expected, String type, String call) {
boolean isCtorReference = "new".equals(call); boolean isCtorReference = "new".equals(call);
@ -55,8 +60,10 @@ public class FunctionRef {
invokedName = method.name; invokedName = method.name;
// e.g. (Object)Comparator // e.g. (Object)Comparator
invokedType = Type.getMethodType(expected.type); invokedType = Type.getMethodType(expected.type);
invokedMethodType = MethodType.methodType(expected.clazz);
// e.g. (Object,Object)int // e.g. (Object,Object)int
interfaceType = Type.getMethodType(method.method.getDescriptor()); interfaceType = Type.getMethodType(method.method.getDescriptor());
interfaceMethodType = method.handle.type().dropParameterTypes(0, 1);
// lookup requested method // lookup requested method
Definition.Struct struct = Definition.getType(type).struct; Definition.Struct struct = Definition.getType(type).struct;
final Definition.Method impl; final Definition.Method impl;
@ -89,15 +96,18 @@ public class FunctionRef {
implMethod = new Handle(tag, struct.type.getInternalName(), impl.name, impl.method.getDescriptor()); implMethod = new Handle(tag, struct.type.getInternalName(), impl.name, impl.method.getDescriptor());
implMethodHandle = impl.handle; implMethodHandle = impl.handle;
if (isCtorReference) { if (isCtorReference) {
samMethodType = Type.getMethodType(interfaceType.getReturnType(), impl.method.getArgumentTypes()); samType = Type.getMethodType(interfaceType.getReturnType(), impl.method.getArgumentTypes());
samMethodType = MethodType.methodType(interfaceMethodType.returnType(), impl.handle.type().parameterArray());
} else if (Modifier.isStatic(impl.modifiers)) { } else if (Modifier.isStatic(impl.modifiers)) {
samMethodType = Type.getMethodType(impl.method.getReturnType(), impl.method.getArgumentTypes()); samType = Type.getMethodType(impl.method.getReturnType(), impl.method.getArgumentTypes());
samMethodType = impl.handle.type();
} else { } else {
Type[] argTypes = impl.method.getArgumentTypes(); Type[] argTypes = impl.method.getArgumentTypes();
Type[] params = new Type[argTypes.length + 1]; Type[] params = new Type[argTypes.length + 1];
System.arraycopy(argTypes, 0, params, 1, argTypes.length); System.arraycopy(argTypes, 0, params, 1, argTypes.length);
params[0] = struct.type; params[0] = struct.type;
samMethodType = Type.getMethodType(impl.method.getReturnType(), params); samType = Type.getMethodType(impl.method.getReturnType(), params);
samMethodType = impl.handle.type();
} }
} }
} }

View File

@ -68,12 +68,12 @@ public class EFunctionRef extends AExpression {
writer.writeDebugInfo(location); writer.writeDebugInfo(location);
// currently if the interface differs, we ask for a bridge, but maybe we should do smarter checking? // currently if the interface differs, we ask for a bridge, but maybe we should do smarter checking?
// either way, stuff will fail if its wrong :) // either way, stuff will fail if its wrong :)
if (ref.interfaceType.equals(ref.samMethodType)) { if (ref.interfaceType.equals(ref.samType)) {
writer.invokeDynamic(ref.invokedName, ref.invokedType.getDescriptor(), LAMBDA_BOOTSTRAP_HANDLE, writer.invokeDynamic(ref.invokedName, ref.invokedType.getDescriptor(), LAMBDA_BOOTSTRAP_HANDLE,
ref.samMethodType, ref.implMethod, ref.samMethodType, 0); ref.samType, ref.implMethod, ref.samType, 0);
} else { } else {
writer.invokeDynamic(ref.invokedName, ref.invokedType.getDescriptor(), LAMBDA_BOOTSTRAP_HANDLE, writer.invokeDynamic(ref.invokedName, ref.invokedType.getDescriptor(), LAMBDA_BOOTSTRAP_HANDLE,
ref.samMethodType, ref.implMethod, ref.samMethodType, ref.samType, ref.implMethod, ref.samType,
LambdaMetafactory.FLAG_BRIDGES, 1, ref.interfaceType); LambdaMetafactory.FLAG_BRIDGES, 1, ref.interfaceType);
} }
} }