Remove some hardcoded strings, fix exception handling (remove rethrow), add some utility methods around the "handle$" fields

This commit is contained in:
Uwe Schindler 2016-06-11 21:53:15 +02:00
parent 454881eeb4
commit fd9b0f9087
4 changed files with 24 additions and 25 deletions

View File

@ -23,7 +23,6 @@ import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.RuntimeClass; import org.elasticsearch.painless.Definition.RuntimeClass;
import java.lang.invoke.CallSite; import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaConversionException;
import java.lang.invoke.LambdaMetafactory; import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
@ -219,11 +218,11 @@ public final class Def {
* @param args args passed to callsite * @param args args passed to callsite
* @param recipe bitset marking functional parameters * @param recipe bitset marking functional parameters
* @return pointer to matching method to invoke. never returns null. * @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 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, 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 // simple case: no lambdas
if (recipe == 0) { if (recipe == 0) {
return lookupMethodInternal(receiverClass, name, args.length - 1).handle; 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. * so we simply need to lookup the matching implementation method based on receiver type.
*/ */
static MethodHandle lookupReference(Lookup lookup, String interfaceClass, 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); Definition.Type interfaceType = Definition.getType(interfaceClass);
Method interfaceMethod = interfaceType.struct.getFunctionalMethod(); Method interfaceMethod = interfaceType.struct.getFunctionalMethod();
if (interfaceMethod == null) { if (interfaceMethod == null) {
@ -313,11 +312,9 @@ public final class Def {
return lookupReferenceInternal(lookup, interfaceType, implMethod.owner.name, implMethod.name, receiverClass); return lookupReferenceInternal(lookup, interfaceType, implMethod.owner.name, implMethod.name, receiverClass);
} }
/** Returns a method handle to an implementation of clazz, given method reference signature /** 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 lookupReferenceInternal(Lookup lookup, Definition.Type clazz, String type, 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; final FunctionRef ref;
if ("this".equals(type)) { if ("this".equals(type)) {
// user written method // user written method
@ -330,14 +327,11 @@ public final class Def {
final MethodHandle handle; final MethodHandle handle;
try { try {
MethodHandle accessor = lookup.findStaticGetter(lookup.lookupClass(), MethodHandle accessor = lookup.findStaticGetter(lookup.lookupClass(),
"handle$" + call + "$" + arity, getUserFunctionHandleFieldName(call, arity),
MethodHandle.class); MethodHandle.class);
handle = (MethodHandle) accessor.invokeExact(); handle = (MethodHandle) accessor.invokeExact();
} catch (NoSuchFieldException | IllegalAccessException e) { } catch (NoSuchFieldException | IllegalAccessException e) {
throw new IllegalArgumentException("Unknown call [" + call + "] with [" + arity + "] arguments."); throw new IllegalArgumentException("Unknown call [" + call + "] with [" + arity + "] arguments.");
} catch (Throwable t) {
rethrow(t);
throw new AssertionError();
} }
ref = new FunctionRef(clazz, interfaceMethod, handle, captures); ref = new FunctionRef(clazz, interfaceMethod, handle, captures);
} else { } else {
@ -367,6 +361,10 @@ public final class Def {
return callSite.dynamicInvoker().asType(MethodType.methodType(clazz.clazz, captures)); 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) * Looks up handle for a dynamic field getter (field load)

View File

@ -28,6 +28,7 @@ import org.objectweb.asm.commons.Method;
import java.lang.invoke.CallSite; import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory; import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.util.BitSet; 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 Type UTILITY_TYPE = Type.getType(Utility.class);
public final static Method STRING_TO_CHAR = getAsmMethod(char.class, "StringTochar", String.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 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 */ /** dynamic callsite bootstrap signature */
public final static MethodType DEF_BOOTSTRAP_TYPE = public final static MethodType DEF_BOOTSTRAP_TYPE =

View File

@ -19,6 +19,7 @@
package org.elasticsearch.painless.node; package org.elasticsearch.painless.node;
import org.elasticsearch.painless.Def;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.Sort; import org.elasticsearch.painless.Definition.Sort;
@ -167,7 +168,7 @@ public class SFunction extends AStatement {
} }
} }
String getHandleStaticFieldName() { String getStaticHandleFieldName() {
return "handle$" + name + "$" + parameters.size(); return Def.getUserFunctionHandleFieldName(name, parameters.size());
} }
} }

View File

@ -26,14 +26,13 @@ import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Locals.ExecuteReserved; import org.elasticsearch.painless.Locals.ExecuteReserved;
import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Locals.Variable;
import org.elasticsearch.painless.WriterConstants; 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.Location;
import org.elasticsearch.painless.MethodWriter; 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.BitSet;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -139,7 +138,6 @@ public final class SSource extends AStatement {
expressions = new BitSet(source.length()); expressions = new BitSet(source.length());
// Write the constructor: // Write the constructor:
MethodWriter constructor = new MethodWriter(Opcodes.ACC_PUBLIC, CONSTRUCTOR, writer, expressions); MethodWriter constructor = new MethodWriter(Opcodes.ACC_PUBLIC, CONSTRUCTOR, writer, expressions);
constructor.loadThis(); constructor.loadThis();
constructor.loadArgs(); constructor.loadArgs();
@ -148,7 +146,6 @@ public final class SSource extends AStatement {
constructor.endMethod(); constructor.endMethod();
// Write the execute method: // Write the execute method:
MethodWriter execute = new MethodWriter(Opcodes.ACC_PUBLIC, EXECUTE, writer, expressions); MethodWriter execute = new MethodWriter(Opcodes.ACC_PUBLIC, EXECUTE, writer, expressions);
write(execute); write(execute);
execute.endMethod(); execute.endMethod();
@ -162,8 +159,8 @@ public final class SSource extends AStatement {
if (!functions.isEmpty()) { if (!functions.isEmpty()) {
for (SFunction function : functions) { for (SFunction function : functions) {
writer.visitField(Opcodes.ACC_FINAL | Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, writer.visitField(Opcodes.ACC_FINAL | Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC,
function.getHandleStaticFieldName(), function.getStaticHandleFieldName(),
Type.getDescriptor(MethodHandle.class), WriterConstants.METHOD_HANDLE_TYPE.getDescriptor(),
null, null,
null).visitEnd(); null).visitEnd();
} }
@ -177,8 +174,8 @@ public final class SSource extends AStatement {
false); false);
clinit.push(handle); clinit.push(handle);
clinit.putStatic(CLASS_TYPE, clinit.putStatic(CLASS_TYPE,
function.getHandleStaticFieldName(), function.getStaticHandleFieldName(),
Type.getType(MethodHandle.class)); WriterConstants.METHOD_HANDLE_TYPE);
} }
clinit.returnValue(); clinit.returnValue();
clinit.endMethod(); clinit.endMethod();