use painless types in FunctionRef

This commit is contained in:
Robert Muir 2016-06-07 09:49:54 -04:00
parent 39550354a7
commit 3108c399f0
3 changed files with 17 additions and 40 deletions

View File

@ -230,7 +230,7 @@ public final class Def {
for (int i = 0; i < args.length; i++) {
// its a functional reference, replace the argument with an impl
if ((recipe & (1L << (i - 1))) != 0) {
filters[i] = lookupReference(lookup, method.arguments.get(i - 1).clazz, (String) args[i]);
filters[i] = lookupReference(lookup, method.arguments.get(i - 1), (String) args[i]);
}
}
handle = MethodHandles.filterArguments(handle, 0, filters);
@ -242,7 +242,7 @@ public final class Def {
/** Returns a method handle to an implementation of clazz, given method reference signature
* @throws LambdaConversionException if a method reference cannot be converted to an functional interface
*/
private static MethodHandle lookupReference(Lookup lookup, Class<?> clazz, String signature) throws LambdaConversionException {
private static MethodHandle lookupReference(Lookup lookup, Definition.Type clazz, String signature) throws LambdaConversionException {
int separator = signature.indexOf('.');
FunctionRef ref = new FunctionRef(clazz, signature.substring(0, separator), signature.substring(separator+1));
final CallSite callSite;
@ -270,7 +270,7 @@ public final class Def {
interfaceType);
}
// 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));
MethodHandle factory = callSite.dynamicInvoker().asType(MethodType.methodType(clazz.clazz));
return MethodHandles.dropArguments(factory, 0, Object.class);
}

View File

@ -19,14 +19,13 @@
package org.elasticsearch.painless;
import org.elasticsearch.painless.Definition.Method;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.Set;
/**
* computes "everything you need" to call LambdaMetaFactory, given an expected interface,
@ -43,29 +42,33 @@ public class FunctionRef {
public final MethodHandle implMethodHandle;
public FunctionRef(Class<?> expected, String type, String call) {
public FunctionRef(Definition.Type expected, String type, String call) {
boolean isCtorReference = "new".equals(call);
// check its really a functional interface
// for e.g. Comparable
java.lang.reflect.Method method = getFunctionalMethod(type, call, expected);
Method method = expected.struct.getFunctionalMethod();
if (method == null) {
throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " +
"to [" + expected.name + "], not a functional interface");
}
// e.g. compareTo
invokedName = method.getName();
invokedName = method.name;
// e.g. (Object)Comparator
invokedType = Type.getMethodType(Type.getType(expected));
invokedType = Type.getMethodType(expected.type);
// e.g. (Object,Object)int
interfaceType = Type.getMethodType(Type.getMethodDescriptor(method));
interfaceType = Type.getMethodType(method.method.getDescriptor());
// lookup requested method
Definition.Struct struct = Definition.getType(type).struct;
final Definition.Method impl;
// ctor ref
if (isCtorReference) {
impl = struct.constructors.get(new Definition.MethodKey("<init>", method.getParameterCount()));
impl = struct.constructors.get(new Definition.MethodKey("<init>", method.arguments.size()));
} else {
// look for a static impl first
Definition.Method staticImpl = struct.staticMethods.get(new Definition.MethodKey(call, method.getParameterCount()));
Definition.Method staticImpl = struct.staticMethods.get(new Definition.MethodKey(call, method.arguments.size()));
if (staticImpl == null) {
// otherwise a virtual impl
impl = struct.methods.get(new Definition.MethodKey(call, method.getParameterCount()-1));
impl = struct.methods.get(new Definition.MethodKey(call, method.arguments.size()-1));
} else {
impl = staticImpl;
}
@ -97,30 +100,4 @@ public class FunctionRef {
samMethodType = Type.getMethodType(impl.method.getReturnType(), params);
}
}
static final Set<Definition.MethodKey> OBJECT_METHODS = new HashSet<>();
static {
for (java.lang.reflect.Method m : Object.class.getMethods()) {
OBJECT_METHODS.add(new Definition.MethodKey(m.getName(), m.getParameterCount()));
}
}
// TODO: move all this crap out, to Definition to compute up front
java.lang.reflect.Method getFunctionalMethod(String type, String call, Class<?> clazz) {
if (!clazz.isInterface()) {
throw new IllegalArgumentException("Cannot convert function reference ["
+ type + "::" + call + "] to [" + clazz + "]");
}
for (java.lang.reflect.Method m : clazz.getMethods()) {
if (m.isDefault()) {
continue;
}
if (OBJECT_METHODS.contains(new Definition.MethodKey(m.getName(), m.getParameterCount()))) {
continue;
}
return m;
}
throw new IllegalArgumentException("Cannot convert function reference ["
+ type + "::" + call + "] to [" + clazz + "]");
}
}

View File

@ -52,7 +52,7 @@ public class EFunctionRef extends AExpression {
actual = Definition.getType("String");
} else {
try {
ref = new FunctionRef(expected.clazz, type, call);
ref = new FunctionRef(expected, type, call);
} catch (IllegalArgumentException e) {
throw createError(e);
}