127 |
131 |
128 final FacetIntrospector introspector = createFacetIntrospector(); |
132 final FacetIntrospector introspector = createFacetIntrospector(); |
129 // Add methods and properties |
133 // Add methods and properties |
130 for(Method method: introspector.getMethods()) { |
134 for(Method method: introspector.getMethods()) { |
131 final String name = method.getName(); |
135 final String name = method.getName(); |
132 final MethodHandle methodHandle = introspector.unreflect(method); |
|
133 // Add method |
136 // Add method |
134 addMember(name, methodHandle, methods); |
137 addMember(name, method, methods); |
135 // Add the method as a property getter and/or setter |
138 // Add the method as a property getter and/or setter |
136 if(name.startsWith("get") && name.length() > 3 && method.getParameterTypes().length == 0) { |
139 if(name.startsWith("get") && name.length() > 3 && method.getParameterTypes().length == 0) { |
137 // Property getter |
140 // Property getter |
138 setPropertyGetter(decapitalize(name.substring(3)), introspector.unreflect( |
141 setPropertyGetter(method, 3); |
139 getMostGenericGetter(method)), ValidationType.INSTANCE_OF); |
|
140 } else if(name.startsWith("is") && name.length() > 2 && method.getParameterTypes().length == 0 && |
142 } else if(name.startsWith("is") && name.length() > 2 && method.getParameterTypes().length == 0 && |
141 method.getReturnType() == boolean.class) { |
143 method.getReturnType() == boolean.class) { |
142 // Boolean property getter |
144 // Boolean property getter |
143 setPropertyGetter(decapitalize(name.substring(2)), introspector.unreflect( |
145 setPropertyGetter(method, 2); |
144 getMostGenericGetter(method)), ValidationType.INSTANCE_OF); |
|
145 } else if(name.startsWith("set") && name.length() > 3 && method.getParameterTypes().length == 1) { |
146 } else if(name.startsWith("set") && name.length() > 3 && method.getParameterTypes().length == 1) { |
146 // Property setter |
147 // Property setter |
147 addMember(decapitalize(name.substring(3)), methodHandle, propertySetters); |
148 addMember(decapitalize(name.substring(3)), method, propertySetters); |
148 } |
149 } |
149 } |
150 } |
150 |
151 |
151 // Add field getter/setters as property getters/setters. |
152 // Add field getter/setters as property getters/setters. |
152 for(Field field: introspector.getFields()) { |
153 for(Field field: introspector.getFields()) { |
190 return new String(c); |
192 return new String(c); |
191 } |
193 } |
192 |
194 |
193 abstract FacetIntrospector createFacetIntrospector(); |
195 abstract FacetIntrospector createFacetIntrospector(); |
194 |
196 |
|
197 /** |
|
198 * Sets the specified dynamic method to be the property getter for the specified property. Note that you can only |
|
199 * use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties |
|
200 * that are caller-sensitive, you must use {@link #setPropertyGetter(String, SingleDynamicMethod, ValidationType)} |
|
201 * instead. |
|
202 * @param name name of the property |
|
203 * @param handle the method handle that implements the property getter |
|
204 * @param validationType the validation type for the property |
|
205 */ |
|
206 private void setPropertyGetter(String name, SingleDynamicMethod handle, ValidationType validationType) { |
|
207 propertyGetters.put(name, new AnnotatedDynamicMethod(handle, validationType)); |
|
208 } |
|
209 |
|
210 /** |
|
211 * Sets the specified reflective method to be the property getter for the specified property. |
|
212 * @param getter the getter method |
|
213 * @param prefixLen the getter prefix in the method name; should be 3 for getter names starting with "get" and 2 for |
|
214 * names starting with "is". |
|
215 */ |
|
216 private void setPropertyGetter(Method getter, int prefixLen) { |
|
217 setPropertyGetter(decapitalize(getter.getName().substring(prefixLen)), createDynamicMethod( |
|
218 getMostGenericGetter(getter)), ValidationType.INSTANCE_OF); |
|
219 } |
|
220 |
|
221 /** |
|
222 * Sets the specified method handle to be the property getter for the specified property. Note that you can only |
|
223 * use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties |
|
224 * that are caller-sensitive, you must use {@link #setPropertyGetter(String, SingleDynamicMethod, ValidationType)} |
|
225 * instead. |
|
226 * @param name name of the property |
|
227 * @param handle the method handle that implements the property getter |
|
228 * @param validationType the validation type for the property |
|
229 */ |
195 void setPropertyGetter(String name, MethodHandle handle, ValidationType validationType) { |
230 void setPropertyGetter(String name, MethodHandle handle, ValidationType validationType) { |
196 propertyGetters.put(name, new AnnotatedMethodHandle(handle, validationType)); |
231 setPropertyGetter(name, new SimpleDynamicMethod(handle, clazz, name), validationType); |
197 } |
232 } |
198 |
233 |
199 private void addMember(String name, MethodHandle mh, Map<String, DynamicMethod> methodMap) { |
234 private void addMember(String name, AccessibleObject ao, Map<String, DynamicMethod> methodMap) { |
|
235 addMember(name, createDynamicMethod(ao), methodMap); |
|
236 } |
|
237 |
|
238 private void addMember(String name, SingleDynamicMethod method, Map<String, DynamicMethod> methodMap) { |
200 final DynamicMethod existingMethod = methodMap.get(name); |
239 final DynamicMethod existingMethod = methodMap.get(name); |
201 final DynamicMethod newMethod = addMember(mh, existingMethod, clazz, name); |
240 final DynamicMethod newMethod = mergeMethods(method, existingMethod, clazz, name); |
202 if(newMethod != existingMethod) { |
241 if(newMethod != existingMethod) { |
203 methodMap.put(name, newMethod); |
242 methodMap.put(name, newMethod); |
204 } |
243 } |
205 } |
244 } |
206 |
245 |
207 static DynamicMethod createDynamicMethod(Iterable<MethodHandle> methodHandles, Class<?> clazz, String name) { |
246 /** |
|
247 * Given one or more reflective methods or constructors, creates a dynamic method that represents them all. The |
|
248 * methods should represent all overloads of the same name (or all constructors of the class). |
|
249 * @param members the reflective members |
|
250 * @param clazz the class declaring the reflective members |
|
251 * @param name the common name of the reflective members. |
|
252 * @return a dynamic method representing all the specified reflective members. |
|
253 */ |
|
254 static DynamicMethod createDynamicMethod(Iterable<? extends AccessibleObject> members, Class<?> clazz, String name) { |
208 DynamicMethod dynMethod = null; |
255 DynamicMethod dynMethod = null; |
209 for(MethodHandle methodHandle: methodHandles) { |
256 for(AccessibleObject method: members) { |
210 dynMethod = addMember(methodHandle, dynMethod, clazz, name); |
257 dynMethod = mergeMethods(createDynamicMethod(method), dynMethod, clazz, name); |
211 } |
258 } |
212 return dynMethod; |
259 return dynMethod; |
213 } |
260 } |
214 |
261 |
215 private static DynamicMethod addMember(MethodHandle mh, DynamicMethod existing, Class<?> clazz, String name) { |
262 /** |
|
263 * Given a reflective method or a constructor, creates a dynamic method that represents it. This method will |
|
264 * distinguish between caller sensitive and ordinary methods/constructors, and create appropriate caller sensitive |
|
265 * dynamic method when needed. |
|
266 * @param m the reflective member |
|
267 * @return the single dynamic method representing the reflective member |
|
268 */ |
|
269 private static SingleDynamicMethod createDynamicMethod(AccessibleObject m) { |
|
270 if(CallerSensitiveDetector.isCallerSensitive(m)) { |
|
271 return new CallerSensitiveDynamicMethod(m); |
|
272 } |
|
273 final Member member = (Member)m; |
|
274 return new SimpleDynamicMethod(unreflectSafely(m), member.getDeclaringClass(), member.getName()); |
|
275 } |
|
276 |
|
277 /** |
|
278 * Unreflects a method handle from a Method or a Constructor using safe (zero-privilege) unreflection. Should be |
|
279 * only used for methods and constructors that are not caller sensitive. If a caller sensitive method were |
|
280 * unreflected through this mechanism, it would not be a security issue, but would be bound to the zero-privilege |
|
281 * unreflector as its caller, and thus completely useless. |
|
282 * @param m the method or constructor |
|
283 * @return the method handle |
|
284 */ |
|
285 private static MethodHandle unreflectSafely(AccessibleObject m) { |
|
286 if(m instanceof Method) { |
|
287 final Method reflMethod = (Method)m; |
|
288 final MethodHandle handle = SafeUnreflector.unreflect(reflMethod); |
|
289 if(Modifier.isStatic(reflMethod.getModifiers())) { |
|
290 return StaticClassIntrospector.editStaticMethodHandle(handle); |
|
291 } |
|
292 return handle; |
|
293 } |
|
294 return StaticClassIntrospector.editConstructorMethodHandle(SafeUnreflector.unreflectConstructor( |
|
295 (Constructor<?>)m)); |
|
296 } |
|
297 |
|
298 private static DynamicMethod mergeMethods(SingleDynamicMethod method, DynamicMethod existing, Class<?> clazz, String name) { |
216 if(existing == null) { |
299 if(existing == null) { |
217 return new SimpleDynamicMethod(mh, clazz, name); |
300 return method; |
218 } else if(existing.contains(mh)) { |
301 } else if(existing.contains(method)) { |
219 return existing; |
302 return existing; |
220 } else if(existing instanceof SimpleDynamicMethod) { |
303 } else if(existing instanceof SingleDynamicMethod) { |
221 final OverloadedDynamicMethod odm = new OverloadedDynamicMethod(clazz, name); |
304 final OverloadedDynamicMethod odm = new OverloadedDynamicMethod(clazz, name); |
222 odm.addMethod(((SimpleDynamicMethod)existing)); |
305 odm.addMethod(((SingleDynamicMethod)existing)); |
223 odm.addMethod(mh); |
306 odm.addMethod(method); |
224 return odm; |
307 return odm; |
225 } else if(existing instanceof OverloadedDynamicMethod) { |
308 } else if(existing instanceof OverloadedDynamicMethod) { |
226 ((OverloadedDynamicMethod)existing).addMethod(mh); |
309 ((OverloadedDynamicMethod)existing).addMethod(method); |
227 return existing; |
310 return existing; |
228 } |
311 } |
229 throw new AssertionError(); |
312 throw new AssertionError(); |
230 } |
313 } |
231 |
314 |
294 } |
377 } |
295 |
378 |
296 private GuardedInvocation getCallPropWithThis(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) { |
379 private GuardedInvocation getCallPropWithThis(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) { |
297 switch(callSiteDescriptor.getNameTokenCount()) { |
380 switch(callSiteDescriptor.getNameTokenCount()) { |
298 case 3: { |
381 case 3: { |
299 return createGuardedDynamicMethodInvocation(callSiteDescriptor.getMethodType(), linkerServices, |
382 return createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices, |
300 callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), methods); |
383 callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), methods); |
301 } |
384 } |
302 default: { |
385 default: { |
303 return null; |
386 return null; |
304 } |
387 } |
305 } |
388 } |
306 } |
389 } |
307 |
390 |
308 private GuardedInvocation createGuardedDynamicMethodInvocation(MethodType callSiteType, |
391 private GuardedInvocation createGuardedDynamicMethodInvocation(CallSiteDescriptor callSiteDescriptor, |
309 LinkerServices linkerServices, String methodName, Map<String, DynamicMethod> methodMap){ |
392 LinkerServices linkerServices, String methodName, Map<String, DynamicMethod> methodMap){ |
310 final MethodHandle inv = getDynamicMethodInvocation(callSiteType, linkerServices, methodName, methodMap); |
393 final MethodHandle inv = getDynamicMethodInvocation(callSiteDescriptor, linkerServices, methodName, methodMap); |
311 return inv == null ? null : new GuardedInvocation(inv, getClassGuard(callSiteType)); |
394 return inv == null ? null : new GuardedInvocation(inv, getClassGuard(callSiteDescriptor.getMethodType())); |
312 } |
395 } |
313 |
396 |
314 private static MethodHandle getDynamicMethodInvocation(MethodType callSiteType, LinkerServices linkerServices, |
397 private static MethodHandle getDynamicMethodInvocation(CallSiteDescriptor callSiteDescriptor, |
315 String methodName, Map<String, DynamicMethod> methodMap) { |
398 LinkerServices linkerServices, String methodName, Map<String, DynamicMethod> methodMap) { |
316 final DynamicMethod dynaMethod = getDynamicMethod(methodName, methodMap); |
399 final DynamicMethod dynaMethod = getDynamicMethod(methodName, methodMap); |
317 return dynaMethod != null ? dynaMethod.getInvocation(callSiteType, linkerServices) : null; |
400 return dynaMethod != null ? dynaMethod.getInvocation(callSiteDescriptor, linkerServices) : null; |
318 } |
401 } |
319 |
402 |
320 private static DynamicMethod getDynamicMethod(String methodName, Map<String, DynamicMethod> methodMap) { |
403 private static DynamicMethod getDynamicMethod(String methodName, Map<String, DynamicMethod> methodMap) { |
321 final DynamicMethod dynaMethod = methodMap.get(methodName); |
404 final DynamicMethod dynaMethod = methodMap.get(methodName); |
322 return dynaMethod != null ? dynaMethod : getExplicitSignatureDynamicMethod(methodName, methodMap); |
405 return dynaMethod != null ? dynaMethod : getExplicitSignatureDynamicMethod(methodName, methodMap); |
323 } |
406 } |
324 |
407 |
325 private static SimpleDynamicMethod getExplicitSignatureDynamicMethod(String methodName, |
408 private static SingleDynamicMethod getExplicitSignatureDynamicMethod(String methodName, |
326 Map<String, DynamicMethod> methodsMap) { |
409 Map<String, DynamicMethod> methodsMap) { |
327 // What's below is meant to support the "name(type, type, ...)" syntax that programmers can use in a method name |
410 // What's below is meant to support the "name(type, type, ...)" syntax that programmers can use in a method name |
328 // to manually pin down an exact overloaded variant. This is not usually required, as the overloaded method |
411 // to manually pin down an exact overloaded variant. This is not usually required, as the overloaded method |
329 // resolution works correctly in almost every situation. However, in presence of many language-specific |
412 // resolution works correctly in almost every situation. However, in presence of many language-specific |
330 // conversions with a radically dynamic language, most overloaded methods will end up being constantly selected |
413 // conversions with a radically dynamic language, most overloaded methods will end up being constantly selected |
331 // at invocation time, so a programmer knowledgable of the situation might choose to pin down an exact overload |
414 // at invocation time, so a programmer knowledgeable of the situation might choose to pin down an exact overload |
332 // for performance reasons. |
415 // for performance reasons. |
333 |
416 |
334 // Is the method name lexically of the form "name(types)"? |
417 // Is the method name lexically of the form "name(types)"? |
335 final int lastChar = methodName.length() - 1; |
418 final int lastChar = methodName.length() - 1; |
336 if(methodName.charAt(lastChar) != ')') { |
419 if(methodName.charAt(lastChar) != ')') { |
433 } |
515 } |
434 } |
516 } |
435 |
517 |
436 private static final Lookup privateLookup = new Lookup(MethodHandles.lookup()); |
518 private static final Lookup privateLookup = new Lookup(MethodHandles.lookup()); |
437 |
519 |
438 private static final MethodHandle IS_ANNOTATED_HANDLE_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType( |
520 private static final MethodHandle IS_ANNOTATED_METHOD_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType( |
439 boolean.class, AnnotatedMethodHandle.class)); |
521 boolean.class, AnnotatedDynamicMethod.class)); |
440 private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_HANDLE = MethodHandles.dropArguments( |
522 private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_METHOD = MethodHandles.dropArguments( |
441 MethodHandles.constant(Object.class, null), 0, AnnotatedMethodHandle.class); |
523 MethodHandles.constant(Object.class, null), 0, AnnotatedDynamicMethod.class); |
442 private static final MethodHandle GET_ANNOTATED_HANDLE = privateLookup.findGetter(AnnotatedMethodHandle.class, |
524 private static final MethodHandle GET_ANNOTATED_METHOD = privateLookup.findVirtual(AnnotatedDynamicMethod.class, |
443 "handle", MethodHandle.class); |
525 "getTarget", MethodType.methodType(MethodHandle.class, MethodHandles.Lookup.class)); |
444 private static final MethodHandle GENERIC_PROPERTY_GETTER_HANDLER_INVOKER = MethodHandles.filterArguments( |
526 private static final MethodHandle GETTER_INVOKER = MethodHandles.invoker(MethodType.methodType(Object.class, Object.class)); |
445 MethodHandles.invoker(MethodType.methodType(Object.class, Object.class)), 0, GET_ANNOTATED_HANDLE); |
|
446 |
527 |
447 private GuardedInvocationComponent getPropertyGetter(CallSiteDescriptor callSiteDescriptor, |
528 private GuardedInvocationComponent getPropertyGetter(CallSiteDescriptor callSiteDescriptor, |
448 LinkerServices linkerServices, List<String> ops) throws Exception { |
529 LinkerServices linkerServices, List<String> ops) throws Exception { |
449 final MethodType type = callSiteDescriptor.getMethodType(); |
530 final MethodType type = callSiteDescriptor.getMethodType(); |
450 switch(callSiteDescriptor.getNameTokenCount()) { |
531 switch(callSiteDescriptor.getNameTokenCount()) { |
453 assertParameterCount(callSiteDescriptor, 2); |
534 assertParameterCount(callSiteDescriptor, 2); |
454 |
535 |
455 // What's below is basically: |
536 // What's below is basically: |
456 // foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle) |
537 // foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle) |
457 // only with a bunch of method signature adjustments. Basically, retrieve method getter |
538 // only with a bunch of method signature adjustments. Basically, retrieve method getter |
458 // AnnotatedMethodHandle; if it is non-null, invoke its "handle" field, otherwise either return null, |
539 // AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null, |
459 // or delegate to next component's invocation. |
540 // or delegate to next component's invocation. |
460 |
541 |
461 final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType( |
542 final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType( |
462 AnnotatedMethodHandle.class)); |
543 AnnotatedDynamicMethod.class)); |
463 // Object(AnnotatedMethodHandle, Object)->R(AnnotatedMethodHandle, T0) |
544 final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments( |
464 final MethodHandle invokeHandleTyped = linkerServices.asType(GENERIC_PROPERTY_GETTER_HANDLER_INVOKER, |
545 GET_ANNOTATED_METHOD, 1, callSiteDescriptor.getLookup()); |
465 MethodType.methodType(type.returnType(), AnnotatedMethodHandle.class, type.parameterType(0))); |
546 final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0, |
|
547 callSiteBoundMethodGetter); |
|
548 // Object(AnnotatedDynamicMethod, Object)->R(AnnotatedDynamicMethod, T0) |
|
549 final MethodHandle invokeHandleTyped = linkerServices.asType(callSiteBoundInvoker, |
|
550 MethodType.methodType(type.returnType(), AnnotatedDynamicMethod.class, type.parameterType(0))); |
466 // Since it's in the target of a fold, drop the unnecessary second argument |
551 // Since it's in the target of a fold, drop the unnecessary second argument |
467 // R(AnnotatedMethodHandle, T0)->R(AnnotatedMethodHandle, T0, T1) |
552 // R(AnnotatedDynamicMethod, T0)->R(AnnotatedDynamicMethod, T0, T1) |
468 final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2, |
553 final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2, |
469 type.parameterType(1)); |
554 type.parameterType(1)); |
470 final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, |
555 final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, |
471 linkerServices, ops); |
556 linkerServices, ops); |
472 |
557 |
473 final MethodHandle fallbackFolded; |
558 final MethodHandle fallbackFolded; |
474 if(nextComponent == null) { |
559 if(nextComponent == null) { |
475 // Object(AnnotatedMethodHandle)->R(AnnotatedMethodHandle, T0, T1); returns constant null |
560 // Object(AnnotatedDynamicMethod)->R(AnnotatedDynamicMethod, T0, T1); returns constant null |
476 fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_HANDLE, 1, |
561 fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_METHOD, 1, |
477 type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedMethodHandle.class)); |
562 type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedDynamicMethod.class)); |
478 } else { |
563 } else { |
479 // R(T0, T1)->R(AnnotatedMethodHAndle, T0, T1); adapts the next component's invocation to drop the |
564 // R(T0, T1)->R(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to drop the |
480 // extra argument resulting from fold |
565 // extra argument resulting from fold |
481 fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(), |
566 fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(), |
482 0, AnnotatedMethodHandle.class); |
567 0, AnnotatedDynamicMethod.class); |
483 } |
568 } |
484 |
569 |
485 // fold(R(AnnotatedMethodHandle, T0, T1), AnnotatedMethodHandle(T0, T1)) |
570 // fold(R(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1)) |
486 final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( |
571 final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( |
487 IS_ANNOTATED_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter); |
572 IS_ANNOTATED_METHOD_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter); |
488 if(nextComponent == null) { |
573 if(nextComponent == null) { |
489 return getClassGuardedInvocationComponent(compositeGetter, type); |
574 return getClassGuardedInvocationComponent(compositeGetter, type); |
490 } |
575 } |
491 return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); |
576 return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); |
492 } |
577 } |
493 case 3: { |
578 case 3: { |
494 // Must have exactly one argument: receiver |
579 // Must have exactly one argument: receiver |
495 assertParameterCount(callSiteDescriptor, 1); |
580 assertParameterCount(callSiteDescriptor, 1); |
496 // Fixed name |
581 // Fixed name |
497 final AnnotatedMethodHandle annGetter = propertyGetters.get(callSiteDescriptor.getNameToken( |
582 final AnnotatedDynamicMethod annGetter = propertyGetters.get(callSiteDescriptor.getNameToken( |
498 CallSiteDescriptor.NAME_OPERAND)); |
583 CallSiteDescriptor.NAME_OPERAND)); |
499 if(annGetter == null) { |
584 if(annGetter == null) { |
500 // We have no such property, always delegate to the next component operation |
585 // We have no such property, always delegate to the next component operation |
501 return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops); |
586 return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops); |
502 } |
587 } |
503 final MethodHandle getter = annGetter.handle; |
588 final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices); |
504 // NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being |
589 // NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being |
505 // overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the |
590 // overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the |
506 // method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If |
591 // method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If |
507 // we're linking against a field getter, don't make the assumption. |
592 // we're linking against a field getter, don't make the assumption. |
508 // NOTE: No delegation to the next component operation if we have a property with this name, even if its |
593 // NOTE: No delegation to the next component operation if we have a property with this name, even if its |
509 // value is null. |
594 // value is null. |
510 final ValidationType validationType = annGetter.validationType; |
595 final ValidationType validationType = annGetter.validationType; |
|
596 // TODO: we aren't using the type that declares the most generic getter here! |
511 return new GuardedInvocationComponent(linkerServices.asType(getter, type), getGuard(validationType, |
597 return new GuardedInvocationComponent(linkerServices.asType(getter, type), getGuard(validationType, |
512 type), clazz, validationType); |
598 type), clazz, validationType); |
513 } |
599 } |
514 default: { |
600 default: { |
515 // Can't do anything with more than 3 name components |
601 // Can't do anything with more than 3 name components |
621 |
707 |
622 // Type is MethodHandle(BeanLinker, MethodType, LinkerServices, Object, String, Object), of which the two "Object" |
708 // Type is MethodHandle(BeanLinker, MethodType, LinkerServices, Object, String, Object), of which the two "Object" |
623 // args are dropped; this makes handles with first three args conform to "Object, String, Object" though, which is |
709 // args are dropped; this makes handles with first three args conform to "Object, String, Object" though, which is |
624 // a typical property setter with variable name signature (target, name, value). |
710 // a typical property setter with variable name signature (target, name, value). |
625 private static final MethodHandle GET_PROPERTY_SETTER_HANDLE = MethodHandles.dropArguments(MethodHandles.dropArguments( |
711 private static final MethodHandle GET_PROPERTY_SETTER_HANDLE = MethodHandles.dropArguments(MethodHandles.dropArguments( |
626 privateLookup.findOwnSpecial("getPropertySetterHandle", MethodHandle.class, MethodType.class, |
712 privateLookup.findOwnSpecial("getPropertySetterHandle", MethodHandle.class, CallSiteDescriptor.class, |
627 LinkerServices.class, Object.class), 3, Object.class), 5, Object.class); |
713 LinkerServices.class, Object.class), 3, Object.class), 5, Object.class); |
628 // Type is MethodHandle(MethodType, LinkerServices, Object, String, Object) |
714 // Type is MethodHandle(MethodType, LinkerServices, Object, String, Object) |
629 private final MethodHandle getPropertySetterHandle = GET_PROPERTY_SETTER_HANDLE.bindTo(this); |
715 private final MethodHandle getPropertySetterHandle = GET_PROPERTY_SETTER_HANDLE.bindTo(this); |
630 |
716 |
631 @SuppressWarnings("unused") |
717 @SuppressWarnings("unused") |
632 private MethodHandle getPropertySetterHandle(MethodType setterType, LinkerServices linkerServices, Object id) { |
718 private MethodHandle getPropertySetterHandle(CallSiteDescriptor setterDescriptor, LinkerServices linkerServices, |
633 return getDynamicMethodInvocation(setterType, linkerServices, String.valueOf(id), propertySetters); |
719 Object id) { |
|
720 return getDynamicMethodInvocation(setterDescriptor, linkerServices, String.valueOf(id), propertySetters); |
634 } |
721 } |
635 |
722 |
636 private static MethodHandle GET_DYNAMIC_METHOD = MethodHandles.dropArguments(privateLookup.findOwnSpecial( |
723 private static MethodHandle GET_DYNAMIC_METHOD = MethodHandles.dropArguments(privateLookup.findOwnSpecial( |
637 "getDynamicMethod", DynamicMethod.class, Object.class), 1, Object.class); |
724 "getDynamicMethod", DynamicMethod.class, Object.class), 1, Object.class); |
638 private final MethodHandle getDynamicMethod = GET_DYNAMIC_METHOD.bindTo(this); |
725 private final MethodHandle getDynamicMethod = GET_DYNAMIC_METHOD.bindTo(this); |