Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,19 @@ static final class Loader extends SecureClassLoader {
* @param bytes The generated byte code.
* @return A Class object extending {@link PainlessScript}.
*/
Class<? extends PainlessScript> define(String name, byte[] bytes) {
Class<? extends PainlessScript> defineScript(String name, byte[] bytes) {
return defineClass(name, bytes, 0, bytes.length, CODESOURCE).asSubclass(PainlessScript.class);
}

/**
* Generates a Class object for a lambda method.
* @param name The name of the class.
* @param bytes The generated byte code.
* @return A Class object.
*/
Class<?> defineLambda(String name, byte[] bytes) {
return defineClass(name, bytes, 0, bytes.length);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not here also use CODESOURCE for safety? I know the lambda class on its own cannot do any bad stuff, but I'd still make it use the same codesource!

}
}

/**
Expand Down Expand Up @@ -110,7 +120,7 @@ static <T> T compile(Loader loader, Class<T> iface, String name, String source,
root.write();

try {
Class<? extends PainlessScript> clazz = loader.define(CLASS_NAME, root.getBytes());
Class<? extends PainlessScript> clazz = loader.defineScript(CLASS_NAME, root.getBytes());
clazz.getField("$DEFINITION").set(null, definition);
java.lang.reflect.Constructor<? extends PainlessScript> constructor =
clazz.getConstructor(String.class, String.class, BitSet.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import org.elasticsearch.painless.Definition.RuntimeClass;

import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
Expand Down Expand Up @@ -132,7 +131,7 @@ private ArrayLengthHelper() {}
} catch (final ReflectiveOperationException roe) {
throw new AssertionError(roe);
}

// lookup up the factory for arraylength MethodHandle (intrinsic) from Java 9:
// https://bugs.openjdk.java.net/browse/JDK-8156915
MethodHandle arrayLengthMHFactory;
Expand All @@ -150,7 +149,7 @@ private ArrayLengthHelper() {}
static <T extends Throwable> void rethrow(Throwable t) throws T {
throw (T) t;
}

/** Returns an array length getter MethodHandle for the given array type */
static MethodHandle arrayLengthGetter(Class<?> arrayType) {
if (JAVA9_ARRAY_LENGTH_MH_FACTORY != null) {
Expand Down Expand Up @@ -206,7 +205,7 @@ static Method lookupMethodInternal(Definition definition, Class<?> receiverClass
}
}
}

throw new IllegalArgumentException("Unable to find dynamic method [" + name + "] with [" + arity + "] arguments " +
"for class [" + receiverClass.getCanonicalName() + "].");
}
Expand Down Expand Up @@ -239,15 +238,15 @@ static MethodHandle lookupMethod(Definition definition, Lookup lookup, MethodTyp
if (recipeString.isEmpty()) {
return lookupMethodInternal(definition, receiverClass, name, numArguments - 1).handle;
}

// convert recipe string to a bitset for convenience (the code below should be refactored...)
BitSet lambdaArgs = new BitSet();
for (int i = 0; i < recipeString.length(); i++) {
lambdaArgs.set(recipeString.charAt(i));
}

// otherwise: first we have to compute the "real" arity. This is because we have extra arguments:
// e.g. f(a, g(x), b, h(y), i()) looks like f(a, g, x, b, h, y, i).
// e.g. f(a, g(x), b, h(y), i()) looks like f(a, g, x, b, h, y, i).
int arity = callSiteType.parameterCount() - 1;
int upTo = 1;
for (int i = 1; i < numArguments; i++) {
Expand All @@ -257,7 +256,7 @@ static MethodHandle lookupMethod(Definition definition, Lookup lookup, MethodTyp
arity -= numCaptures;
}
}

// lookup the method with the proper arity, then we know everything (e.g. interface types of parameters).
// based on these we can finally link any remaining lambdas that were deferred.
Method method = lookupMethodInternal(definition, receiverClass, name, arity);
Expand All @@ -268,7 +267,7 @@ static MethodHandle lookupMethod(Definition definition, Lookup lookup, MethodTyp
for (int i = 1; i < numArguments; i++) {
// its a functional reference, replace the argument with an impl
if (lambdaArgs.get(i - 1)) {
// decode signature of form 'type.call,2'
// decode signature of form 'type.call,2'
String signature = (String) args[upTo++];
int separator = signature.lastIndexOf('.');
int separator2 = signature.indexOf(',');
Expand Down Expand Up @@ -313,10 +312,10 @@ static MethodHandle lookupMethod(Definition definition, Lookup lookup, MethodTyp
replaced += numCaptures;
}
}

return handle;
}

/**
* Returns an implementation of interfaceClass that calls receiverClass.name
* <p>
Expand All @@ -335,7 +334,7 @@ static MethodHandle lookupReference(Definition definition, Lookup lookup, String
return lookupReferenceInternal(definition, lookup, interfaceType, implMethod.owner.name,
implMethod.name, receiverClass);
}

/** Returns a method handle to an implementation of clazz, given method reference signature. */
private static MethodHandle lookupReferenceInternal(Definition definition, Lookup lookup,
Definition.Type clazz, String type, String call, Class<?>... captures)
Expand All @@ -351,47 +350,37 @@ private static MethodHandle lookupReferenceInternal(Definition definition, Looku
int arity = interfaceMethod.arguments.size() + captures.length;
final MethodHandle handle;
try {
MethodHandle accessor = lookup.findStaticGetter(lookup.lookupClass(),
getUserFunctionHandleFieldName(call, arity),
MethodHandle accessor = lookup.findStaticGetter(lookup.lookupClass(),
getUserFunctionHandleFieldName(call, arity),
MethodHandle.class);
handle = (MethodHandle) accessor.invokeExact();
handle = (MethodHandle)accessor.invokeExact();
} catch (NoSuchFieldException | IllegalAccessException e) {
// is it a synthetic method? If we generated the method ourselves, be more helpful. It can only fail
// because the arity does not match the expected interface type.
if (call.contains("$")) {
throw new IllegalArgumentException("Incorrect number of parameters for [" + interfaceMethod.name +
throw new IllegalArgumentException("Incorrect number of parameters for [" + interfaceMethod.name +
"] in [" + clazz.clazz + "]");
}
throw new IllegalArgumentException("Unknown call [" + call + "] with [" + arity + "] arguments.");
}
ref = new FunctionRef(clazz, interfaceMethod, handle, captures.length);
ref = new FunctionRef(clazz, interfaceMethod, call, handle.type(), captures.length);
} else {
// whitelist lookup
ref = new FunctionRef(definition, clazz, type, call, captures.length);
}
final CallSite callSite;
if (ref.needsBridges()) {
callSite = LambdaMetafactory.altMetafactory(lookup,
ref.invokedName,
ref.invokedType,
ref.samMethodType,
ref.implMethod,
ref.samMethodType,
LambdaMetafactory.FLAG_BRIDGES,
1,
ref.interfaceMethodType);
} else {
callSite = LambdaMetafactory.altMetafactory(lookup,
ref.invokedName,
ref.invokedType,
ref.samMethodType,
ref.implMethod,
ref.samMethodType,
0);
}
final CallSite callSite = LambdaBootstrap.lambdaBootstrap(
lookup,
ref.interfaceMethodName,
ref.factoryMethodType,
ref.interfaceMethodType,
ref.delegateClassName,
ref.delegateInvokeType,
ref.delegateMethodName,
ref.delegateMethodType
);
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;
Expand Down Expand Up @@ -595,7 +584,7 @@ static MethodHandle lookupArrayLoad(Class<?> receiverClass) {
throw new IllegalArgumentException("Attempting to address a non-array type " +
"[" + receiverClass.getCanonicalName() + "] as an array.");
}

/** Helper class for isolating MethodHandles and methods to get iterators over arrays
* (to emulate "enhanced for loop" using MethodHandles). These cause boxing, and are not as efficient
* as they could be, but works.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.elasticsearch.painless;

import java.util.List;
import java.util.function.Function;

/*
Expand All @@ -25,11 +26,11 @@
public class FeatureTest {
private int x;
private int y;

/** empty ctor */
public FeatureTest() {
}

/** ctor with params */
public FeatureTest(int x, int y) {
this.x = x;
Expand Down Expand Up @@ -60,14 +61,18 @@ public void setY(int y) {
public static boolean overloadedStatic() {
return true;
}

/** static method that returns what you ask it */
public static boolean overloadedStatic(boolean whatToReturn) {
return whatToReturn;
}

/** method taking two functions! */
public Object twoFunctionsOfX(Function<Object,Object> f, Function<Object,Object> g) {
return f.apply(g.apply(x));
}

public void listInput(List<Object> list) {

}
}
Loading