1 /* |
|
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 /* |
|
27 * This file is available under and governed by the GNU General Public |
|
28 * License version 2 only, as published by the Free Software Foundation. |
|
29 * However, the following notice accompanied the original version of this |
|
30 * file, and Oracle licenses the original version of this file under the BSD |
|
31 * license: |
|
32 */ |
|
33 /* |
|
34 Copyright 2009-2013 Attila Szegedi |
|
35 |
|
36 Licensed under both the Apache License, Version 2.0 (the "Apache License") |
|
37 and the BSD License (the "BSD License"), with licensee being free to |
|
38 choose either of the two at their discretion. |
|
39 |
|
40 You may not use this file except in compliance with either the Apache |
|
41 License or the BSD License. |
|
42 |
|
43 If you choose to use this file in compliance with the Apache License, the |
|
44 following notice applies to you: |
|
45 |
|
46 You may obtain a copy of the Apache License at |
|
47 |
|
48 http://www.apache.org/licenses/LICENSE-2.0 |
|
49 |
|
50 Unless required by applicable law or agreed to in writing, software |
|
51 distributed under the License is distributed on an "AS IS" BASIS, |
|
52 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
|
53 implied. See the License for the specific language governing |
|
54 permissions and limitations under the License. |
|
55 |
|
56 If you choose to use this file in compliance with the BSD License, the |
|
57 following notice applies to you: |
|
58 |
|
59 Redistribution and use in source and binary forms, with or without |
|
60 modification, are permitted provided that the following conditions are |
|
61 met: |
|
62 * Redistributions of source code must retain the above copyright |
|
63 notice, this list of conditions and the following disclaimer. |
|
64 * Redistributions in binary form must reproduce the above copyright |
|
65 notice, this list of conditions and the following disclaimer in the |
|
66 documentation and/or other materials provided with the distribution. |
|
67 * Neither the name of the copyright holder nor the names of |
|
68 contributors may be used to endorse or promote products derived from |
|
69 this software without specific prior written permission. |
|
70 |
|
71 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
|
72 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
|
73 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
|
74 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER |
|
75 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
76 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
77 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
|
78 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
|
79 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
|
80 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
|
81 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
82 */ |
|
83 |
|
84 package jdk.internal.dynalink.beans; |
|
85 |
|
86 import java.lang.invoke.MethodHandle; |
|
87 import java.lang.invoke.MethodHandles; |
|
88 import java.lang.invoke.MethodType; |
|
89 import java.lang.reflect.AccessibleObject; |
|
90 import java.lang.reflect.Constructor; |
|
91 import java.lang.reflect.Field; |
|
92 import java.lang.reflect.Member; |
|
93 import java.lang.reflect.Method; |
|
94 import java.lang.reflect.Modifier; |
|
95 import java.util.Arrays; |
|
96 import java.util.Collections; |
|
97 import java.util.HashMap; |
|
98 import java.util.List; |
|
99 import java.util.Map; |
|
100 import java.util.Set; |
|
101 import jdk.internal.dynalink.CallSiteDescriptor; |
|
102 import jdk.internal.dynalink.CompositeOperation; |
|
103 import jdk.internal.dynalink.NamedOperation; |
|
104 import jdk.internal.dynalink.Operation; |
|
105 import jdk.internal.dynalink.StandardOperation; |
|
106 import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType; |
|
107 import jdk.internal.dynalink.internal.InternalTypeUtilities; |
|
108 import jdk.internal.dynalink.linker.GuardedInvocation; |
|
109 import jdk.internal.dynalink.linker.GuardingDynamicLinker; |
|
110 import jdk.internal.dynalink.linker.LinkRequest; |
|
111 import jdk.internal.dynalink.linker.LinkerServices; |
|
112 import jdk.internal.dynalink.linker.support.Guards; |
|
113 import jdk.internal.dynalink.linker.support.Lookup; |
|
114 import sun.reflect.CallerSensitive; |
|
115 |
|
116 /** |
|
117 * A base class for both {@link StaticClassLinker} and {@link BeanLinker}. Deals with common aspects of property |
|
118 * exposure and method calls for both static and instance facets of a class. |
|
119 */ |
|
120 abstract class AbstractJavaLinker implements GuardingDynamicLinker { |
|
121 |
|
122 final Class<?> clazz; |
|
123 private final MethodHandle classGuard; |
|
124 private final MethodHandle assignableGuard; |
|
125 private final Map<String, AnnotatedDynamicMethod> propertyGetters = new HashMap<>(); |
|
126 private final Map<String, DynamicMethod> propertySetters = new HashMap<>(); |
|
127 private final Map<String, DynamicMethod> methods = new HashMap<>(); |
|
128 |
|
129 AbstractJavaLinker(final Class<?> clazz, final MethodHandle classGuard) { |
|
130 this(clazz, classGuard, classGuard); |
|
131 } |
|
132 |
|
133 AbstractJavaLinker(final Class<?> clazz, final MethodHandle classGuard, final MethodHandle assignableGuard) { |
|
134 this.clazz = clazz; |
|
135 this.classGuard = classGuard; |
|
136 this.assignableGuard = assignableGuard; |
|
137 |
|
138 final FacetIntrospector introspector = createFacetIntrospector(); |
|
139 // Add methods and properties |
|
140 for(final Method method: introspector.getMethods()) { |
|
141 final String name = method.getName(); |
|
142 // Add method |
|
143 addMember(name, method, methods); |
|
144 // Add the method as a property getter and/or setter |
|
145 if(name.startsWith("get") && name.length() > 3 && method.getParameterTypes().length == 0) { |
|
146 // Property getter |
|
147 setPropertyGetter(method, 3); |
|
148 } else if(name.startsWith("is") && name.length() > 2 && method.getParameterTypes().length == 0 && |
|
149 method.getReturnType() == boolean.class) { |
|
150 // Boolean property getter |
|
151 setPropertyGetter(method, 2); |
|
152 } else if(name.startsWith("set") && name.length() > 3 && method.getParameterTypes().length == 1) { |
|
153 // Property setter |
|
154 addMember(decapitalize(name.substring(3)), method, propertySetters); |
|
155 } |
|
156 } |
|
157 |
|
158 // Add field getter/setters as property getters/setters. |
|
159 for(final Field field: introspector.getFields()) { |
|
160 final String name = field.getName(); |
|
161 // Only add a property getter when one is not defined already as a getXxx()/isXxx() method. |
|
162 if(!propertyGetters.containsKey(name)) { |
|
163 setPropertyGetter(name, introspector.unreflectGetter(field), ValidationType.EXACT_CLASS); |
|
164 } |
|
165 if(!(Modifier.isFinal(field.getModifiers()) || propertySetters.containsKey(name))) { |
|
166 addMember(name, new SimpleDynamicMethod(introspector.unreflectSetter(field), clazz, name), |
|
167 propertySetters); |
|
168 } |
|
169 } |
|
170 |
|
171 // Add inner classes, but only those for which we don't hide a property with it |
|
172 for(final Map.Entry<String, MethodHandle> innerClassSpec: introspector.getInnerClassGetters().entrySet()) { |
|
173 final String name = innerClassSpec.getKey(); |
|
174 if(!propertyGetters.containsKey(name)) { |
|
175 setPropertyGetter(name, innerClassSpec.getValue(), ValidationType.EXACT_CLASS); |
|
176 } |
|
177 } |
|
178 } |
|
179 |
|
180 private static String decapitalize(final String str) { |
|
181 assert str != null; |
|
182 if(str.isEmpty()) { |
|
183 return str; |
|
184 } |
|
185 |
|
186 final char c0 = str.charAt(0); |
|
187 if(Character.isLowerCase(c0)) { |
|
188 return str; |
|
189 } |
|
190 |
|
191 // If it has two consecutive upper-case characters, i.e. "URL", don't decapitalize |
|
192 if(str.length() > 1 && Character.isUpperCase(str.charAt(1))) { |
|
193 return str; |
|
194 } |
|
195 |
|
196 final char c[] = str.toCharArray(); |
|
197 c[0] = Character.toLowerCase(c0); |
|
198 return new String(c); |
|
199 } |
|
200 |
|
201 abstract FacetIntrospector createFacetIntrospector(); |
|
202 |
|
203 Set<String> getReadablePropertyNames() { |
|
204 return getUnmodifiableKeys(propertyGetters); |
|
205 } |
|
206 |
|
207 Set<String> getWritablePropertyNames() { |
|
208 return getUnmodifiableKeys(propertySetters); |
|
209 } |
|
210 |
|
211 Set<String> getMethodNames() { |
|
212 return getUnmodifiableKeys(methods); |
|
213 } |
|
214 |
|
215 private static Set<String> getUnmodifiableKeys(final Map<String, ?> m) { |
|
216 return Collections.unmodifiableSet(m.keySet()); |
|
217 } |
|
218 |
|
219 /** |
|
220 * Sets the specified dynamic method to be the property getter for the specified property. Note that you can only |
|
221 * use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties |
|
222 * that are caller-sensitive, you must use {@link #setPropertyGetter(String, SingleDynamicMethod, ValidationType)} |
|
223 * instead. |
|
224 * @param name name of the property |
|
225 * @param handle the method handle that implements the property getter |
|
226 * @param validationType the validation type for the property |
|
227 */ |
|
228 private void setPropertyGetter(final String name, final SingleDynamicMethod handle, final ValidationType validationType) { |
|
229 propertyGetters.put(name, new AnnotatedDynamicMethod(handle, validationType)); |
|
230 } |
|
231 |
|
232 /** |
|
233 * Sets the specified reflective method to be the property getter for the specified property. |
|
234 * @param getter the getter method |
|
235 * @param prefixLen the getter prefix in the method name; should be 3 for getter names starting with "get" and 2 for |
|
236 * names starting with "is". |
|
237 */ |
|
238 private void setPropertyGetter(final Method getter, final int prefixLen) { |
|
239 setPropertyGetter(decapitalize(getter.getName().substring(prefixLen)), createDynamicMethod( |
|
240 getMostGenericGetter(getter)), ValidationType.INSTANCE_OF); |
|
241 } |
|
242 |
|
243 /** |
|
244 * Sets the specified method handle to be the property getter for the specified property. Note that you can only |
|
245 * use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties |
|
246 * that are caller-sensitive, you must use {@link #setPropertyGetter(String, SingleDynamicMethod, ValidationType)} |
|
247 * instead. |
|
248 * @param name name of the property |
|
249 * @param handle the method handle that implements the property getter |
|
250 * @param validationType the validation type for the property |
|
251 */ |
|
252 void setPropertyGetter(final String name, final MethodHandle handle, final ValidationType validationType) { |
|
253 setPropertyGetter(name, new SimpleDynamicMethod(handle, clazz, name), validationType); |
|
254 } |
|
255 |
|
256 private void addMember(final String name, final AccessibleObject ao, final Map<String, DynamicMethod> methodMap) { |
|
257 addMember(name, createDynamicMethod(ao), methodMap); |
|
258 } |
|
259 |
|
260 private void addMember(final String name, final SingleDynamicMethod method, final Map<String, DynamicMethod> methodMap) { |
|
261 final DynamicMethod existingMethod = methodMap.get(name); |
|
262 final DynamicMethod newMethod = mergeMethods(method, existingMethod, clazz, name); |
|
263 if(newMethod != existingMethod) { |
|
264 methodMap.put(name, newMethod); |
|
265 } |
|
266 } |
|
267 |
|
268 /** |
|
269 * Given one or more reflective methods or constructors, creates a dynamic method that represents them all. The |
|
270 * methods should represent all overloads of the same name (or all constructors of the class). |
|
271 * @param members the reflective members |
|
272 * @param clazz the class declaring the reflective members |
|
273 * @param name the common name of the reflective members. |
|
274 * @return a dynamic method representing all the specified reflective members. |
|
275 */ |
|
276 static DynamicMethod createDynamicMethod(final Iterable<? extends AccessibleObject> members, final Class<?> clazz, final String name) { |
|
277 DynamicMethod dynMethod = null; |
|
278 for(final AccessibleObject method: members) { |
|
279 dynMethod = mergeMethods(createDynamicMethod(method), dynMethod, clazz, name); |
|
280 } |
|
281 return dynMethod; |
|
282 } |
|
283 |
|
284 /** |
|
285 * Given a reflective method or a constructor, creates a dynamic method that represents it. This method will |
|
286 * distinguish between caller sensitive and ordinary methods/constructors, and create appropriate caller sensitive |
|
287 * dynamic method when needed. |
|
288 * @param m the reflective member |
|
289 * @return the single dynamic method representing the reflective member |
|
290 */ |
|
291 private static SingleDynamicMethod createDynamicMethod(final AccessibleObject m) { |
|
292 if (m.isAnnotationPresent(CallerSensitive.class)) { |
|
293 // Method has @CallerSensitive annotation |
|
294 return new CallerSensitiveDynamicMethod(m); |
|
295 } |
|
296 // Method has no @CallerSensitive annotation |
|
297 final MethodHandle mh; |
|
298 try { |
|
299 mh = unreflectSafely(m); |
|
300 } catch (final IllegalAccessError e) { |
|
301 // java.lang.invoke can in some case conservatively treat as caller sensitive methods that aren't |
|
302 // marked with the annotation. In this case, we'll fall back to treating it as caller sensitive. |
|
303 return new CallerSensitiveDynamicMethod(m); |
|
304 } |
|
305 // Proceed with non-caller sensitive |
|
306 final Member member = (Member)m; |
|
307 return new SimpleDynamicMethod(mh, member.getDeclaringClass(), member.getName(), m instanceof Constructor); |
|
308 } |
|
309 |
|
310 /** |
|
311 * Unreflects a method handle from a Method or a Constructor using safe (zero-privilege) unreflection. Should be |
|
312 * only used for methods and constructors that are not caller sensitive. If a caller sensitive method were |
|
313 * unreflected through this mechanism, it would not be a security issue, but would be bound to the zero-privilege |
|
314 * unreflector as its caller, and thus completely useless. |
|
315 * @param m the method or constructor |
|
316 * @return the method handle |
|
317 */ |
|
318 private static MethodHandle unreflectSafely(final AccessibleObject m) { |
|
319 if(m instanceof Method) { |
|
320 final Method reflMethod = (Method)m; |
|
321 final MethodHandle handle = Lookup.PUBLIC.unreflect(reflMethod); |
|
322 if(Modifier.isStatic(reflMethod.getModifiers())) { |
|
323 return StaticClassIntrospector.editStaticMethodHandle(handle); |
|
324 } |
|
325 return handle; |
|
326 } |
|
327 return StaticClassIntrospector.editConstructorMethodHandle(Lookup.PUBLIC.unreflectConstructor((Constructor<?>)m)); |
|
328 } |
|
329 |
|
330 private static DynamicMethod mergeMethods(final SingleDynamicMethod method, final DynamicMethod existing, final Class<?> clazz, final String name) { |
|
331 if(existing == null) { |
|
332 return method; |
|
333 } else if(existing.contains(method)) { |
|
334 return existing; |
|
335 } else if(existing instanceof SingleDynamicMethod) { |
|
336 final OverloadedDynamicMethod odm = new OverloadedDynamicMethod(clazz, name); |
|
337 odm.addMethod(((SingleDynamicMethod)existing)); |
|
338 odm.addMethod(method); |
|
339 return odm; |
|
340 } else if(existing instanceof OverloadedDynamicMethod) { |
|
341 ((OverloadedDynamicMethod)existing).addMethod(method); |
|
342 return existing; |
|
343 } |
|
344 throw new AssertionError(); |
|
345 } |
|
346 |
|
347 @Override |
|
348 public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices) |
|
349 throws Exception { |
|
350 final CallSiteDescriptor callSiteDescriptor = request.getCallSiteDescriptor(); |
|
351 |
|
352 // Handle NamedOperation(CALL_METHOD, name) separately |
|
353 final Operation operation = callSiteDescriptor.getOperation(); |
|
354 if (operation instanceof NamedOperation) { |
|
355 final NamedOperation namedOperation = (NamedOperation)operation; |
|
356 if (namedOperation.getBaseOperation() == StandardOperation.CALL_METHOD) { |
|
357 return createGuardedDynamicMethodInvocation(callSiteDescriptor, |
|
358 linkerServices, namedOperation.getName().toString(), methods); |
|
359 } |
|
360 } |
|
361 |
|
362 List<Operation> operations = Arrays.asList( |
|
363 CompositeOperation.getOperations( |
|
364 NamedOperation.getBaseOperation(operation))); |
|
365 final Object name = NamedOperation.getName(operation); |
|
366 |
|
367 while(!operations.isEmpty()) { |
|
368 final GuardedInvocationComponent gic = |
|
369 getGuardedInvocationComponent(callSiteDescriptor, |
|
370 linkerServices, operations, name); |
|
371 if(gic != null) { |
|
372 return gic.getGuardedInvocation(); |
|
373 } |
|
374 operations = pop(operations); |
|
375 } |
|
376 return null; |
|
377 } |
|
378 |
|
379 protected GuardedInvocationComponent getGuardedInvocationComponent( |
|
380 final CallSiteDescriptor callSiteDescriptor, |
|
381 final LinkerServices linkerServices, |
|
382 final List<Operation> operations, final Object name) |
|
383 throws Exception { |
|
384 if(operations.isEmpty()) { |
|
385 return null; |
|
386 } |
|
387 final Operation op = operations.get(0); |
|
388 // Either GET_PROPERTY:name(this) or GET_PROPERTY(this, name) |
|
389 if(op == StandardOperation.GET_PROPERTY) { |
|
390 return getPropertyGetter(callSiteDescriptor, linkerServices, pop(operations), name); |
|
391 } |
|
392 // Either SET_PROPERTY:name(this, value) or SET_PROPERTY(this, name, value) |
|
393 if(op == StandardOperation.SET_PROPERTY) { |
|
394 return getPropertySetter(callSiteDescriptor, linkerServices, pop(operations), name); |
|
395 } |
|
396 // Either GET_METHOD:name(this), or GET_METHOD(this, name) |
|
397 if(op == StandardOperation.GET_METHOD) { |
|
398 return getMethodGetter(callSiteDescriptor, linkerServices, pop(operations), name); |
|
399 } |
|
400 return null; |
|
401 } |
|
402 |
|
403 static final <T> List<T> pop(final List<T> l) { |
|
404 return l.subList(1, l.size()); |
|
405 } |
|
406 |
|
407 MethodHandle getClassGuard(final CallSiteDescriptor desc) { |
|
408 return getClassGuard(desc.getMethodType()); |
|
409 } |
|
410 |
|
411 MethodHandle getClassGuard(final MethodType type) { |
|
412 return Guards.asType(classGuard, type); |
|
413 } |
|
414 |
|
415 GuardedInvocationComponent getClassGuardedInvocationComponent(final MethodHandle invocation, final MethodType type) { |
|
416 return new GuardedInvocationComponent(invocation, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); |
|
417 } |
|
418 |
|
419 abstract SingleDynamicMethod getConstructorMethod(final String signature); |
|
420 |
|
421 private MethodHandle getAssignableGuard(final MethodType type) { |
|
422 return Guards.asType(assignableGuard, type); |
|
423 } |
|
424 |
|
425 private GuardedInvocation createGuardedDynamicMethodInvocation(final CallSiteDescriptor callSiteDescriptor, |
|
426 final LinkerServices linkerServices, final String methodName, final Map<String, DynamicMethod> methodMap){ |
|
427 final MethodHandle inv = getDynamicMethodInvocation(callSiteDescriptor, linkerServices, methodName, methodMap); |
|
428 return inv == null ? null : new GuardedInvocation(inv, getClassGuard(callSiteDescriptor.getMethodType())); |
|
429 } |
|
430 |
|
431 private MethodHandle getDynamicMethodInvocation(final CallSiteDescriptor callSiteDescriptor, |
|
432 final LinkerServices linkerServices, final String methodName, final Map<String, DynamicMethod> methodMap) { |
|
433 final DynamicMethod dynaMethod = getDynamicMethod(methodName, methodMap); |
|
434 return dynaMethod != null ? dynaMethod.getInvocation(callSiteDescriptor, linkerServices) : null; |
|
435 } |
|
436 |
|
437 private DynamicMethod getDynamicMethod(final String methodName, final Map<String, DynamicMethod> methodMap) { |
|
438 final DynamicMethod dynaMethod = methodMap.get(methodName); |
|
439 return dynaMethod != null ? dynaMethod : getExplicitSignatureDynamicMethod(methodName, methodMap); |
|
440 } |
|
441 |
|
442 private SingleDynamicMethod getExplicitSignatureDynamicMethod(final String fullName, |
|
443 final Map<String, DynamicMethod> methodsMap) { |
|
444 // What's below is meant to support the "name(type, type, ...)" syntax that programmers can use in a method name |
|
445 // to manually pin down an exact overloaded variant. This is not usually required, as the overloaded method |
|
446 // resolution works correctly in almost every situation. However, in presence of many language-specific |
|
447 // conversions with a radically dynamic language, most overloaded methods will end up being constantly selected |
|
448 // at invocation time, so a programmer knowledgeable of the situation might choose to pin down an exact overload |
|
449 // for performance reasons. |
|
450 |
|
451 // Is the method name lexically of the form "name(types)"? |
|
452 final int lastChar = fullName.length() - 1; |
|
453 if(fullName.charAt(lastChar) != ')') { |
|
454 return null; |
|
455 } |
|
456 final int openBrace = fullName.indexOf('('); |
|
457 if(openBrace == -1) { |
|
458 return null; |
|
459 } |
|
460 |
|
461 final String name = fullName.substring(0, openBrace); |
|
462 final String signature = fullName.substring(openBrace + 1, lastChar); |
|
463 |
|
464 // Find an existing method for the "name" part |
|
465 final DynamicMethod simpleNamedMethod = methodsMap.get(name); |
|
466 if(simpleNamedMethod == null) { |
|
467 // explicit signature constructor access |
|
468 // Java.type("java.awt.Color")["(int,int,int)"] |
|
469 // will get Color(int,int,int) constructor of Color class. |
|
470 if (name.isEmpty()) { |
|
471 return getConstructorMethod(signature); |
|
472 } |
|
473 |
|
474 return null; |
|
475 } |
|
476 |
|
477 // Try to get a narrowed dynamic method for the explicit parameter types. |
|
478 return simpleNamedMethod.getMethodForExactParamTypes(signature); |
|
479 } |
|
480 |
|
481 private static final MethodHandle IS_METHOD_HANDLE_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType( |
|
482 boolean.class, MethodHandle.class)); |
|
483 private static final MethodHandle CONSTANT_NULL_DROP_METHOD_HANDLE = MethodHandles.dropArguments( |
|
484 MethodHandles.constant(Object.class, null), 0, MethodHandle.class); |
|
485 |
|
486 private GuardedInvocationComponent getPropertySetter(final CallSiteDescriptor callSiteDescriptor, |
|
487 final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception { |
|
488 if (name == null) { |
|
489 return getUnnamedPropertySetter(callSiteDescriptor, linkerServices, operations); |
|
490 } |
|
491 return getNamedPropertySetter(callSiteDescriptor, linkerServices, operations, name); |
|
492 } |
|
493 |
|
494 private GuardedInvocationComponent getUnnamedPropertySetter(final CallSiteDescriptor callSiteDescriptor, |
|
495 final LinkerServices linkerServices, final List<Operation> operations) throws Exception { |
|
496 // Must have three arguments: target object, property name, and property value. |
|
497 assertParameterCount(callSiteDescriptor, 3); |
|
498 |
|
499 // We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be |
|
500 // valid for us to convert return values proactively. Also, since we don't know what setters will be |
|
501 // invoked, we'll conservatively presume Object return type. The one exception is void return. |
|
502 final MethodType origType = callSiteDescriptor.getMethodType(); |
|
503 final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class); |
|
504 |
|
505 // What's below is basically: |
|
506 // foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation), |
|
507 // get_setter_handle(type, linkerServices)) |
|
508 // only with a bunch of method signature adjustments. Basically, retrieve method setter |
|
509 // MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next |
|
510 // component's invocation. |
|
511 |
|
512 // Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll |
|
513 // abbreviate to R(O, N, V) going forward, although we don't really use R here (see above about using |
|
514 // Object return type). |
|
515 final MethodType setterType = type.dropParameterTypes(1, 2); |
|
516 // Bind property setter handle to the expected setter type and linker services. Type is |
|
517 // MethodHandle(Object, String, Object) |
|
518 final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0, |
|
519 callSiteDescriptor.changeMethodType(setterType), linkerServices); |
|
520 |
|
521 // Cast getter to MethodHandle(O, N, V) |
|
522 final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType( |
|
523 MethodHandle.class)); |
|
524 |
|
525 // Handle to invoke the setter R(MethodHandle, O, V) |
|
526 final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType); |
|
527 // Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V) |
|
528 final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType( |
|
529 1)); |
|
530 final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, |
|
531 linkerServices, operations, null); |
|
532 |
|
533 final MethodHandle fallbackFolded; |
|
534 if(nextComponent == null) { |
|
535 // Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null |
|
536 fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1, |
|
537 type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class)); |
|
538 } else { |
|
539 // Object(O, N, V)->Object(MethodHandle, O, N, V); adapts the next component's invocation to drop the |
|
540 // extra argument resulting from fold |
|
541 fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(), |
|
542 0, MethodHandle.class); |
|
543 } |
|
544 |
|
545 // fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V)) |
|
546 final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( |
|
547 IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter); |
|
548 if(nextComponent == null) { |
|
549 return getClassGuardedInvocationComponent(compositeSetter, type); |
|
550 } |
|
551 return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); |
|
552 } |
|
553 |
|
554 private GuardedInvocationComponent getNamedPropertySetter(final CallSiteDescriptor callSiteDescriptor, |
|
555 final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception { |
|
556 // Must have two arguments: target object and property value |
|
557 assertParameterCount(callSiteDescriptor, 2); |
|
558 final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices, |
|
559 name.toString(), propertySetters); |
|
560 // If we have a property setter with this name, this composite operation will always stop here |
|
561 if(gi != null) { |
|
562 return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS); |
|
563 } |
|
564 // If we don't have a property setter with this name, always fall back to the next operation in the |
|
565 // composite (if any) |
|
566 return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations, name); |
|
567 } |
|
568 |
|
569 private static final Lookup privateLookup = new Lookup(MethodHandles.lookup()); |
|
570 |
|
571 private static final MethodHandle IS_ANNOTATED_METHOD_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType( |
|
572 boolean.class, AnnotatedDynamicMethod.class)); |
|
573 private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_METHOD = MethodHandles.dropArguments( |
|
574 MethodHandles.constant(Object.class, null), 0, AnnotatedDynamicMethod.class); |
|
575 private static final MethodHandle GET_ANNOTATED_METHOD = privateLookup.findVirtual(AnnotatedDynamicMethod.class, |
|
576 "getTarget", MethodType.methodType(MethodHandle.class, CallSiteDescriptor.class, LinkerServices.class)); |
|
577 private static final MethodHandle GETTER_INVOKER = MethodHandles.invoker(MethodType.methodType(Object.class, Object.class)); |
|
578 |
|
579 private GuardedInvocationComponent getPropertyGetter(final CallSiteDescriptor callSiteDescriptor, |
|
580 final LinkerServices linkerServices, final List<Operation> ops, final Object name) throws Exception { |
|
581 if (name == null) { |
|
582 return getUnnamedPropertyGetter(callSiteDescriptor, linkerServices, ops); |
|
583 } |
|
584 |
|
585 return getNamedPropertyGetter(callSiteDescriptor, linkerServices, ops, name); |
|
586 } |
|
587 |
|
588 private GuardedInvocationComponent getUnnamedPropertyGetter(final CallSiteDescriptor callSiteDescriptor, |
|
589 final LinkerServices linkerServices, final List<Operation> ops) throws Exception { |
|
590 // Since we can't know what kind of a getter we'll get back on different invocations, we'll just |
|
591 // conservatively presume Object. Note we can't just coerce to a narrower call site type as the linking |
|
592 // runtime might not allow coercing at that call site. |
|
593 final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class); |
|
594 // Must have exactly two arguments: receiver and name |
|
595 assertParameterCount(callSiteDescriptor, 2); |
|
596 |
|
597 // What's below is basically: |
|
598 // foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle) |
|
599 // only with a bunch of method signature adjustments. Basically, retrieve method getter |
|
600 // AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null, |
|
601 // or delegate to next component's invocation. |
|
602 |
|
603 final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType( |
|
604 AnnotatedDynamicMethod.class)); |
|
605 final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments( |
|
606 GET_ANNOTATED_METHOD, 1, callSiteDescriptor, linkerServices); |
|
607 final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0, |
|
608 callSiteBoundMethodGetter); |
|
609 // Object(AnnotatedDynamicMethod, Object)->Object(AnnotatedDynamicMethod, T0) |
|
610 final MethodHandle invokeHandleTyped = linkerServices.asType(callSiteBoundInvoker, |
|
611 MethodType.methodType(type.returnType(), AnnotatedDynamicMethod.class, type.parameterType(0))); |
|
612 // Since it's in the target of a fold, drop the unnecessary second argument |
|
613 // Object(AnnotatedDynamicMethod, T0)->Object(AnnotatedDynamicMethod, T0, T1) |
|
614 final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2, |
|
615 type.parameterType(1)); |
|
616 final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, |
|
617 linkerServices, ops, null); |
|
618 |
|
619 final MethodHandle fallbackFolded; |
|
620 if(nextComponent == null) { |
|
621 // Object(AnnotatedDynamicMethod)->Object(AnnotatedDynamicMethod, T0, T1); returns constant null |
|
622 fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_METHOD, 1, |
|
623 type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedDynamicMethod.class)); |
|
624 } else { |
|
625 // Object(T0, T1)->Object(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to |
|
626 // drop the extra argument resulting from fold and to change its return type to Object. |
|
627 final MethodHandle nextInvocation = nextComponent.getGuardedInvocation().getInvocation(); |
|
628 final MethodType nextType = nextInvocation.type(); |
|
629 fallbackFolded = MethodHandles.dropArguments(nextInvocation.asType( |
|
630 nextType.changeReturnType(Object.class)), 0, AnnotatedDynamicMethod.class); |
|
631 } |
|
632 |
|
633 // fold(Object(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1)) |
|
634 final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( |
|
635 IS_ANNOTATED_METHOD_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter); |
|
636 if(nextComponent == null) { |
|
637 return getClassGuardedInvocationComponent(compositeGetter, type); |
|
638 } |
|
639 return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); |
|
640 } |
|
641 |
|
642 private GuardedInvocationComponent getNamedPropertyGetter(final CallSiteDescriptor callSiteDescriptor, |
|
643 final LinkerServices linkerServices, final List<Operation> ops, final Object name) throws Exception { |
|
644 // Must have exactly one argument: receiver |
|
645 assertParameterCount(callSiteDescriptor, 1); |
|
646 // Fixed name |
|
647 final AnnotatedDynamicMethod annGetter = propertyGetters.get(name.toString()); |
|
648 if(annGetter == null) { |
|
649 // We have no such property, always delegate to the next component operation |
|
650 return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops, name); |
|
651 } |
|
652 final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices); |
|
653 // NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being |
|
654 // overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the |
|
655 // method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If |
|
656 // we're linking against a field getter, don't make the assumption. |
|
657 // NOTE: No delegation to the next component operation if we have a property with this name, even if its |
|
658 // value is null. |
|
659 final ValidationType validationType = annGetter.validationType; |
|
660 // TODO: we aren't using the type that declares the most generic getter here! |
|
661 return new GuardedInvocationComponent(getter, getGuard(validationType, |
|
662 callSiteDescriptor.getMethodType()), clazz, validationType); |
|
663 } |
|
664 |
|
665 private MethodHandle getGuard(final ValidationType validationType, final MethodType methodType) { |
|
666 switch(validationType) { |
|
667 case EXACT_CLASS: { |
|
668 return getClassGuard(methodType); |
|
669 } |
|
670 case INSTANCE_OF: { |
|
671 return getAssignableGuard(methodType); |
|
672 } |
|
673 case IS_ARRAY: { |
|
674 return Guards.isArray(0, methodType); |
|
675 } |
|
676 case NONE: { |
|
677 return null; |
|
678 } |
|
679 default: { |
|
680 throw new AssertionError(); |
|
681 } |
|
682 } |
|
683 } |
|
684 |
|
685 private static final MethodHandle IS_DYNAMIC_METHOD = Guards.isInstance(DynamicMethod.class, |
|
686 MethodType.methodType(boolean.class, Object.class)); |
|
687 private static final MethodHandle OBJECT_IDENTITY = MethodHandles.identity(Object.class); |
|
688 |
|
689 private GuardedInvocationComponent getMethodGetter(final CallSiteDescriptor callSiteDescriptor, |
|
690 final LinkerServices linkerServices, final List<Operation> ops, final Object name) throws Exception { |
|
691 // The created method handle will always return a DynamicMethod (or null), but since we don't want that type to |
|
692 // be visible outside of this linker, declare it to return Object. |
|
693 final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class); |
|
694 if (name == null) { |
|
695 return getUnnamedMethodGetter(callSiteDescriptor, linkerServices, ops, type); |
|
696 } |
|
697 |
|
698 return getNamedMethodGetter(callSiteDescriptor, linkerServices, ops, name, type); |
|
699 } |
|
700 |
|
701 private GuardedInvocationComponent getUnnamedMethodGetter(final CallSiteDescriptor callSiteDescriptor, |
|
702 final LinkerServices linkerServices, final List<Operation> ops, final MethodType type) throws Exception { |
|
703 // Must have exactly two arguments: receiver and name |
|
704 assertParameterCount(callSiteDescriptor, 2); |
|
705 final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, |
|
706 linkerServices, ops, null); |
|
707 if(nextComponent == null || !InternalTypeUtilities.areAssignable(DynamicMethod.class, |
|
708 nextComponent.getGuardedInvocation().getInvocation().type().returnType())) { |
|
709 // No next component operation, or it can never produce a dynamic method; just return a component |
|
710 // for this operation. |
|
711 return getClassGuardedInvocationComponent(linkerServices.asType(getDynamicMethod, type), type); |
|
712 } |
|
713 |
|
714 // What's below is basically: |
|
715 // foldArguments(guardWithTest(isNotNull, identity, nextComponent.invocation), getter) only with a |
|
716 // bunch of method signature adjustments. Basically, execute method getter; if it returns a non-null |
|
717 // DynamicMethod, use identity to return it, otherwise delegate to nextComponent's invocation. |
|
718 |
|
719 final MethodHandle typedGetter = linkerServices.asType(getDynamicMethod, type); |
|
720 // Since it is part of the foldArgument() target, it will have extra args that we need to drop. |
|
721 final MethodHandle returnMethodHandle = linkerServices.asType(MethodHandles.dropArguments( |
|
722 OBJECT_IDENTITY, 1, type.parameterList()), type.insertParameterTypes(0, Object.class)); |
|
723 final MethodHandle nextComponentInvocation = nextComponent.getGuardedInvocation().getInvocation(); |
|
724 // The assumption is that getGuardedInvocationComponent() already asType()'d it correctly modulo the |
|
725 // return type. |
|
726 assert nextComponentInvocation.type().changeReturnType(type.returnType()).equals(type); |
|
727 // Since it is part of the foldArgument() target, we have to drop an extra arg it receives. |
|
728 final MethodHandle nextCombinedInvocation = MethodHandles.dropArguments(nextComponentInvocation, 0, |
|
729 Object.class); |
|
730 // Assemble it all into a fold(guard(isNotNull, identity, nextInvocation), get) |
|
731 final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( |
|
732 IS_DYNAMIC_METHOD, returnMethodHandle, nextCombinedInvocation), typedGetter); |
|
733 |
|
734 return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); |
|
735 } |
|
736 |
|
737 private GuardedInvocationComponent getNamedMethodGetter(final CallSiteDescriptor callSiteDescriptor, |
|
738 final LinkerServices linkerServices, final List<Operation> ops, final Object name, final MethodType type) |
|
739 throws Exception { |
|
740 // Must have exactly one argument: receiver |
|
741 assertParameterCount(callSiteDescriptor, 1); |
|
742 final DynamicMethod method = getDynamicMethod(name.toString()); |
|
743 if(method == null) { |
|
744 // We have no such method, always delegate to the next component |
|
745 return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops, name); |
|
746 } |
|
747 // No delegation to the next component of the composite operation; if we have a method with that name, |
|
748 // we'll always return it at this point. |
|
749 return getClassGuardedInvocationComponent(linkerServices.asType(MethodHandles.dropArguments( |
|
750 MethodHandles.constant(Object.class, method), 0, type.parameterType(0)), type), type); |
|
751 } |
|
752 |
|
753 static class MethodPair { |
|
754 final MethodHandle method1; |
|
755 final MethodHandle method2; |
|
756 |
|
757 MethodPair(final MethodHandle method1, final MethodHandle method2) { |
|
758 this.method1 = method1; |
|
759 this.method2 = method2; |
|
760 } |
|
761 |
|
762 MethodHandle guardWithTest(final MethodHandle test) { |
|
763 return MethodHandles.guardWithTest(test, method1, method2); |
|
764 } |
|
765 } |
|
766 |
|
767 static MethodPair matchReturnTypes(final MethodHandle m1, final MethodHandle m2) { |
|
768 final MethodType type1 = m1.type(); |
|
769 final MethodType type2 = m2.type(); |
|
770 final Class<?> commonRetType = InternalTypeUtilities.getCommonLosslessConversionType(type1.returnType(), |
|
771 type2.returnType()); |
|
772 return new MethodPair( |
|
773 m1.asType(type1.changeReturnType(commonRetType)), |
|
774 m2.asType(type2.changeReturnType(commonRetType))); |
|
775 } |
|
776 |
|
777 private static void assertParameterCount(final CallSiteDescriptor descriptor, final int paramCount) { |
|
778 if(descriptor.getMethodType().parameterCount() != paramCount) { |
|
779 throw new BootstrapMethodError(descriptor.getOperation() + " must have exactly " + paramCount + " parameters."); |
|
780 } |
|
781 } |
|
782 |
|
783 private static MethodHandle GET_PROPERTY_GETTER_HANDLE = MethodHandles.dropArguments(privateLookup.findOwnSpecial( |
|
784 "getPropertyGetterHandle", Object.class, Object.class), 1, Object.class); |
|
785 private final MethodHandle getPropertyGetterHandle = GET_PROPERTY_GETTER_HANDLE.bindTo(this); |
|
786 |
|
787 /** |
|
788 * @param id the property ID |
|
789 * @return the method handle for retrieving the property, or null if the property does not exist |
|
790 */ |
|
791 @SuppressWarnings("unused") |
|
792 private Object getPropertyGetterHandle(final Object id) { |
|
793 return propertyGetters.get(id); |
|
794 } |
|
795 |
|
796 // Type is MethodHandle(BeanLinker, MethodType, LinkerServices, Object, String, Object), of which the two "Object" |
|
797 // args are dropped; this makes handles with first three args conform to "Object, String, Object" though, which is |
|
798 // a typical property setter with variable name signature (target, name, value). |
|
799 private static final MethodHandle GET_PROPERTY_SETTER_HANDLE = MethodHandles.dropArguments(MethodHandles.dropArguments( |
|
800 privateLookup.findOwnSpecial("getPropertySetterHandle", MethodHandle.class, CallSiteDescriptor.class, |
|
801 LinkerServices.class, Object.class), 3, Object.class), 5, Object.class); |
|
802 // Type is MethodHandle(MethodType, LinkerServices, Object, String, Object) |
|
803 private final MethodHandle getPropertySetterHandle = GET_PROPERTY_SETTER_HANDLE.bindTo(this); |
|
804 |
|
805 @SuppressWarnings("unused") |
|
806 private MethodHandle getPropertySetterHandle(final CallSiteDescriptor setterDescriptor, final LinkerServices linkerServices, |
|
807 final Object id) { |
|
808 return getDynamicMethodInvocation(setterDescriptor, linkerServices, String.valueOf(id), propertySetters); |
|
809 } |
|
810 |
|
811 private static MethodHandle GET_DYNAMIC_METHOD = MethodHandles.dropArguments(privateLookup.findOwnSpecial( |
|
812 "getDynamicMethod", Object.class, Object.class), 1, Object.class); |
|
813 private final MethodHandle getDynamicMethod = GET_DYNAMIC_METHOD.bindTo(this); |
|
814 |
|
815 @SuppressWarnings("unused") |
|
816 // This method is marked to return Object instead of DynamicMethod as it's used as a linking component and we don't |
|
817 // want to make the DynamicMethod type observable externally (e.g. as the return type of a MethodHandle returned for |
|
818 // GET_METHOD linking). |
|
819 private Object getDynamicMethod(final Object name) { |
|
820 return getDynamicMethod(String.valueOf(name), methods); |
|
821 } |
|
822 |
|
823 /** |
|
824 * Returns a dynamic method of the specified name. |
|
825 * |
|
826 * @param name name of the method |
|
827 * @return the dynamic method (either {@link SimpleDynamicMethod} or {@link OverloadedDynamicMethod}, or null if the |
|
828 * method with the specified name does not exist. |
|
829 */ |
|
830 DynamicMethod getDynamicMethod(final String name) { |
|
831 return getDynamicMethod(name, methods); |
|
832 } |
|
833 |
|
834 /** |
|
835 * Find the most generic superclass that declares this getter. Since getters have zero args (aside from the |
|
836 * receiver), they can't be overloaded, so we're free to link with an instanceof guard for the most generic one, |
|
837 * creating more stable call sites. |
|
838 * @param getter the getter |
|
839 * @return getter with same name, declared on the most generic superclass/interface of the declaring class |
|
840 */ |
|
841 private static Method getMostGenericGetter(final Method getter) { |
|
842 return getMostGenericGetter(getter.getName(), getter.getReturnType(), getter.getDeclaringClass()); |
|
843 } |
|
844 |
|
845 private static Method getMostGenericGetter(final String name, final Class<?> returnType, final Class<?> declaringClass) { |
|
846 if(declaringClass == null) { |
|
847 return null; |
|
848 } |
|
849 // Prefer interfaces |
|
850 for(final Class<?> itf: declaringClass.getInterfaces()) { |
|
851 final Method itfGetter = getMostGenericGetter(name, returnType, itf); |
|
852 if(itfGetter != null) { |
|
853 return itfGetter; |
|
854 } |
|
855 } |
|
856 final Method superGetter = getMostGenericGetter(name, returnType, declaringClass.getSuperclass()); |
|
857 if(superGetter != null) { |
|
858 return superGetter; |
|
859 } |
|
860 if(!CheckRestrictedPackage.isRestrictedClass(declaringClass)) { |
|
861 try { |
|
862 return declaringClass.getMethod(name); |
|
863 } catch(final NoSuchMethodException e) { |
|
864 // Intentionally ignored, meant to fall through |
|
865 } |
|
866 } |
|
867 return null; |
|
868 } |
|
869 |
|
870 private static final class AnnotatedDynamicMethod { |
|
871 private final SingleDynamicMethod method; |
|
872 /*private*/ final ValidationType validationType; |
|
873 |
|
874 AnnotatedDynamicMethod(final SingleDynamicMethod method, final ValidationType validationType) { |
|
875 this.method = method; |
|
876 this.validationType = validationType; |
|
877 } |
|
878 |
|
879 MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) { |
|
880 return method.getInvocation(callSiteDescriptor, linkerServices); |
|
881 } |
|
882 |
|
883 @SuppressWarnings("unused") |
|
884 MethodHandle getTarget(final CallSiteDescriptor desc, final LinkerServices linkerServices) { |
|
885 final MethodHandle inv = linkerServices.filterInternalObjects(method.getTarget(desc)); |
|
886 assert inv != null; |
|
887 return inv; |
|
888 } |
|
889 } |
|
890 } |
|