Skip to content

Commit 2455e39

Browse files
committed
Painless: Clean up FunctionRef (#32644)
This change consolidates all the logic for generating a FunctionReference (renamed from FunctionRef) from several arbitrary constructors to a single static function that is used at both compile-time and run-time. This increases long-term maintainability as it is much easier to follow when and how a function reference is being generated. It moves most of the duplicated logic out of the ECapturingFuncRef, EFuncRef and ELambda nodes and Def as well.
1 parent 8373446 commit 2455e39

File tree

12 files changed

+305
-416
lines changed

12 files changed

+305
-416
lines changed

modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java

Lines changed: 27 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -279,10 +279,6 @@ static MethodHandle lookupMethod(PainlessLookup painlessLookup, Map<String, Loca
279279
String type = signature.substring(1, separator);
280280
String call = signature.substring(separator+1, separator2);
281281
int numCaptures = Integer.parseInt(signature.substring(separator2+1));
282-
Class<?> captures[] = new Class<?>[numCaptures];
283-
for (int capture = 0; capture < captures.length; capture++) {
284-
captures[capture] = callSiteType.parameterType(i + 1 + capture);
285-
}
286282
MethodHandle filter;
287283
Class<?> interfaceType = method.typeParameters.get(i - 1 - replaced);
288284
if (signature.charAt(0) == 'S') {
@@ -294,11 +290,15 @@ static MethodHandle lookupMethod(PainlessLookup painlessLookup, Map<String, Loca
294290
interfaceType,
295291
type,
296292
call,
297-
captures);
293+
numCaptures);
298294
} else if (signature.charAt(0) == 'D') {
299295
// the interface type is now known, but we need to get the implementation.
300296
// this is dynamically based on the receiver type (and cached separately, underneath
301297
// this cache). It won't blow up since we never nest here (just references)
298+
Class<?> captures[] = new Class<?>[numCaptures];
299+
for (int capture = 0; capture < captures.length; capture++) {
300+
captures[capture] = callSiteType.parameterType(i + 1 + capture);
301+
}
302302
MethodType nestedType = MethodType.methodType(interfaceType, captures);
303303
CallSite nested = DefBootstrap.bootstrap(painlessLookup,
304304
localMethods,
@@ -331,57 +331,34 @@ static MethodHandle lookupMethod(PainlessLookup painlessLookup, Map<String, Loca
331331
*/
332332
static MethodHandle lookupReference(PainlessLookup painlessLookup, Map<String, LocalMethod> localMethods,
333333
MethodHandles.Lookup methodHandlesLookup, String interfaceClass, Class<?> receiverClass, String name) throws Throwable {
334-
Class<?> interfaceType = painlessLookup.canonicalTypeNameToType(interfaceClass);
335-
PainlessMethod interfaceMethod = painlessLookup.lookupPainlessClass(interfaceType).functionalMethod;
336-
if (interfaceMethod == null) {
337-
throw new IllegalArgumentException("Class [" + interfaceClass + "] is not a functional interface");
338-
}
339-
int arity = interfaceMethod.typeParameters.size();
340-
PainlessMethod implMethod = lookupMethodInternal(painlessLookup, receiverClass, name, arity);
334+
Class<?> interfaceType = painlessLookup.canonicalTypeNameToType(interfaceClass);
335+
PainlessMethod interfaceMethod = painlessLookup.lookupFunctionalInterfacePainlessMethod(interfaceType);
336+
if (interfaceMethod == null) {
337+
throw new IllegalArgumentException("Class [" + interfaceClass + "] is not a functional interface");
338+
}
339+
int arity = interfaceMethod.typeParameters.size();
340+
PainlessMethod implMethod = lookupMethodInternal(painlessLookup, receiverClass, name, arity);
341341
return lookupReferenceInternal(painlessLookup, localMethods, methodHandlesLookup,
342342
interfaceType, PainlessLookupUtility.typeToCanonicalTypeName(implMethod.targetClass),
343-
implMethod.javaMethod.getName(), receiverClass);
343+
implMethod.javaMethod.getName(), 1);
344344
}
345345

346346
/** Returns a method handle to an implementation of clazz, given method reference signature. */
347347
private static MethodHandle lookupReferenceInternal(PainlessLookup painlessLookup, Map<String, LocalMethod> localMethods,
348-
MethodHandles.Lookup methodHandlesLookup, Class<?> clazz, String type, String call, Class<?>... captures) throws Throwable {
349-
final FunctionRef ref;
350-
if ("this".equals(type)) {
351-
// user written method
352-
PainlessMethod interfaceMethod = painlessLookup.lookupPainlessClass(clazz).functionalMethod;
353-
if (interfaceMethod == null) {
354-
throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " +
355-
"to [" + PainlessLookupUtility.typeToCanonicalTypeName(clazz) + "], not a functional interface");
356-
}
357-
int arity = interfaceMethod.typeParameters.size() + captures.length;
358-
LocalMethod localMethod = localMethods.get(Locals.buildLocalMethodKey(call, arity));
359-
if (localMethod == null) {
360-
// is it a synthetic method? If we generated the method ourselves, be more helpful. It can only fail
361-
// because the arity does not match the expected interface type.
362-
if (call.contains("$")) {
363-
throw new IllegalArgumentException("Incorrect number of parameters for [" + interfaceMethod.javaMethod.getName() +
364-
"] in [" + clazz + "]");
365-
}
366-
throw new IllegalArgumentException("Unknown call [" + call + "] with [" + arity + "] arguments.");
367-
}
368-
ref = new FunctionRef(clazz, interfaceMethod, call, localMethod.methodType, captures.length);
369-
} else {
370-
// whitelist lookup
371-
ref = FunctionRef.resolveFromLookup(painlessLookup, clazz, type, call, captures.length);
372-
}
373-
final CallSite callSite = LambdaBootstrap.lambdaBootstrap(
374-
methodHandlesLookup,
375-
ref.interfaceMethodName,
376-
ref.factoryMethodType,
377-
ref.interfaceMethodType,
378-
ref.delegateClassName,
379-
ref.delegateInvokeType,
380-
ref.delegateMethodName,
381-
ref.delegateMethodType,
382-
ref.isDelegateInterface ? 1 : 0
383-
);
384-
return callSite.dynamicInvoker().asType(MethodType.methodType(clazz, captures));
348+
MethodHandles.Lookup methodHandlesLookup, Class<?> clazz, String type, String call, int captures) throws Throwable {
349+
final FunctionRef ref = FunctionRef.create(painlessLookup, localMethods, null, clazz, type, call, captures);
350+
final CallSite callSite = LambdaBootstrap.lambdaBootstrap(
351+
methodHandlesLookup,
352+
ref.interfaceMethodName,
353+
ref.factoryMethodType,
354+
ref.interfaceMethodType,
355+
ref.delegateClassName,
356+
ref.delegateInvokeType,
357+
ref.delegateMethodName,
358+
ref.delegateMethodType,
359+
ref.isDelegateInterface ? 1 : 0
360+
);
361+
return callSite.dynamicInvoker().asType(MethodType.methodType(clazz, ref.factoryMethodType.parameterArray()));
385362
}
386363

387364
/**

0 commit comments

Comments
 (0)