Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Painless: Complete Removal of Painless Type #31699

Merged
merged 8 commits into from
Jul 3, 2018
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
6 changes: 3 additions & 3 deletions modules/lang-painless/src/main/antlr/PainlessLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@

lexer grammar PainlessLexer;

@members{
@members {
/**
* Check against the current whitelist to determine whether a token is a type
* or not. Called by the {@code TYPE} token defined in {@code PainlessLexer.g4}.
* See also
* <a href="https://en.wikipedia.org/wiki/The_lexer_hack">The lexer hack</a>.
*/
protected abstract boolean isSimpleType(String name);
protected abstract boolean isType(String name);

/**
* Is the preceding {@code /} a the beginning of a regex (true) or a division
Expand Down Expand Up @@ -133,7 +133,7 @@ NULL: 'null';
// or not. Note this works by processing one character at a time
// and the rule is added or removed as this happens. This is also known
// as "the lexer hack." See (https://en.wikipedia.org/wiki/The_lexer_hack).
TYPE: ID ( DOT ID )* { isSimpleType(getText()) }?;
TYPE: ID ( DOT ID )* { isType(getText()) }?;
ID: [_a-zA-Z] [_a-zA-Z0-9]*;

mode AFTER_DOT;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ static Method lookupMethodInternal(Definition definition, Class<?> receiverClass
Definition.MethodKey key = new Definition.MethodKey(name, arity);
// check whitelist for matching method
for (Class<?> clazz = receiverClass; clazz != null; clazz = clazz.getSuperclass()) {
Struct struct = definition.RuntimeClassToStruct(clazz);
Struct struct = definition.getPainlessStructFromJavaClass(clazz);

if (struct != null) {
Method method = struct.methods.get(key);
Expand All @@ -195,7 +195,7 @@ static Method lookupMethodInternal(Definition definition, Class<?> receiverClass
}

for (Class<?> iface : clazz.getInterfaces()) {
struct = definition.RuntimeClassToStruct(iface);
struct = definition.getPainlessStructFromJavaClass(iface);

if (struct != null) {
Method method = struct.methods.get(key);
Expand Down Expand Up @@ -279,7 +279,7 @@ static MethodHandle lookupMethod(Definition definition, Lookup lookup, MethodTyp
captures[capture] = callSiteType.parameterType(i + 1 + capture);
}
MethodHandle filter;
Definition.Type interfaceType = definition.ClassToType(method.arguments.get(i - 1 - replaced));
Class<?> interfaceType = method.arguments.get(i - 1 - replaced);
if (signature.charAt(0) == 'S') {
// the implementation is strongly typed, now that we know the interface type,
// we have everything.
Expand All @@ -293,14 +293,14 @@ static MethodHandle lookupMethod(Definition definition, Lookup lookup, MethodTyp
// the interface type is now known, but we need to get the implementation.
// this is dynamically based on the receiver type (and cached separately, underneath
// this cache). It won't blow up since we never nest here (just references)
MethodType nestedType = MethodType.methodType(interfaceType.clazz, captures);
MethodType nestedType = MethodType.methodType(interfaceType, captures);
CallSite nested = DefBootstrap.bootstrap(definition,
lookup,
call,
nestedType,
0,
DefBootstrap.REFERENCE,
interfaceType.name);
Definition.ClassToName(interfaceType));
filter = nested.dynamicInvoker();
} else {
throw new AssertionError();
Expand All @@ -324,8 +324,8 @@ static MethodHandle lookupMethod(Definition definition, Lookup lookup, MethodTyp
*/
static MethodHandle lookupReference(Definition definition, Lookup lookup, String interfaceClass,
Class<?> receiverClass, String name) throws Throwable {
Definition.Type interfaceType = definition.getType(interfaceClass);
Method interfaceMethod = interfaceType.struct.functionalMethod;
Class<?> interfaceType = definition.getJavaClassFromPainlessType(interfaceClass);
Method interfaceMethod = definition.getPainlessStructFromJavaClass(interfaceType).functionalMethod;
if (interfaceMethod == null) {
throw new IllegalArgumentException("Class [" + interfaceClass + "] is not a functional interface");
}
Expand All @@ -337,15 +337,15 @@ static MethodHandle lookupReference(Definition definition, Lookup lookup, String

/** 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)
Class<?> clazz, String type, String call, Class<?>... captures)
throws Throwable {
final FunctionRef ref;
if ("this".equals(type)) {
// user written method
Method interfaceMethod = clazz.struct.functionalMethod;
Method interfaceMethod = definition.getPainlessStructFromJavaClass(clazz).functionalMethod;
if (interfaceMethod == null) {
throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " +
"to [" + clazz.name + "], not a functional interface");
"to [" + Definition.ClassToName(clazz) + "], not a functional interface");
}
int arity = interfaceMethod.arguments.size() + captures.length;
final MethodHandle handle;
Expand All @@ -359,14 +359,14 @@ private static MethodHandle lookupReferenceInternal(Definition definition, Looku
// because the arity does not match the expected interface type.
if (call.contains("$")) {
throw new IllegalArgumentException("Incorrect number of parameters for [" + interfaceMethod.name +
"] in [" + clazz.clazz + "]");
"] in [" + clazz + "]");
}
throw new IllegalArgumentException("Unknown call [" + call + "] with [" + arity + "] arguments.");
}
ref = new FunctionRef(clazz.clazz, interfaceMethod, call, handle.type(), captures.length);
ref = new FunctionRef(clazz, interfaceMethod, call, handle.type(), captures.length);
} else {
// whitelist lookup
ref = new FunctionRef(definition, clazz.clazz, type, call, captures.length);
ref = new FunctionRef(definition, clazz, type, call, captures.length);
}
final CallSite callSite = LambdaBootstrap.lambdaBootstrap(
lookup,
Expand All @@ -379,7 +379,7 @@ private static MethodHandle lookupReferenceInternal(Definition definition, Looku
ref.delegateMethodType,
ref.isDelegateInterface ? 1 : 0
);
return callSite.dynamicInvoker().asType(MethodType.methodType(clazz.clazz, captures));
return callSite.dynamicInvoker().asType(MethodType.methodType(clazz, captures));
}

/** gets the field name used to lookup up the MethodHandle for a function. */
Expand Down Expand Up @@ -416,7 +416,7 @@ public static String getUserFunctionHandleFieldName(String name, int arity) {
static MethodHandle lookupGetter(Definition definition, Class<?> receiverClass, String name) {
// first try whitelist
for (Class<?> clazz = receiverClass; clazz != null; clazz = clazz.getSuperclass()) {
Struct struct = definition.RuntimeClassToStruct(clazz);
Struct struct = definition.getPainlessStructFromJavaClass(clazz);

if (struct != null) {
MethodHandle handle = struct.getters.get(name);
Expand All @@ -426,7 +426,7 @@ static MethodHandle lookupGetter(Definition definition, Class<?> receiverClass,
}

for (final Class<?> iface : clazz.getInterfaces()) {
struct = definition.RuntimeClassToStruct(iface);
struct = definition.getPainlessStructFromJavaClass(iface);

if (struct != null) {
MethodHandle handle = struct.getters.get(name);
Expand Down Expand Up @@ -487,7 +487,7 @@ static MethodHandle lookupGetter(Definition definition, Class<?> receiverClass,
static MethodHandle lookupSetter(Definition definition, Class<?> receiverClass, String name) {
// first try whitelist
for (Class<?> clazz = receiverClass; clazz != null; clazz = clazz.getSuperclass()) {
Struct struct = definition.RuntimeClassToStruct(clazz);
Struct struct = definition.getPainlessStructFromJavaClass(clazz);

if (struct != null) {
MethodHandle handle = struct.setters.get(name);
Expand All @@ -497,7 +497,7 @@ static MethodHandle lookupSetter(Definition definition, Class<?> receiverClass,
}

for (final Class<?> iface : clazz.getInterfaces()) {
struct = definition.RuntimeClassToStruct(iface);
struct = definition.getPainlessStructFromJavaClass(iface);

if (struct != null) {
MethodHandle handle = struct.setters.get(name);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
package org.elasticsearch.painless;

import org.elasticsearch.common.SuppressForbidden;

/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
Expand All @@ -21,6 +17,10 @@
* under the License.
*/

package org.elasticsearch.painless;

import org.elasticsearch.common.SuppressForbidden;

import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
Expand Down Expand Up @@ -72,24 +72,24 @@ private DefBootstrap() {} // no instance!
public static final int SHIFT_OPERATOR = 9;
/** static bootstrap parameter indicating a request to normalize an index for array-like-access */
public static final int INDEX_NORMALIZE = 10;

// constants for the flags parameter of operators
/**
* static bootstrap parameter indicating the binary operator allows nulls (e.g. == and +)
/**
* static bootstrap parameter indicating the binary operator allows nulls (e.g. == and +)
* <p>
* requires additional {@link MethodHandles#catchException} guard, which will invoke
* the fallback if a null is encountered.
*/
public static final int OPERATOR_ALLOWS_NULL = 1 << 0;

/**
* static bootstrap parameter indicating the binary operator is part of compound assignment (e.g. +=).
* <p>
* may require {@link MethodHandles#explicitCastArguments}, or a dynamic cast
* to cast back to the receiver's type, depending on types seen.
*/
public static final int OPERATOR_COMPOUND_ASSIGNMENT = 1 << 1;

/**
* static bootstrap parameter indicating an explicit cast to the return type.
* <p>
Expand Down Expand Up @@ -129,7 +129,7 @@ static final class PIC extends MutableCallSite {

setTarget(fallback);
}

/**
* guard method for inline caching: checks the receiver's class is the same
* as the cached class
Expand Down Expand Up @@ -162,7 +162,7 @@ private MethodHandle lookup(int flavor, String name, Class<?> receiver) throws T
default: throw new AssertionError();
}
}

/**
* Creates the {@link MethodHandle} for the megamorphic call site
* using {@link ClassValue} and {@link MethodHandles#exactInvoker(MethodType)}:
Expand All @@ -182,7 +182,7 @@ protected MethodHandle computeValue(Class<?> receiverType) {
}
};
return MethodHandles.foldArguments(MethodHandles.exactInvoker(type),
MEGAMORPHIC_LOOKUP.bindTo(megamorphicCache));
MEGAMORPHIC_LOOKUP.bindTo(megamorphicCache));
}

/**
Expand All @@ -195,18 +195,18 @@ Object fallback(final Object[] callArgs) throws Throwable {
if (depth >= MAX_DEPTH) {
// we revert the whole cache and build a new megamorphic one
final MethodHandle target = this.createMegamorphicHandle();

setTarget(target);
return target.invokeWithArguments(callArgs);
return target.invokeWithArguments(callArgs);
} else {
final Class<?> receiver = callArgs[0].getClass();
final MethodHandle target = lookup(flavor, name, receiver).asType(type());

MethodHandle test = CHECK_CLASS.bindTo(receiver);
MethodHandle guard = MethodHandles.guardWithTest(test, target, getTarget());

depth++;

setTarget(guard);
return target.invokeWithArguments(callArgs);
}
Expand All @@ -225,15 +225,15 @@ Object fallback(final Object[] callArgs) throws Throwable {
MethodType.methodType(Object.class, Object[].class));
MethodHandle mh = publicLookup.findVirtual(ClassValue.class, "get",
MethodType.methodType(Object.class, Class.class));
mh = MethodHandles.filterArguments(mh, 1,
mh = MethodHandles.filterArguments(mh, 1,
publicLookup.findVirtual(Object.class, "getClass", MethodType.methodType(Class.class)));
MEGAMORPHIC_LOOKUP = mh.asType(mh.type().changeReturnType(MethodHandle.class));
} catch (ReflectiveOperationException e) {
throw new AssertionError(e);
}
}
}

/**
* CallSite that implements the monomorphic inlining cache (for operators).
*/
Expand All @@ -252,14 +252,14 @@ static final class MIC extends MutableCallSite {
if (initialDepth > 0) {
initialized = true;
}

MethodHandle fallback = FALLBACK.bindTo(this)
.asCollector(Object[].class, type.parameterCount())
.asType(type);

setTarget(fallback);
}

/**
* Does a slow lookup for the operator
*/
Expand Down Expand Up @@ -290,7 +290,7 @@ private MethodHandle lookup(Object[] args) throws Throwable {
default: throw new AssertionError();
}
}

private MethodHandle lookupGeneric() {
MethodHandle target = DefMath.lookupGeneric(name);
if ((flags & OPERATOR_EXPLICIT_CAST) != 0) {
Expand All @@ -302,7 +302,7 @@ private MethodHandle lookupGeneric() {
}
return target;
}

/**
* Called when a new type is encountered or if cached type does not match.
* In that case we revert to a generic, but slower operator handling.
Expand All @@ -315,7 +315,7 @@ Object fallback(Object[] args) throws Throwable {
setTarget(generic.asType(type()));
return generic.invokeWithArguments(args);
}

final MethodType type = type();
MethodHandle target = lookup(args);
// for math operators: WrongMethodType can be confusing. convert into a ClassCastException if they screw up.
Expand Down Expand Up @@ -361,18 +361,18 @@ Object fallback(Object[] args) throws Throwable {
// very special cases, where even the receiver can be null (see JLS rules for string concat)
// we wrap + with an NPE catcher, and use our generic method in that case.
if (flavor == BINARY_OPERATOR && (flags & OPERATOR_ALLOWS_NULL) != 0) {
MethodHandle handler = MethodHandles.dropArguments(lookupGeneric().asType(type()),
0,
MethodHandle handler = MethodHandles.dropArguments(lookupGeneric().asType(type()),
0,
NullPointerException.class);
guard = MethodHandles.catchException(guard, NullPointerException.class, handler);
}

initialized = true;

setTarget(guard);
return target.invokeWithArguments(args);
}

/**
* guard method for inline caching: checks the receiver's class is the same
* as the cached class
Expand All @@ -388,15 +388,15 @@ static boolean checkLHS(Class<?> clazz, Object leftObject) {
static boolean checkRHS(Class<?> left, Class<?> right, Object leftObject, Object rightObject) {
return rightObject.getClass() == right;
}

/**
* guard method for inline caching: checks the receiver's class and the first argument
* are the same as the cached receiver and first argument.
*/
static boolean checkBoth(Class<?> left, Class<?> right, Object leftObject, Object rightObject) {
return leftObject.getClass() == left && rightObject.getClass() == right;
}

private static final MethodHandle CHECK_LHS;
private static final MethodHandle CHECK_RHS;
private static final MethodHandle CHECK_BOTH;
Expand Down
Loading