Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-aarch32-jdk8u
Path: blob/jdk8u272-b10-aarch32-20201026/nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java
48797 views
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.Collection;
96
import java.util.Collections;
97
import java.util.HashMap;
98
import java.util.List;
99
import java.util.Map;
100
import jdk.internal.dynalink.CallSiteDescriptor;
101
import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType;
102
import jdk.internal.dynalink.linker.GuardedInvocation;
103
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
104
import jdk.internal.dynalink.linker.LinkRequest;
105
import jdk.internal.dynalink.linker.LinkerServices;
106
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
107
import jdk.internal.dynalink.support.Guards;
108
import jdk.internal.dynalink.support.Lookup;
109
import jdk.internal.dynalink.support.TypeUtilities;
110
111
/**
112
* A base class for both {@link StaticClassLinker} and {@link BeanLinker}. Deals with common aspects of property
113
* exposure and method calls for both static and instance facets of a class.
114
*
115
* @author Attila Szegedi
116
*/
117
abstract class AbstractJavaLinker implements GuardingDynamicLinker {
118
119
final Class<?> clazz;
120
private final MethodHandle classGuard;
121
private final MethodHandle assignableGuard;
122
private final Map<String, AnnotatedDynamicMethod> propertyGetters = new HashMap<>();
123
private final Map<String, DynamicMethod> propertySetters = new HashMap<>();
124
private final Map<String, DynamicMethod> methods = new HashMap<>();
125
126
AbstractJavaLinker(final Class<?> clazz, final MethodHandle classGuard) {
127
this(clazz, classGuard, classGuard);
128
}
129
130
AbstractJavaLinker(final Class<?> clazz, final MethodHandle classGuard, final MethodHandle assignableGuard) {
131
this.clazz = clazz;
132
this.classGuard = classGuard;
133
this.assignableGuard = assignableGuard;
134
135
final FacetIntrospector introspector = createFacetIntrospector();
136
// Add methods and properties
137
for(final Method method: introspector.getMethods()) {
138
final String name = method.getName();
139
// Add method
140
addMember(name, method, methods);
141
// Add the method as a property getter and/or setter
142
if(name.startsWith("get") && name.length() > 3 && method.getParameterTypes().length == 0) {
143
// Property getter
144
setPropertyGetter(method, 3);
145
} else if(name.startsWith("is") && name.length() > 2 && method.getParameterTypes().length == 0 &&
146
method.getReturnType() == boolean.class) {
147
// Boolean property getter
148
setPropertyGetter(method, 2);
149
} else if(name.startsWith("set") && name.length() > 3 && method.getParameterTypes().length == 1) {
150
// Property setter
151
addMember(decapitalize(name.substring(3)), method, propertySetters);
152
}
153
}
154
155
// Add field getter/setters as property getters/setters.
156
for(final Field field: introspector.getFields()) {
157
final String name = field.getName();
158
// Only add a property getter when one is not defined already as a getXxx()/isXxx() method.
159
if(!propertyGetters.containsKey(name)) {
160
setPropertyGetter(name, introspector.unreflectGetter(field), ValidationType.EXACT_CLASS);
161
}
162
if(!(Modifier.isFinal(field.getModifiers()) || propertySetters.containsKey(name))) {
163
addMember(name, new SimpleDynamicMethod(introspector.unreflectSetter(field), clazz, name),
164
propertySetters);
165
}
166
}
167
168
// Add inner classes, but only those for which we don't hide a property with it
169
for(final Map.Entry<String, MethodHandle> innerClassSpec: introspector.getInnerClassGetters().entrySet()) {
170
final String name = innerClassSpec.getKey();
171
if(!propertyGetters.containsKey(name)) {
172
setPropertyGetter(name, innerClassSpec.getValue(), ValidationType.EXACT_CLASS);
173
}
174
}
175
}
176
177
private static String decapitalize(final String str) {
178
assert str != null;
179
if(str.isEmpty()) {
180
return str;
181
}
182
183
final char c0 = str.charAt(0);
184
if(Character.isLowerCase(c0)) {
185
return str;
186
}
187
188
// If it has two consecutive upper-case characters, i.e. "URL", don't decapitalize
189
if(str.length() > 1 && Character.isUpperCase(str.charAt(1))) {
190
return str;
191
}
192
193
final char c[] = str.toCharArray();
194
c[0] = Character.toLowerCase(c0);
195
return new String(c);
196
}
197
198
abstract FacetIntrospector createFacetIntrospector();
199
200
Collection<String> getReadablePropertyNames() {
201
return getUnmodifiableKeys(propertyGetters);
202
}
203
204
Collection<String> getWritablePropertyNames() {
205
return getUnmodifiableKeys(propertySetters);
206
}
207
208
Collection<String> getMethodNames() {
209
return getUnmodifiableKeys(methods);
210
}
211
212
private static Collection<String> getUnmodifiableKeys(final Map<String, ?> m) {
213
return Collections.unmodifiableCollection(m.keySet());
214
}
215
216
/**
217
* Sets the specified dynamic method to be the property getter for the specified property. Note that you can only
218
* use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties
219
* that are caller-sensitive, you must use {@link #setPropertyGetter(String, SingleDynamicMethod, ValidationType)}
220
* instead.
221
* @param name name of the property
222
* @param handle the method handle that implements the property getter
223
* @param validationType the validation type for the property
224
*/
225
private void setPropertyGetter(final String name, final SingleDynamicMethod handle, final ValidationType validationType) {
226
propertyGetters.put(name, new AnnotatedDynamicMethod(handle, validationType));
227
}
228
229
/**
230
* Sets the specified reflective method to be the property getter for the specified property.
231
* @param getter the getter method
232
* @param prefixLen the getter prefix in the method name; should be 3 for getter names starting with "get" and 2 for
233
* names starting with "is".
234
*/
235
private void setPropertyGetter(final Method getter, final int prefixLen) {
236
setPropertyGetter(decapitalize(getter.getName().substring(prefixLen)), createDynamicMethod(
237
getMostGenericGetter(getter)), ValidationType.INSTANCE_OF);
238
}
239
240
/**
241
* Sets the specified method handle to be the property getter for the specified property. Note that you can only
242
* use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties
243
* that are caller-sensitive, you must use {@link #setPropertyGetter(String, SingleDynamicMethod, ValidationType)}
244
* instead.
245
* @param name name of the property
246
* @param handle the method handle that implements the property getter
247
* @param validationType the validation type for the property
248
*/
249
void setPropertyGetter(final String name, final MethodHandle handle, final ValidationType validationType) {
250
setPropertyGetter(name, new SimpleDynamicMethod(handle, clazz, name), validationType);
251
}
252
253
private void addMember(final String name, final AccessibleObject ao, final Map<String, DynamicMethod> methodMap) {
254
addMember(name, createDynamicMethod(ao), methodMap);
255
}
256
257
private void addMember(final String name, final SingleDynamicMethod method, final Map<String, DynamicMethod> methodMap) {
258
final DynamicMethod existingMethod = methodMap.get(name);
259
final DynamicMethod newMethod = mergeMethods(method, existingMethod, clazz, name);
260
if(newMethod != existingMethod) {
261
methodMap.put(name, newMethod);
262
}
263
}
264
265
/**
266
* Given one or more reflective methods or constructors, creates a dynamic method that represents them all. The
267
* methods should represent all overloads of the same name (or all constructors of the class).
268
* @param members the reflective members
269
* @param clazz the class declaring the reflective members
270
* @param name the common name of the reflective members.
271
* @return a dynamic method representing all the specified reflective members.
272
*/
273
static DynamicMethod createDynamicMethod(final Iterable<? extends AccessibleObject> members, final Class<?> clazz, final String name) {
274
DynamicMethod dynMethod = null;
275
for(final AccessibleObject method: members) {
276
dynMethod = mergeMethods(createDynamicMethod(method), dynMethod, clazz, name);
277
}
278
return dynMethod;
279
}
280
281
/**
282
* Given a reflective method or a constructor, creates a dynamic method that represents it. This method will
283
* distinguish between caller sensitive and ordinary methods/constructors, and create appropriate caller sensitive
284
* dynamic method when needed.
285
* @param m the reflective member
286
* @return the single dynamic method representing the reflective member
287
*/
288
private static SingleDynamicMethod createDynamicMethod(final AccessibleObject m) {
289
if(CallerSensitiveDetector.isCallerSensitive(m)) {
290
// Method has @CallerSensitive annotation
291
return new CallerSensitiveDynamicMethod(m);
292
}
293
// Method has no @CallerSensitive annotation
294
final MethodHandle mh;
295
try {
296
mh = unreflectSafely(m);
297
} catch (final IllegalAccessError e) {
298
// java.lang.invoke can in some case conservatively treat as caller sensitive methods that aren't
299
// marked with the annotation. In this case, we'll fall back to treating it as caller sensitive.
300
return new CallerSensitiveDynamicMethod(m);
301
}
302
// Proceed with non-caller sensitive
303
final Member member = (Member)m;
304
return new SimpleDynamicMethod(mh, member.getDeclaringClass(), member.getName(), m instanceof Constructor);
305
}
306
307
/**
308
* Unreflects a method handle from a Method or a Constructor using safe (zero-privilege) unreflection. Should be
309
* only used for methods and constructors that are not caller sensitive. If a caller sensitive method were
310
* unreflected through this mechanism, it would not be a security issue, but would be bound to the zero-privilege
311
* unreflector as its caller, and thus completely useless.
312
* @param m the method or constructor
313
* @return the method handle
314
*/
315
private static MethodHandle unreflectSafely(final AccessibleObject m) {
316
if(m instanceof Method) {
317
final Method reflMethod = (Method)m;
318
final MethodHandle handle = Lookup.PUBLIC.unreflect(reflMethod);
319
if(Modifier.isStatic(reflMethod.getModifiers())) {
320
return StaticClassIntrospector.editStaticMethodHandle(handle);
321
}
322
return handle;
323
}
324
return StaticClassIntrospector.editConstructorMethodHandle(Lookup.PUBLIC.unreflectConstructor((Constructor<?>)m));
325
}
326
327
private static DynamicMethod mergeMethods(final SingleDynamicMethod method, final DynamicMethod existing, final Class<?> clazz, final String name) {
328
if(existing == null) {
329
return method;
330
} else if(existing.contains(method)) {
331
return existing;
332
} else if(existing instanceof SingleDynamicMethod) {
333
final OverloadedDynamicMethod odm = new OverloadedDynamicMethod(clazz, name);
334
odm.addMethod(((SingleDynamicMethod)existing));
335
odm.addMethod(method);
336
return odm;
337
} else if(existing instanceof OverloadedDynamicMethod) {
338
((OverloadedDynamicMethod)existing).addMethod(method);
339
return existing;
340
}
341
throw new AssertionError();
342
}
343
344
@Override
345
public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices)
346
throws Exception {
347
final LinkRequest ncrequest = request.withoutRuntimeContext();
348
// BeansLinker already checked that the name is at least 2 elements long and the first element is "dyn".
349
final CallSiteDescriptor callSiteDescriptor = ncrequest.getCallSiteDescriptor();
350
final String op = callSiteDescriptor.getNameToken(CallSiteDescriptor.OPERATOR);
351
// Either dyn:callMethod:name(this[,args]) or dyn:callMethod(this,name[,args]).
352
if("callMethod" == op) {
353
return getCallPropWithThis(callSiteDescriptor, linkerServices);
354
}
355
List<String> operations = CallSiteDescriptorFactory.tokenizeOperators(callSiteDescriptor);
356
while(!operations.isEmpty()) {
357
final GuardedInvocationComponent gic = getGuardedInvocationComponent(callSiteDescriptor, linkerServices,
358
operations);
359
if(gic != null) {
360
return gic.getGuardedInvocation();
361
}
362
operations = pop(operations);
363
}
364
return null;
365
}
366
367
protected GuardedInvocationComponent getGuardedInvocationComponent(final CallSiteDescriptor callSiteDescriptor,
368
final LinkerServices linkerServices, final List<String> operations) throws Exception {
369
if(operations.isEmpty()) {
370
return null;
371
}
372
final String op = operations.get(0);
373
// Either dyn:getProp:name(this) or dyn:getProp(this, name)
374
if("getProp".equals(op)) {
375
return getPropertyGetter(callSiteDescriptor, linkerServices, pop(operations));
376
}
377
// Either dyn:setProp:name(this, value) or dyn:setProp(this, name, value)
378
if("setProp".equals(op)) {
379
return getPropertySetter(callSiteDescriptor, linkerServices, pop(operations));
380
}
381
// Either dyn:getMethod:name(this), or dyn:getMethod(this, name)
382
if("getMethod".equals(op)) {
383
return getMethodGetter(callSiteDescriptor, linkerServices, pop(operations));
384
}
385
return null;
386
}
387
388
static final <T> List<T> pop(final List<T> l) {
389
return l.subList(1, l.size());
390
}
391
392
MethodHandle getClassGuard(final CallSiteDescriptor desc) {
393
return getClassGuard(desc.getMethodType());
394
}
395
396
MethodHandle getClassGuard(final MethodType type) {
397
return Guards.asType(classGuard, type);
398
}
399
400
GuardedInvocationComponent getClassGuardedInvocationComponent(final MethodHandle invocation, final MethodType type) {
401
return new GuardedInvocationComponent(invocation, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
402
}
403
404
SingleDynamicMethod getConstructorMethod(final String signature) {
405
return null;
406
}
407
408
private MethodHandle getAssignableGuard(final MethodType type) {
409
return Guards.asType(assignableGuard, type);
410
}
411
412
private GuardedInvocation getCallPropWithThis(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) {
413
switch(callSiteDescriptor.getNameTokenCount()) {
414
case 3: {
415
return createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
416
callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), methods);
417
}
418
default: {
419
return null;
420
}
421
}
422
}
423
424
private GuardedInvocation createGuardedDynamicMethodInvocation(final CallSiteDescriptor callSiteDescriptor,
425
final LinkerServices linkerServices, final String methodName, final Map<String, DynamicMethod> methodMap){
426
final MethodHandle inv = getDynamicMethodInvocation(callSiteDescriptor, linkerServices, methodName, methodMap);
427
return inv == null ? null : new GuardedInvocation(inv, getClassGuard(callSiteDescriptor.getMethodType()));
428
}
429
430
private MethodHandle getDynamicMethodInvocation(final CallSiteDescriptor callSiteDescriptor,
431
final LinkerServices linkerServices, final String methodName, final Map<String, DynamicMethod> methodMap) {
432
final DynamicMethod dynaMethod = getDynamicMethod(methodName, methodMap);
433
return dynaMethod != null ? dynaMethod.getInvocation(callSiteDescriptor, linkerServices) : null;
434
}
435
436
private DynamicMethod getDynamicMethod(final String methodName, final Map<String, DynamicMethod> methodMap) {
437
final DynamicMethod dynaMethod = methodMap.get(methodName);
438
return dynaMethod != null ? dynaMethod : getExplicitSignatureDynamicMethod(methodName, methodMap);
439
}
440
441
private SingleDynamicMethod getExplicitSignatureDynamicMethod(final String fullName,
442
final Map<String, DynamicMethod> methodsMap) {
443
// What's below is meant to support the "name(type, type, ...)" syntax that programmers can use in a method name
444
// to manually pin down an exact overloaded variant. This is not usually required, as the overloaded method
445
// resolution works correctly in almost every situation. However, in presence of many language-specific
446
// conversions with a radically dynamic language, most overloaded methods will end up being constantly selected
447
// at invocation time, so a programmer knowledgeable of the situation might choose to pin down an exact overload
448
// for performance reasons.
449
450
// Is the method name lexically of the form "name(types)"?
451
final int lastChar = fullName.length() - 1;
452
if(fullName.charAt(lastChar) != ')') {
453
return null;
454
}
455
final int openBrace = fullName.indexOf('(');
456
if(openBrace == -1) {
457
return null;
458
}
459
460
final String name = fullName.substring(0, openBrace);
461
final String signature = fullName.substring(openBrace + 1, lastChar);
462
463
// Find an existing method for the "name" part
464
final DynamicMethod simpleNamedMethod = methodsMap.get(name);
465
if(simpleNamedMethod == null) {
466
// explicit signature constructor access
467
// Java.type("java.awt.Color")["(int,int,int)"]
468
// will get Color(int,int,int) constructor of Color class.
469
if (name.isEmpty()) {
470
return getConstructorMethod(signature);
471
}
472
473
return null;
474
}
475
476
// Try to get a narrowed dynamic method for the explicit parameter types.
477
return simpleNamedMethod.getMethodForExactParamTypes(signature);
478
}
479
480
private static final MethodHandle IS_METHOD_HANDLE_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType(
481
boolean.class, MethodHandle.class));
482
private static final MethodHandle CONSTANT_NULL_DROP_METHOD_HANDLE = MethodHandles.dropArguments(
483
MethodHandles.constant(Object.class, null), 0, MethodHandle.class);
484
485
private GuardedInvocationComponent getPropertySetter(final CallSiteDescriptor callSiteDescriptor,
486
final LinkerServices linkerServices, final List<String> operations) throws Exception {
487
switch(callSiteDescriptor.getNameTokenCount()) {
488
case 2: {
489
// Must have three arguments: target object, property name, and property value.
490
assertParameterCount(callSiteDescriptor, 3);
491
492
// We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be
493
// valid for us to convert return values proactively. Also, since we don't know what setters will be
494
// invoked, we'll conservatively presume Object return type. The one exception is void return.
495
final MethodType origType = callSiteDescriptor.getMethodType();
496
final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class);
497
498
// What's below is basically:
499
// foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
500
// get_setter_handle(type, linkerServices))
501
// only with a bunch of method signature adjustments. Basically, retrieve method setter
502
// MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next
503
// component's invocation.
504
505
// Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll
506
// abbreviate to R(O, N, V) going forward, although we don't really use R here (see above about using
507
// Object return type).
508
final MethodType setterType = type.dropParameterTypes(1, 2);
509
// Bind property setter handle to the expected setter type and linker services. Type is
510
// MethodHandle(Object, String, Object)
511
final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
512
callSiteDescriptor.changeMethodType(setterType), linkerServices);
513
514
// Cast getter to MethodHandle(O, N, V)
515
final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
516
MethodHandle.class));
517
518
// Handle to invoke the setter R(MethodHandle, O, V)
519
final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType);
520
// Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V)
521
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType(
522
1));
523
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
524
linkerServices, operations);
525
526
final MethodHandle fallbackFolded;
527
if(nextComponent == null) {
528
// Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null
529
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
530
type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
531
} else {
532
// Object(O, N, V)->Object(MethodHandle, O, N, V); adapts the next component's invocation to drop the
533
// extra argument resulting from fold
534
fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
535
0, MethodHandle.class);
536
}
537
538
// fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V))
539
final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
540
IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
541
if(nextComponent == null) {
542
return getClassGuardedInvocationComponent(compositeSetter, type);
543
}
544
return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
545
}
546
case 3: {
547
// Must have two arguments: target object and property value
548
assertParameterCount(callSiteDescriptor, 2);
549
final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
550
callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), propertySetters);
551
// If we have a property setter with this name, this composite operation will always stop here
552
if(gi != null) {
553
return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
554
}
555
// If we don't have a property setter with this name, always fall back to the next operation in the
556
// composite (if any)
557
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations);
558
}
559
default: {
560
// More than two name components; don't know what to do with it.
561
return null;
562
}
563
}
564
}
565
566
private static final Lookup privateLookup = new Lookup(MethodHandles.lookup());
567
568
private static final MethodHandle IS_ANNOTATED_METHOD_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType(
569
boolean.class, AnnotatedDynamicMethod.class));
570
private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_METHOD = MethodHandles.dropArguments(
571
MethodHandles.constant(Object.class, null), 0, AnnotatedDynamicMethod.class);
572
private static final MethodHandle GET_ANNOTATED_METHOD = privateLookup.findVirtual(AnnotatedDynamicMethod.class,
573
"getTarget", MethodType.methodType(MethodHandle.class, MethodHandles.Lookup.class, LinkerServices.class));
574
private static final MethodHandle GETTER_INVOKER = MethodHandles.invoker(MethodType.methodType(Object.class, Object.class));
575
576
private GuardedInvocationComponent getPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
577
final LinkerServices linkerServices, final List<String> ops) throws Exception {
578
switch(callSiteDescriptor.getNameTokenCount()) {
579
case 2: {
580
// Since we can't know what kind of a getter we'll get back on different invocations, we'll just
581
// conservatively presume Object. Note we can't just coerce to a narrower call site type as the linking
582
// runtime might not allow coercing at that call site.
583
final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class);
584
// Must have exactly two arguments: receiver and name
585
assertParameterCount(callSiteDescriptor, 2);
586
587
// What's below is basically:
588
// foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle)
589
// only with a bunch of method signature adjustments. Basically, retrieve method getter
590
// AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null,
591
// or delegate to next component's invocation.
592
593
final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType(
594
AnnotatedDynamicMethod.class));
595
final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments(
596
GET_ANNOTATED_METHOD, 1, callSiteDescriptor.getLookup(), linkerServices);
597
final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0,
598
callSiteBoundMethodGetter);
599
// Object(AnnotatedDynamicMethod, Object)->Object(AnnotatedDynamicMethod, T0)
600
final MethodHandle invokeHandleTyped = linkerServices.asType(callSiteBoundInvoker,
601
MethodType.methodType(type.returnType(), AnnotatedDynamicMethod.class, type.parameterType(0)));
602
// Since it's in the target of a fold, drop the unnecessary second argument
603
// Object(AnnotatedDynamicMethod, T0)->Object(AnnotatedDynamicMethod, T0, T1)
604
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2,
605
type.parameterType(1));
606
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
607
linkerServices, ops);
608
609
final MethodHandle fallbackFolded;
610
if(nextComponent == null) {
611
// Object(AnnotatedDynamicMethod)->Object(AnnotatedDynamicMethod, T0, T1); returns constant null
612
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_METHOD, 1,
613
type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedDynamicMethod.class));
614
} else {
615
// Object(T0, T1)->Object(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to
616
// drop the extra argument resulting from fold and to change its return type to Object.
617
final MethodHandle nextInvocation = nextComponent.getGuardedInvocation().getInvocation();
618
final MethodType nextType = nextInvocation.type();
619
fallbackFolded = MethodHandles.dropArguments(nextInvocation.asType(
620
nextType.changeReturnType(Object.class)), 0, AnnotatedDynamicMethod.class);
621
}
622
623
// fold(Object(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1))
624
final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
625
IS_ANNOTATED_METHOD_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
626
if(nextComponent == null) {
627
return getClassGuardedInvocationComponent(compositeGetter, type);
628
}
629
return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
630
}
631
case 3: {
632
// Must have exactly one argument: receiver
633
assertParameterCount(callSiteDescriptor, 1);
634
// Fixed name
635
final AnnotatedDynamicMethod annGetter = propertyGetters.get(callSiteDescriptor.getNameToken(
636
CallSiteDescriptor.NAME_OPERAND));
637
if(annGetter == null) {
638
// We have no such property, always delegate to the next component operation
639
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops);
640
}
641
final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices);
642
// NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being
643
// overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the
644
// method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If
645
// we're linking against a field getter, don't make the assumption.
646
// NOTE: No delegation to the next component operation if we have a property with this name, even if its
647
// value is null.
648
final ValidationType validationType = annGetter.validationType;
649
// TODO: we aren't using the type that declares the most generic getter here!
650
return new GuardedInvocationComponent(getter, getGuard(validationType,
651
callSiteDescriptor.getMethodType()), clazz, validationType);
652
}
653
default: {
654
// Can't do anything with more than 3 name components
655
return null;
656
}
657
}
658
}
659
660
private MethodHandle getGuard(final ValidationType validationType, final MethodType methodType) {
661
switch(validationType) {
662
case EXACT_CLASS: {
663
return getClassGuard(methodType);
664
}
665
case INSTANCE_OF: {
666
return getAssignableGuard(methodType);
667
}
668
case IS_ARRAY: {
669
return Guards.isArray(0, methodType);
670
}
671
case NONE: {
672
return null;
673
}
674
default: {
675
throw new AssertionError();
676
}
677
}
678
}
679
680
private static final MethodHandle IS_DYNAMIC_METHOD = Guards.isInstance(DynamicMethod.class,
681
MethodType.methodType(boolean.class, Object.class));
682
private static final MethodHandle OBJECT_IDENTITY = MethodHandles.identity(Object.class);
683
684
private GuardedInvocationComponent getMethodGetter(final CallSiteDescriptor callSiteDescriptor,
685
final LinkerServices linkerServices, final List<String> ops) throws Exception {
686
// The created method handle will always return a DynamicMethod (or null), but since we don't want that type to
687
// be visible outside of this linker, declare it to return Object.
688
final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class);
689
switch(callSiteDescriptor.getNameTokenCount()) {
690
case 2: {
691
// Must have exactly two arguments: receiver and name
692
assertParameterCount(callSiteDescriptor, 2);
693
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
694
linkerServices, ops);
695
if(nextComponent == null || !TypeUtilities.areAssignable(DynamicMethod.class,
696
nextComponent.getGuardedInvocation().getInvocation().type().returnType())) {
697
// No next component operation, or it can never produce a dynamic method; just return a component
698
// for this operation.
699
return getClassGuardedInvocationComponent(linkerServices.asType(getDynamicMethod, type), type);
700
}
701
702
// What's below is basically:
703
// foldArguments(guardWithTest(isNotNull, identity, nextComponent.invocation), getter) only with a
704
// bunch of method signature adjustments. Basically, execute method getter; if it returns a non-null
705
// DynamicMethod, use identity to return it, otherwise delegate to nextComponent's invocation.
706
707
final MethodHandle typedGetter = linkerServices.asType(getDynamicMethod, type);
708
// Since it is part of the foldArgument() target, it will have extra args that we need to drop.
709
final MethodHandle returnMethodHandle = linkerServices.asType(MethodHandles.dropArguments(
710
OBJECT_IDENTITY, 1, type.parameterList()), type.insertParameterTypes(0, Object.class));
711
final MethodHandle nextComponentInvocation = nextComponent.getGuardedInvocation().getInvocation();
712
// The assumption is that getGuardedInvocationComponent() already asType()'d it correctly modulo the
713
// return type.
714
assert nextComponentInvocation.type().changeReturnType(type.returnType()).equals(type);
715
// Since it is part of the foldArgument() target, we have to drop an extra arg it receives.
716
final MethodHandle nextCombinedInvocation = MethodHandles.dropArguments(nextComponentInvocation, 0,
717
Object.class);
718
// Assemble it all into a fold(guard(isNotNull, identity, nextInvocation), get)
719
final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
720
IS_DYNAMIC_METHOD, returnMethodHandle, nextCombinedInvocation), typedGetter);
721
722
return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
723
}
724
case 3: {
725
// Must have exactly one argument: receiver
726
assertParameterCount(callSiteDescriptor, 1);
727
final DynamicMethod method = getDynamicMethod(callSiteDescriptor.getNameToken(
728
CallSiteDescriptor.NAME_OPERAND));
729
if(method == null) {
730
// We have no such method, always delegate to the next component
731
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops);
732
}
733
// No delegation to the next component of the composite operation; if we have a method with that name,
734
// we'll always return it at this point.
735
return getClassGuardedInvocationComponent(linkerServices.asType(MethodHandles.dropArguments(
736
MethodHandles.constant(Object.class, method), 0, type.parameterType(0)), type), type);
737
}
738
default: {
739
// Can't do anything with more than 3 name components
740
return null;
741
}
742
}
743
}
744
745
static class MethodPair {
746
final MethodHandle method1;
747
final MethodHandle method2;
748
749
MethodPair(final MethodHandle method1, final MethodHandle method2) {
750
this.method1 = method1;
751
this.method2 = method2;
752
}
753
754
MethodHandle guardWithTest(final MethodHandle test) {
755
return MethodHandles.guardWithTest(test, method1, method2);
756
}
757
}
758
759
static MethodPair matchReturnTypes(final MethodHandle m1, final MethodHandle m2) {
760
final MethodType type1 = m1.type();
761
final MethodType type2 = m2.type();
762
final Class<?> commonRetType = TypeUtilities.getCommonLosslessConversionType(type1.returnType(),
763
type2.returnType());
764
return new MethodPair(
765
m1.asType(type1.changeReturnType(commonRetType)),
766
m2.asType(type2.changeReturnType(commonRetType)));
767
}
768
769
private static void assertParameterCount(final CallSiteDescriptor descriptor, final int paramCount) {
770
if(descriptor.getMethodType().parameterCount() != paramCount) {
771
throw new BootstrapMethodError(descriptor.getName() + " must have exactly " + paramCount + " parameters.");
772
}
773
}
774
775
private static MethodHandle GET_PROPERTY_GETTER_HANDLE = MethodHandles.dropArguments(privateLookup.findOwnSpecial(
776
"getPropertyGetterHandle", Object.class, Object.class), 1, Object.class);
777
private final MethodHandle getPropertyGetterHandle = GET_PROPERTY_GETTER_HANDLE.bindTo(this);
778
779
/**
780
* @param id the property ID
781
* @return the method handle for retrieving the property, or null if the property does not exist
782
*/
783
@SuppressWarnings("unused")
784
private Object getPropertyGetterHandle(final Object id) {
785
return propertyGetters.get(String.valueOf(id));
786
}
787
788
// Type is MethodHandle(BeanLinker, MethodType, LinkerServices, Object, String, Object), of which the two "Object"
789
// args are dropped; this makes handles with first three args conform to "Object, String, Object" though, which is
790
// a typical property setter with variable name signature (target, name, value).
791
private static final MethodHandle GET_PROPERTY_SETTER_HANDLE = MethodHandles.dropArguments(MethodHandles.dropArguments(
792
privateLookup.findOwnSpecial("getPropertySetterHandle", MethodHandle.class, CallSiteDescriptor.class,
793
LinkerServices.class, Object.class), 3, Object.class), 5, Object.class);
794
// Type is MethodHandle(MethodType, LinkerServices, Object, String, Object)
795
private final MethodHandle getPropertySetterHandle = GET_PROPERTY_SETTER_HANDLE.bindTo(this);
796
797
@SuppressWarnings("unused")
798
private MethodHandle getPropertySetterHandle(final CallSiteDescriptor setterDescriptor, final LinkerServices linkerServices,
799
final Object id) {
800
return getDynamicMethodInvocation(setterDescriptor, linkerServices, String.valueOf(id), propertySetters);
801
}
802
803
private static MethodHandle GET_DYNAMIC_METHOD = MethodHandles.dropArguments(privateLookup.findOwnSpecial(
804
"getDynamicMethod", Object.class, Object.class), 1, Object.class);
805
private final MethodHandle getDynamicMethod = GET_DYNAMIC_METHOD.bindTo(this);
806
807
@SuppressWarnings("unused")
808
// This method is marked to return Object instead of DynamicMethod as it's used as a linking component and we don't
809
// want to make the DynamicMethod type observable externally (e.g. as the return type of a MethodHandle returned for
810
// "dyn:getMethod" linking).
811
private Object getDynamicMethod(final Object name) {
812
return getDynamicMethod(String.valueOf(name), methods);
813
}
814
815
/**
816
* Returns a dynamic method of the specified name.
817
*
818
* @param name name of the method
819
* @return the dynamic method (either {@link SimpleDynamicMethod} or {@link OverloadedDynamicMethod}, or null if the
820
* method with the specified name does not exist.
821
*/
822
DynamicMethod getDynamicMethod(final String name) {
823
return getDynamicMethod(name, methods);
824
}
825
826
/**
827
* Find the most generic superclass that declares this getter. Since getters have zero args (aside from the
828
* receiver), they can't be overloaded, so we're free to link with an instanceof guard for the most generic one,
829
* creating more stable call sites.
830
* @param getter the getter
831
* @return getter with same name, declared on the most generic superclass/interface of the declaring class
832
*/
833
private static Method getMostGenericGetter(final Method getter) {
834
return getMostGenericGetter(getter.getName(), getter.getReturnType(), getter.getDeclaringClass());
835
}
836
837
private static Method getMostGenericGetter(final String name, final Class<?> returnType, final Class<?> declaringClass) {
838
if(declaringClass == null) {
839
return null;
840
}
841
// Prefer interfaces
842
for(final Class<?> itf: declaringClass.getInterfaces()) {
843
final Method itfGetter = getMostGenericGetter(name, returnType, itf);
844
if(itfGetter != null) {
845
return itfGetter;
846
}
847
}
848
final Method superGetter = getMostGenericGetter(name, returnType, declaringClass.getSuperclass());
849
if(superGetter != null) {
850
return superGetter;
851
}
852
if(!CheckRestrictedPackage.isRestrictedClass(declaringClass)) {
853
try {
854
return declaringClass.getMethod(name);
855
} catch(final NoSuchMethodException e) {
856
// Intentionally ignored, meant to fall through
857
}
858
}
859
return null;
860
}
861
862
private static final class AnnotatedDynamicMethod {
863
private final SingleDynamicMethod method;
864
/*private*/ final ValidationType validationType;
865
866
AnnotatedDynamicMethod(final SingleDynamicMethod method, final ValidationType validationType) {
867
this.method = method;
868
this.validationType = validationType;
869
}
870
871
MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) {
872
return method.getInvocation(callSiteDescriptor, linkerServices);
873
}
874
875
@SuppressWarnings("unused")
876
MethodHandle getTarget(final MethodHandles.Lookup lookup, final LinkerServices linkerServices) {
877
final MethodHandle inv = linkerServices.filterInternalObjects(method.getTarget(lookup));
878
assert inv != null;
879
return inv;
880
}
881
}
882
}
883
884