AbstractJavaLinker.java revision 1551:f3b883bec2d0
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
84package jdk.dynalink.beans;
85
86import java.lang.invoke.MethodHandle;
87import java.lang.invoke.MethodHandles;
88import java.lang.invoke.MethodType;
89import java.lang.reflect.AccessibleObject;
90import java.lang.reflect.Constructor;
91import java.lang.reflect.Field;
92import java.lang.reflect.Member;
93import java.lang.reflect.Method;
94import java.lang.reflect.Modifier;
95import java.util.Arrays;
96import java.util.Collections;
97import java.util.HashMap;
98import java.util.List;
99import java.util.Map;
100import java.util.Set;
101import jdk.dynalink.CallSiteDescriptor;
102import jdk.dynalink.CompositeOperation;
103import jdk.dynalink.NamedOperation;
104import jdk.dynalink.Operation;
105import jdk.dynalink.StandardOperation;
106import jdk.dynalink.beans.GuardedInvocationComponent.ValidationType;
107import jdk.dynalink.internal.InternalTypeUtilities;
108import jdk.dynalink.linker.GuardedInvocation;
109import jdk.dynalink.linker.GuardingDynamicLinker;
110import jdk.dynalink.linker.LinkRequest;
111import jdk.dynalink.linker.LinkerServices;
112import jdk.dynalink.linker.support.Guards;
113import jdk.dynalink.linker.support.Lookup;
114import 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 */
120abstract 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}
891