19
19
20
20
package org .elasticsearch .painless ;
21
21
22
+ import org .elasticsearch .painless .Locals .LocalMethod ;
22
23
import org .elasticsearch .painless .lookup .PainlessClass ;
23
24
import org .elasticsearch .painless .lookup .PainlessLookup ;
24
25
import org .elasticsearch .painless .lookup .PainlessLookupUtility ;
@@ -232,8 +233,10 @@ static PainlessMethod lookupMethodInternal(PainlessLookup painlessLookup, Class<
232
233
* @throws IllegalArgumentException if no matching whitelisted method was found.
233
234
* @throws Throwable if a method reference cannot be converted to an functional interface
234
235
*/
235
- static MethodHandle lookupMethod (PainlessLookup painlessLookup , MethodHandles .Lookup methodHandlesLookup , MethodType callSiteType ,
236
- Class <?> receiverClass , String name , Object args []) throws Throwable {
236
+ static MethodHandle lookupMethod (PainlessLookup painlessLookup , Map <String , LocalMethod > localMethods ,
237
+ MethodHandles .Lookup methodHandlesLookup , MethodType callSiteType , Class <?> receiverClass , String name , Object args [])
238
+ throws Throwable {
239
+
237
240
String recipeString = (String ) args [0 ];
238
241
int numArguments = callSiteType .parameterCount ();
239
242
// simple case: no lambdas
@@ -286,6 +289,7 @@ static MethodHandle lookupMethod(PainlessLookup painlessLookup, MethodHandles.Lo
286
289
// the implementation is strongly typed, now that we know the interface type,
287
290
// we have everything.
288
291
filter = lookupReferenceInternal (painlessLookup ,
292
+ localMethods ,
289
293
methodHandlesLookup ,
290
294
interfaceType ,
291
295
type ,
@@ -297,6 +301,7 @@ static MethodHandle lookupMethod(PainlessLookup painlessLookup, MethodHandles.Lo
297
301
// this cache). It won't blow up since we never nest here (just references)
298
302
MethodType nestedType = MethodType .methodType (interfaceType , captures );
299
303
CallSite nested = DefBootstrap .bootstrap (painlessLookup ,
304
+ localMethods ,
300
305
methodHandlesLookup ,
301
306
call ,
302
307
nestedType ,
@@ -324,24 +329,23 @@ static MethodHandle lookupMethod(PainlessLookup painlessLookup, MethodHandles.Lo
324
329
* This is just like LambdaMetaFactory, only with a dynamic type. The interface type is known,
325
330
* so we simply need to lookup the matching implementation method based on receiver type.
326
331
*/
327
- static MethodHandle lookupReference (PainlessLookup painlessLookup , MethodHandles . Lookup methodHandlesLookup , String interfaceClass ,
328
- Class <?> receiverClass , String name ) throws Throwable {
332
+ static MethodHandle lookupReference (PainlessLookup painlessLookup , Map < String , LocalMethod > localMethods ,
333
+ MethodHandles . Lookup methodHandlesLookup , String interfaceClass , Class <?> receiverClass , String name ) throws Throwable {
329
334
Class <?> interfaceType = painlessLookup .canonicalTypeNameToType (interfaceClass );
330
335
PainlessMethod interfaceMethod = painlessLookup .lookupPainlessClass (interfaceType ).functionalMethod ;
331
336
if (interfaceMethod == null ) {
332
337
throw new IllegalArgumentException ("Class [" + interfaceClass + "] is not a functional interface" );
333
338
}
334
339
int arity = interfaceMethod .typeParameters .size ();
335
340
PainlessMethod implMethod = lookupMethodInternal (painlessLookup , receiverClass , name , arity );
336
- return lookupReferenceInternal (painlessLookup , methodHandlesLookup , interfaceType ,
337
- PainlessLookupUtility .typeToCanonicalTypeName (implMethod .targetClass ),
341
+ return lookupReferenceInternal (painlessLookup , localMethods , methodHandlesLookup ,
342
+ interfaceType , PainlessLookupUtility .typeToCanonicalTypeName (implMethod .targetClass ),
338
343
implMethod .javaMethod .getName (), receiverClass );
339
344
}
340
345
341
346
/** Returns a method handle to an implementation of clazz, given method reference signature. */
342
- private static MethodHandle lookupReferenceInternal (PainlessLookup painlessLookup , MethodHandles .Lookup methodHandlesLookup ,
343
- Class <?> clazz , String type , String call , Class <?>... captures )
344
- throws Throwable {
347
+ private static MethodHandle lookupReferenceInternal (PainlessLookup painlessLookup , Map <String , LocalMethod > localMethods ,
348
+ MethodHandles .Lookup methodHandlesLookup , Class <?> clazz , String type , String call , Class <?>... captures ) throws Throwable {
345
349
final FunctionRef ref ;
346
350
if ("this" .equals (type )) {
347
351
// user written method
@@ -351,13 +355,8 @@ private static MethodHandle lookupReferenceInternal(PainlessLookup painlessLooku
351
355
"to [" + PainlessLookupUtility .typeToCanonicalTypeName (clazz ) + "], not a functional interface" );
352
356
}
353
357
int arity = interfaceMethod .typeParameters .size () + captures .length ;
354
- final MethodHandle handle ;
355
- try {
356
- MethodHandle accessor = methodHandlesLookup .findStaticGetter (methodHandlesLookup .lookupClass (),
357
- getUserFunctionHandleFieldName (call , arity ),
358
- MethodHandle .class );
359
- handle = (MethodHandle )accessor .invokeExact ();
360
- } catch (NoSuchFieldException | IllegalAccessException e ) {
358
+ LocalMethod localMethod = localMethods .get (Locals .buildLocalMethodKey (call , arity ));
359
+ if (localMethod == null ) {
361
360
// is it a synthetic method? If we generated the method ourselves, be more helpful. It can only fail
362
361
// because the arity does not match the expected interface type.
363
362
if (call .contains ("$" )) {
@@ -366,7 +365,7 @@ private static MethodHandle lookupReferenceInternal(PainlessLookup painlessLooku
366
365
}
367
366
throw new IllegalArgumentException ("Unknown call [" + call + "] with [" + arity + "] arguments." );
368
367
}
369
- ref = new FunctionRef (clazz , interfaceMethod , call , handle . type () , captures .length );
368
+ ref = new FunctionRef (clazz , interfaceMethod , call , localMethod . methodType , captures .length );
370
369
} else {
371
370
// whitelist lookup
372
371
ref = FunctionRef .resolveFromLookup (painlessLookup , clazz , type , call , captures .length );
@@ -385,11 +384,6 @@ private static MethodHandle lookupReferenceInternal(PainlessLookup painlessLooku
385
384
return callSite .dynamicInvoker ().asType (MethodType .methodType (clazz , captures ));
386
385
}
387
386
388
- /** gets the field name used to lookup up the MethodHandle for a function. */
389
- public static String getUserFunctionHandleFieldName (String name , int arity ) {
390
- return "handle$" + name + "$" + arity ;
391
- }
392
-
393
387
/**
394
388
* Looks up handle for a dynamic field getter (field load)
395
389
* <p>
0 commit comments