2020package org .elasticsearch .painless ;
2121
2222import org .elasticsearch .painless .Locals .LocalMethod ;
23- import org .elasticsearch .painless .lookup .PainlessClass ;
2423import org .elasticsearch .painless .lookup .PainlessLookup ;
2524import org .elasticsearch .painless .lookup .PainlessLookupUtility ;
2625import org .elasticsearch .painless .lookup .PainlessMethod ;
3837import java .util .stream .Collectors ;
3938import java .util .stream .Stream ;
4039
40+ import static org .elasticsearch .painless .lookup .PainlessLookupUtility .typeToCanonicalTypeName ;
41+
4142/**
4243 * Support for dynamic type (def).
4344 * <p>
@@ -167,52 +168,6 @@ static MethodHandle arrayLengthGetter(Class<?> arrayType) {
167168 }
168169 }
169170
170- /**
171- * Looks up method entry for a dynamic method call.
172- * <p>
173- * A dynamic method call for variable {@code x} of type {@code def} looks like:
174- * {@code x.method(args...)}
175- * <p>
176- * This method traverses {@code recieverClass}'s class hierarchy (including interfaces)
177- * until it finds a matching whitelisted method. If one is not found, it throws an exception.
178- * Otherwise it returns the matching method.
179- * <p>
180- * @params painlessLookup the whitelist
181- * @param receiverClass Class of the object to invoke the method on.
182- * @param name Name of the method.
183- * @param arity arity of method
184- * @return matching method to invoke. never returns null.
185- * @throws IllegalArgumentException if no matching whitelisted method was found.
186- */
187- static PainlessMethod lookupMethodInternal (PainlessLookup painlessLookup , Class <?> receiverClass , String name , int arity ) {
188- String key = PainlessLookupUtility .buildPainlessMethodKey (name , arity );
189- // check whitelist for matching method
190- for (Class <?> clazz = receiverClass ; clazz != null ; clazz = clazz .getSuperclass ()) {
191- PainlessClass struct = painlessLookup .lookupPainlessClass (clazz );
192-
193- if (struct != null ) {
194- PainlessMethod method = struct .methods .get (key );
195- if (method != null ) {
196- return method ;
197- }
198- }
199-
200- for (Class <?> iface : clazz .getInterfaces ()) {
201- struct = painlessLookup .lookupPainlessClass (iface );
202-
203- if (struct != null ) {
204- PainlessMethod method = struct .methods .get (key );
205- if (method != null ) {
206- return method ;
207- }
208- }
209- }
210- }
211-
212- throw new IllegalArgumentException ("Unable to find dynamic method [" + name + "] with [" + arity + "] arguments " +
213- "for class [" + receiverClass .getCanonicalName () + "]." );
214- }
215-
216171 /**
217172 * Looks up handle for a dynamic method call, with lambda replacement
218173 * <p>
@@ -241,7 +196,14 @@ static MethodHandle lookupMethod(PainlessLookup painlessLookup, Map<String, Loca
241196 int numArguments = callSiteType .parameterCount ();
242197 // simple case: no lambdas
243198 if (recipeString .isEmpty ()) {
244- return lookupMethodInternal (painlessLookup , receiverClass , name , numArguments - 1 ).methodHandle ;
199+ PainlessMethod painlessMethod = painlessLookup .lookupRuntimePainlessMethod (receiverClass , name , numArguments - 1 );
200+
201+ if (painlessMethod == null ) {
202+ throw new IllegalArgumentException ("dynamic method " +
203+ "[" + typeToCanonicalTypeName (receiverClass ) + ", " + name + "/" + (numArguments - 1 ) + "] not found" );
204+ }
205+
206+ return painlessMethod .methodHandle ;
245207 }
246208
247209 // convert recipe string to a bitset for convenience (the code below should be refactored...)
@@ -264,7 +226,13 @@ static MethodHandle lookupMethod(PainlessLookup painlessLookup, Map<String, Loca
264226
265227 // lookup the method with the proper arity, then we know everything (e.g. interface types of parameters).
266228 // based on these we can finally link any remaining lambdas that were deferred.
267- PainlessMethod method = lookupMethodInternal (painlessLookup , receiverClass , name , arity );
229+ PainlessMethod method = painlessLookup .lookupRuntimePainlessMethod (receiverClass , name , arity );
230+
231+ if (method == null ) {
232+ throw new IllegalArgumentException (
233+ "dynamic method [" + typeToCanonicalTypeName (receiverClass ) + ", " + name + "/" + arity + "] not found" );
234+ }
235+
268236 MethodHandle handle = method .methodHandle ;
269237
270238 int replaced = 0 ;
@@ -332,15 +300,23 @@ static MethodHandle lookupMethod(PainlessLookup painlessLookup, Map<String, Loca
332300 static MethodHandle lookupReference (PainlessLookup painlessLookup , Map <String , LocalMethod > localMethods ,
333301 MethodHandles .Lookup methodHandlesLookup , String interfaceClass , Class <?> receiverClass , String name ) throws Throwable {
334302 Class <?> interfaceType = painlessLookup .canonicalTypeNameToType (interfaceClass );
303+ if (interfaceType == null ) {
304+ throw new IllegalArgumentException ("type [" + interfaceClass + "] not found" );
305+ }
335306 PainlessMethod interfaceMethod = painlessLookup .lookupFunctionalInterfacePainlessMethod (interfaceType );
336307 if (interfaceMethod == null ) {
337308 throw new IllegalArgumentException ("Class [" + interfaceClass + "] is not a functional interface" );
338309 }
339310 int arity = interfaceMethod .typeParameters .size ();
340- PainlessMethod implMethod = lookupMethodInternal (painlessLookup , receiverClass , name , arity );
311+ PainlessMethod implMethod = painlessLookup .lookupRuntimePainlessMethod (receiverClass , name , arity );
312+ if (implMethod == null ) {
313+ throw new IllegalArgumentException (
314+ "dynamic method [" + typeToCanonicalTypeName (receiverClass ) + ", " + name + "/" + arity + "] not found" );
315+ }
316+
341317 return lookupReferenceInternal (painlessLookup , localMethods , methodHandlesLookup ,
342- interfaceType , PainlessLookupUtility .typeToCanonicalTypeName (implMethod .targetClass ),
343- implMethod .javaMethod .getName (), 1 );
318+ interfaceType , PainlessLookupUtility .typeToCanonicalTypeName (implMethod .targetClass ),
319+ implMethod .javaMethod .getName (), 1 );
344320 }
345321
346322 /** Returns a method handle to an implementation of clazz, given method reference signature. */
@@ -389,27 +365,12 @@ private static MethodHandle lookupReferenceInternal(PainlessLookup painlessLooku
389365 */
390366 static MethodHandle lookupGetter (PainlessLookup painlessLookup , Class <?> receiverClass , String name ) {
391367 // first try whitelist
392- for (Class <?> clazz = receiverClass ; clazz != null ; clazz = clazz .getSuperclass ()) {
393- PainlessClass struct = painlessLookup .lookupPainlessClass (clazz );
394-
395- if (struct != null ) {
396- MethodHandle handle = struct .getterMethodHandles .get (name );
397- if (handle != null ) {
398- return handle ;
399- }
400- }
401-
402- for (final Class <?> iface : clazz .getInterfaces ()) {
403- struct = painlessLookup .lookupPainlessClass (iface );
368+ MethodHandle getter = painlessLookup .lookupRuntimeGetterMethodHandle (receiverClass , name );
404369
405- if (struct != null ) {
406- MethodHandle handle = struct .getterMethodHandles .get (name );
407- if (handle != null ) {
408- return handle ;
409- }
410- }
411- }
370+ if (getter != null ) {
371+ return getter ;
412372 }
373+
413374 // special case: arrays, maps, and lists
414375 if (receiverClass .isArray () && "length" .equals (name )) {
415376 // arrays expose .length as a read-only getter
@@ -426,12 +387,12 @@ static MethodHandle lookupGetter(PainlessLookup painlessLookup, Class<?> receive
426387 int index = Integer .parseInt (name );
427388 return MethodHandles .insertArguments (LIST_GET , 1 , index );
428389 } catch (NumberFormatException exception ) {
429- throw new IllegalArgumentException ( "Illegal list shortcut value [" + name + "]." );
390+ throw new IllegalArgumentException ("Illegal list shortcut value [" + name + "]." );
430391 }
431392 }
432393
433- throw new IllegalArgumentException ("Unable to find dynamic field [" + name + "] " +
434- "for class [ " + receiverClass . getCanonicalName () + "]. " );
394+ throw new IllegalArgumentException (
395+ "dynamic getter [" + typeToCanonicalTypeName ( receiverClass ) + ", " + name + "] not found " );
435396 }
436397
437398 /**
@@ -460,27 +421,12 @@ static MethodHandle lookupGetter(PainlessLookup painlessLookup, Class<?> receive
460421 */
461422 static MethodHandle lookupSetter (PainlessLookup painlessLookup , Class <?> receiverClass , String name ) {
462423 // first try whitelist
463- for (Class <?> clazz = receiverClass ; clazz != null ; clazz = clazz .getSuperclass ()) {
464- PainlessClass struct = painlessLookup .lookupPainlessClass (clazz );
465-
466- if (struct != null ) {
467- MethodHandle handle = struct .setterMethodHandles .get (name );
468- if (handle != null ) {
469- return handle ;
470- }
471- }
472-
473- for (final Class <?> iface : clazz .getInterfaces ()) {
474- struct = painlessLookup .lookupPainlessClass (iface );
424+ MethodHandle setter = painlessLookup .lookupRuntimeSetterMethodHandle (receiverClass , name );
475425
476- if (struct != null ) {
477- MethodHandle handle = struct .setterMethodHandles .get (name );
478- if (handle != null ) {
479- return handle ;
480- }
481- }
482- }
426+ if (setter != null ) {
427+ return setter ;
483428 }
429+
484430 // special case: maps, and lists
485431 if (Map .class .isAssignableFrom (receiverClass )) {
486432 // maps allow access like mymap.key
@@ -494,12 +440,12 @@ static MethodHandle lookupSetter(PainlessLookup painlessLookup, Class<?> receive
494440 int index = Integer .parseInt (name );
495441 return MethodHandles .insertArguments (LIST_SET , 1 , index );
496442 } catch (final NumberFormatException exception ) {
497- throw new IllegalArgumentException ( "Illegal list shortcut value [" + name + "]." );
443+ throw new IllegalArgumentException ("Illegal list shortcut value [" + name + "]." );
498444 }
499445 }
500446
501- throw new IllegalArgumentException ("Unable to find dynamic field [" + name + "] " +
502- "for class [ " + receiverClass . getCanonicalName () + "]. " );
447+ throw new IllegalArgumentException (
448+ "dynamic getter [" + typeToCanonicalTypeName ( receiverClass ) + ", " + name + "] not found " );
503449 }
504450
505451 /**
0 commit comments