diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java index c18b724c350..48775a88a20 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java @@ -23,7 +23,6 @@ import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.RuntimeClass; import java.lang.invoke.CallSite; -import java.lang.invoke.LambdaConversionException; import java.lang.invoke.LambdaMetafactory; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -219,11 +218,11 @@ public final class Def { * @param args args passed to callsite * @param recipe bitset marking functional parameters * @return pointer to matching method to invoke. never returns null. - * @throws LambdaConversionException if a method reference cannot be converted to an functional interface * @throws IllegalArgumentException if no matching whitelisted method was found. + * @throws Throwable if a method reference cannot be converted to an functional interface */ static MethodHandle lookupMethod(Lookup lookup, MethodType callSiteType, - Class receiverClass, String name, Object args[], long recipe) throws LambdaConversionException { + Class receiverClass, String name, Object args[], long recipe) throws Throwable { // simple case: no lambdas if (recipe == 0) { return lookupMethodInternal(receiverClass, name, args.length - 1).handle; @@ -302,7 +301,7 @@ public final class Def { * so we simply need to lookup the matching implementation method based on receiver type. */ static MethodHandle lookupReference(Lookup lookup, String interfaceClass, - Class receiverClass, String name) throws LambdaConversionException { + Class receiverClass, String name) throws Throwable { Definition.Type interfaceType = Definition.getType(interfaceClass); Method interfaceMethod = interfaceType.struct.getFunctionalMethod(); if (interfaceMethod == null) { @@ -313,11 +312,9 @@ public final class Def { return lookupReferenceInternal(lookup, interfaceType, implMethod.owner.name, implMethod.name, receiverClass); } - /** 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 - */ + /** Returns a method handle to an implementation of clazz, given method reference signature. */ private static MethodHandle lookupReferenceInternal(Lookup lookup, Definition.Type clazz, String type, - String call, Class... captures) throws LambdaConversionException { + String call, Class... captures) throws Throwable { final FunctionRef ref; if ("this".equals(type)) { // user written method @@ -330,14 +327,11 @@ public final class Def { final MethodHandle handle; try { MethodHandle accessor = lookup.findStaticGetter(lookup.lookupClass(), - "handle$" + call + "$" + arity, + getUserFunctionHandleFieldName(call, arity), MethodHandle.class); handle = (MethodHandle) accessor.invokeExact(); } catch (NoSuchFieldException | IllegalAccessException e) { throw new IllegalArgumentException("Unknown call [" + call + "] with [" + arity + "] arguments."); - } catch (Throwable t) { - rethrow(t); - throw new AssertionError(); } ref = new FunctionRef(clazz, interfaceMethod, handle, captures); } else { @@ -367,6 +361,10 @@ public final class Def { return callSite.dynamicInvoker().asType(MethodType.methodType(clazz.clazz, captures)); } + /** gets the field name used to lookup up the MethodHandle for a function. */ + public static String getUserFunctionHandleFieldName(String name, int arity) { + return "handle$" + name + "$" + arity; + } /** * Looks up handle for a dynamic field getter (field load) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java index bb7ebd690ed..038096da99e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java @@ -28,6 +28,7 @@ import org.objectweb.asm.commons.Method; import java.lang.invoke.CallSite; import java.lang.invoke.LambdaMetafactory; +import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.BitSet; @@ -66,6 +67,8 @@ public final class WriterConstants { public final static Type UTILITY_TYPE = Type.getType(Utility.class); public final static Method STRING_TO_CHAR = getAsmMethod(char.class, "StringTochar", String.class); public final static Method CHAR_TO_STRING = getAsmMethod(String.class, "charToString", char.class); + + public final static Type METHOD_HANDLE_TYPE = Type.getType(MethodHandle.class); /** dynamic callsite bootstrap signature */ public final static MethodType DEF_BOOTSTRAP_TYPE = diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java index 4884e73ddce..a422e3b9d3d 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFunction.java @@ -19,6 +19,7 @@ package org.elasticsearch.painless.node; +import org.elasticsearch.painless.Def; import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Sort; @@ -167,7 +168,7 @@ public class SFunction extends AStatement { } } - String getHandleStaticFieldName() { - return "handle$" + name + "$" + parameters.size(); + String getStaticHandleFieldName() { + return Def.getUserFunctionHandleFieldName(name, parameters.size()); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java index 63fe3f5c377..07b5871f928 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java @@ -26,14 +26,13 @@ import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.ExecuteReserved; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.WriterConstants; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Handle; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; -import java.lang.invoke.MethodHandle; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Opcodes; + import java.util.BitSet; import java.util.Collections; import java.util.HashMap; @@ -139,7 +138,6 @@ public final class SSource extends AStatement { expressions = new BitSet(source.length()); // Write the constructor: - MethodWriter constructor = new MethodWriter(Opcodes.ACC_PUBLIC, CONSTRUCTOR, writer, expressions); constructor.loadThis(); constructor.loadArgs(); @@ -148,7 +146,6 @@ public final class SSource extends AStatement { constructor.endMethod(); // Write the execute method: - MethodWriter execute = new MethodWriter(Opcodes.ACC_PUBLIC, EXECUTE, writer, expressions); write(execute); execute.endMethod(); @@ -162,8 +159,8 @@ public final class SSource extends AStatement { if (!functions.isEmpty()) { for (SFunction function : functions) { writer.visitField(Opcodes.ACC_FINAL | Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, - function.getHandleStaticFieldName(), - Type.getDescriptor(MethodHandle.class), + function.getStaticHandleFieldName(), + WriterConstants.METHOD_HANDLE_TYPE.getDescriptor(), null, null).visitEnd(); } @@ -177,8 +174,8 @@ public final class SSource extends AStatement { false); clinit.push(handle); clinit.putStatic(CLASS_TYPE, - function.getHandleStaticFieldName(), - Type.getType(MethodHandle.class)); + function.getStaticHandleFieldName(), + WriterConstants.METHOD_HANDLE_TYPE); } clinit.returnValue(); clinit.endMethod();