nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java
changeset 34456 84eaea8d0574
parent 34096 5ac6287ec71a
parent 34455 cc9f05d3caf0
child 34457 81a65a2faef3
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java	Wed Jul 05 21:04:26 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,890 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file, and Oracle licenses the original version of this file under the BSD
- * license:
- */
-/*
-   Copyright 2009-2013 Attila Szegedi
-
-   Licensed under both the Apache License, Version 2.0 (the "Apache License")
-   and the BSD License (the "BSD License"), with licensee being free to
-   choose either of the two at their discretion.
-
-   You may not use this file except in compliance with either the Apache
-   License or the BSD License.
-
-   If you choose to use this file in compliance with the Apache License, the
-   following notice applies to you:
-
-       You may obtain a copy of the Apache License at
-
-           http://www.apache.org/licenses/LICENSE-2.0
-
-       Unless required by applicable law or agreed to in writing, software
-       distributed under the License is distributed on an "AS IS" BASIS,
-       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-       implied. See the License for the specific language governing
-       permissions and limitations under the License.
-
-   If you choose to use this file in compliance with the BSD License, the
-   following notice applies to you:
-
-       Redistribution and use in source and binary forms, with or without
-       modification, are permitted provided that the following conditions are
-       met:
-       * Redistributions of source code must retain the above copyright
-         notice, this list of conditions and the following disclaimer.
-       * Redistributions in binary form must reproduce the above copyright
-         notice, this list of conditions and the following disclaimer in the
-         documentation and/or other materials provided with the distribution.
-       * Neither the name of the copyright holder nor the names of
-         contributors may be used to endorse or promote products derived from
-         this software without specific prior written permission.
-
-       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-       IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-       TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-       PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
-       BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-       SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-       BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-       WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-       OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-package jdk.internal.dynalink.beans;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import java.lang.reflect.AccessibleObject;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.Member;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import jdk.internal.dynalink.CallSiteDescriptor;
-import jdk.internal.dynalink.CompositeOperation;
-import jdk.internal.dynalink.NamedOperation;
-import jdk.internal.dynalink.Operation;
-import jdk.internal.dynalink.StandardOperation;
-import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType;
-import jdk.internal.dynalink.internal.InternalTypeUtilities;
-import jdk.internal.dynalink.linker.GuardedInvocation;
-import jdk.internal.dynalink.linker.GuardingDynamicLinker;
-import jdk.internal.dynalink.linker.LinkRequest;
-import jdk.internal.dynalink.linker.LinkerServices;
-import jdk.internal.dynalink.linker.support.Guards;
-import jdk.internal.dynalink.linker.support.Lookup;
-import sun.reflect.CallerSensitive;
-
-/**
- * A base class for both {@link StaticClassLinker} and {@link BeanLinker}. Deals with common aspects of property
- * exposure and method calls for both static and instance facets of a class.
- */
-abstract class AbstractJavaLinker implements GuardingDynamicLinker {
-
-    final Class<?> clazz;
-    private final MethodHandle classGuard;
-    private final MethodHandle assignableGuard;
-    private final Map<String, AnnotatedDynamicMethod> propertyGetters = new HashMap<>();
-    private final Map<String, DynamicMethod> propertySetters = new HashMap<>();
-    private final Map<String, DynamicMethod> methods = new HashMap<>();
-
-    AbstractJavaLinker(final Class<?> clazz, final MethodHandle classGuard) {
-        this(clazz, classGuard, classGuard);
-    }
-
-    AbstractJavaLinker(final Class<?> clazz, final MethodHandle classGuard, final MethodHandle assignableGuard) {
-        this.clazz = clazz;
-        this.classGuard = classGuard;
-        this.assignableGuard = assignableGuard;
-
-        final FacetIntrospector introspector = createFacetIntrospector();
-        // Add methods and properties
-        for(final Method method: introspector.getMethods()) {
-            final String name = method.getName();
-            // Add method
-            addMember(name, method, methods);
-            // Add the method as a property getter and/or setter
-            if(name.startsWith("get") && name.length() > 3 && method.getParameterTypes().length == 0) {
-                // Property getter
-                setPropertyGetter(method, 3);
-            } else if(name.startsWith("is") && name.length() > 2 && method.getParameterTypes().length == 0 &&
-                    method.getReturnType() == boolean.class) {
-                // Boolean property getter
-                setPropertyGetter(method, 2);
-            } else if(name.startsWith("set") && name.length() > 3 && method.getParameterTypes().length == 1) {
-                // Property setter
-                addMember(decapitalize(name.substring(3)), method, propertySetters);
-            }
-        }
-
-        // Add field getter/setters as property getters/setters.
-        for(final Field field: introspector.getFields()) {
-            final String name = field.getName();
-            // Only add a property getter when one is not defined already as a getXxx()/isXxx() method.
-            if(!propertyGetters.containsKey(name)) {
-                setPropertyGetter(name, introspector.unreflectGetter(field), ValidationType.EXACT_CLASS);
-            }
-            if(!(Modifier.isFinal(field.getModifiers()) || propertySetters.containsKey(name))) {
-                addMember(name, new SimpleDynamicMethod(introspector.unreflectSetter(field), clazz, name),
-                        propertySetters);
-            }
-        }
-
-        // Add inner classes, but only those for which we don't hide a property with it
-        for(final Map.Entry<String, MethodHandle> innerClassSpec: introspector.getInnerClassGetters().entrySet()) {
-            final String name = innerClassSpec.getKey();
-            if(!propertyGetters.containsKey(name)) {
-                setPropertyGetter(name, innerClassSpec.getValue(), ValidationType.EXACT_CLASS);
-            }
-        }
-    }
-
-    private static String decapitalize(final String str) {
-        assert str != null;
-        if(str.isEmpty()) {
-            return str;
-        }
-
-        final char c0 = str.charAt(0);
-        if(Character.isLowerCase(c0)) {
-            return str;
-        }
-
-        // If it has two consecutive upper-case characters, i.e. "URL", don't decapitalize
-        if(str.length() > 1 && Character.isUpperCase(str.charAt(1))) {
-            return str;
-        }
-
-        final char c[] = str.toCharArray();
-        c[0] = Character.toLowerCase(c0);
-        return new String(c);
-    }
-
-    abstract FacetIntrospector createFacetIntrospector();
-
-    Set<String> getReadablePropertyNames() {
-        return getUnmodifiableKeys(propertyGetters);
-    }
-
-    Set<String> getWritablePropertyNames() {
-        return getUnmodifiableKeys(propertySetters);
-    }
-
-    Set<String> getMethodNames() {
-        return getUnmodifiableKeys(methods);
-    }
-
-    private static Set<String> getUnmodifiableKeys(final Map<String, ?> m) {
-        return Collections.unmodifiableSet(m.keySet());
-    }
-
-    /**
-     * Sets the specified dynamic method to be the property getter for the specified property. Note that you can only
-     * use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties
-     * that are caller-sensitive, you must use {@link #setPropertyGetter(String, SingleDynamicMethod, ValidationType)}
-     * instead.
-     * @param name name of the property
-     * @param handle the method handle that implements the property getter
-     * @param validationType the validation type for the property
-     */
-    private void setPropertyGetter(final String name, final SingleDynamicMethod handle, final ValidationType validationType) {
-        propertyGetters.put(name, new AnnotatedDynamicMethod(handle, validationType));
-    }
-
-    /**
-     * Sets the specified reflective method to be the property getter for the specified property.
-     * @param getter the getter method
-     * @param prefixLen the getter prefix in the method name; should be 3 for getter names starting with "get" and 2 for
-     * names starting with "is".
-     */
-    private void setPropertyGetter(final Method getter, final int prefixLen) {
-        setPropertyGetter(decapitalize(getter.getName().substring(prefixLen)), createDynamicMethod(
-                getMostGenericGetter(getter)), ValidationType.INSTANCE_OF);
-    }
-
-    /**
-     * Sets the specified method handle to be the property getter for the specified property. Note that you can only
-     * use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties
-     * that are caller-sensitive, you must use {@link #setPropertyGetter(String, SingleDynamicMethod, ValidationType)}
-     * instead.
-     * @param name name of the property
-     * @param handle the method handle that implements the property getter
-     * @param validationType the validation type for the property
-     */
-    void setPropertyGetter(final String name, final MethodHandle handle, final ValidationType validationType) {
-        setPropertyGetter(name, new SimpleDynamicMethod(handle, clazz, name), validationType);
-    }
-
-    private void addMember(final String name, final AccessibleObject ao, final Map<String, DynamicMethod> methodMap) {
-        addMember(name, createDynamicMethod(ao), methodMap);
-    }
-
-    private void addMember(final String name, final SingleDynamicMethod method, final Map<String, DynamicMethod> methodMap) {
-        final DynamicMethod existingMethod = methodMap.get(name);
-        final DynamicMethod newMethod = mergeMethods(method, existingMethod, clazz, name);
-        if(newMethod != existingMethod) {
-            methodMap.put(name, newMethod);
-        }
-    }
-
-    /**
-     * Given one or more reflective methods or constructors, creates a dynamic method that represents them all. The
-     * methods should represent all overloads of the same name (or all constructors of the class).
-     * @param members the reflective members
-     * @param clazz the class declaring the reflective members
-     * @param name the common name of the reflective members.
-     * @return a dynamic method representing all the specified reflective members.
-     */
-    static DynamicMethod createDynamicMethod(final Iterable<? extends AccessibleObject> members, final Class<?> clazz, final String name) {
-        DynamicMethod dynMethod = null;
-        for(final AccessibleObject method: members) {
-            dynMethod = mergeMethods(createDynamicMethod(method), dynMethod, clazz, name);
-        }
-        return dynMethod;
-    }
-
-    /**
-     * Given a reflective method or a constructor, creates a dynamic method that represents it. This method will
-     * distinguish between caller sensitive and ordinary methods/constructors, and create appropriate caller sensitive
-     * dynamic method when needed.
-     * @param m the reflective member
-     * @return the single dynamic method representing the reflective member
-     */
-    private static SingleDynamicMethod createDynamicMethod(final AccessibleObject m) {
-        if (m.isAnnotationPresent(CallerSensitive.class)) {
-            // Method has @CallerSensitive annotation
-            return new CallerSensitiveDynamicMethod(m);
-        }
-        // Method has no @CallerSensitive annotation
-        final MethodHandle mh;
-        try {
-            mh = unreflectSafely(m);
-        } catch (final IllegalAccessError e) {
-            // java.lang.invoke can in some case conservatively treat as caller sensitive methods that aren't
-            // marked with the annotation. In this case, we'll fall back to treating it as caller sensitive.
-            return new CallerSensitiveDynamicMethod(m);
-        }
-        // Proceed with non-caller sensitive
-        final Member member = (Member)m;
-        return new SimpleDynamicMethod(mh, member.getDeclaringClass(), member.getName(), m instanceof Constructor);
-    }
-
-    /**
-     * Unreflects a method handle from a Method or a Constructor using safe (zero-privilege) unreflection. Should be
-     * only used for methods and constructors that are not caller sensitive. If a caller sensitive method were
-     * unreflected through this mechanism, it would not be a security issue, but would be bound to the zero-privilege
-     * unreflector as its caller, and thus completely useless.
-     * @param m the method or constructor
-     * @return the method handle
-     */
-    private static MethodHandle unreflectSafely(final AccessibleObject m) {
-        if(m instanceof Method) {
-            final Method reflMethod = (Method)m;
-            final MethodHandle handle = Lookup.PUBLIC.unreflect(reflMethod);
-            if(Modifier.isStatic(reflMethod.getModifiers())) {
-                return StaticClassIntrospector.editStaticMethodHandle(handle);
-            }
-            return handle;
-        }
-        return StaticClassIntrospector.editConstructorMethodHandle(Lookup.PUBLIC.unreflectConstructor((Constructor<?>)m));
-    }
-
-    private static DynamicMethod mergeMethods(final SingleDynamicMethod method, final DynamicMethod existing, final Class<?> clazz, final String name) {
-        if(existing == null) {
-            return method;
-        } else if(existing.contains(method)) {
-            return existing;
-        } else if(existing instanceof SingleDynamicMethod) {
-            final OverloadedDynamicMethod odm = new OverloadedDynamicMethod(clazz, name);
-            odm.addMethod(((SingleDynamicMethod)existing));
-            odm.addMethod(method);
-            return odm;
-        } else if(existing instanceof OverloadedDynamicMethod) {
-            ((OverloadedDynamicMethod)existing).addMethod(method);
-            return existing;
-        }
-        throw new AssertionError();
-    }
-
-    @Override
-    public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices)
-            throws Exception {
-        final CallSiteDescriptor callSiteDescriptor = request.getCallSiteDescriptor();
-
-        // Handle NamedOperation(CALL_METHOD, name) separately
-        final Operation operation = callSiteDescriptor.getOperation();
-        if (operation instanceof NamedOperation) {
-            final NamedOperation namedOperation = (NamedOperation)operation;
-            if (namedOperation.getBaseOperation() == StandardOperation.CALL_METHOD) {
-                return createGuardedDynamicMethodInvocation(callSiteDescriptor,
-                        linkerServices, namedOperation.getName().toString(), methods);
-            }
-        }
-
-        List<Operation> operations = Arrays.asList(
-                CompositeOperation.getOperations(
-                        NamedOperation.getBaseOperation(operation)));
-        final Object name = NamedOperation.getName(operation);
-
-        while(!operations.isEmpty()) {
-            final GuardedInvocationComponent gic =
-                    getGuardedInvocationComponent(callSiteDescriptor,
-                            linkerServices, operations, name);
-            if(gic != null) {
-                return gic.getGuardedInvocation();
-            }
-            operations = pop(operations);
-        }
-        return null;
-    }
-
-    protected GuardedInvocationComponent getGuardedInvocationComponent(
-            final CallSiteDescriptor callSiteDescriptor,
-            final LinkerServices linkerServices,
-            final List<Operation> operations, final Object name)
-    throws Exception {
-        if(operations.isEmpty()) {
-            return null;
-        }
-        final Operation op = operations.get(0);
-        // Either GET_PROPERTY:name(this) or GET_PROPERTY(this, name)
-        if(op == StandardOperation.GET_PROPERTY) {
-            return getPropertyGetter(callSiteDescriptor, linkerServices, pop(operations), name);
-        }
-        // Either SET_PROPERTY:name(this, value) or SET_PROPERTY(this, name, value)
-        if(op == StandardOperation.SET_PROPERTY) {
-            return getPropertySetter(callSiteDescriptor, linkerServices, pop(operations), name);
-        }
-        // Either GET_METHOD:name(this), or GET_METHOD(this, name)
-        if(op == StandardOperation.GET_METHOD) {
-            return getMethodGetter(callSiteDescriptor, linkerServices, pop(operations), name);
-        }
-        return null;
-    }
-
-    static final <T> List<T> pop(final List<T> l) {
-        return l.subList(1, l.size());
-    }
-
-    MethodHandle getClassGuard(final CallSiteDescriptor desc) {
-        return getClassGuard(desc.getMethodType());
-    }
-
-    MethodHandle getClassGuard(final MethodType type) {
-        return Guards.asType(classGuard, type);
-    }
-
-    GuardedInvocationComponent getClassGuardedInvocationComponent(final MethodHandle invocation, final MethodType type) {
-        return new GuardedInvocationComponent(invocation, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
-    }
-
-    abstract SingleDynamicMethod getConstructorMethod(final String signature);
-
-    private MethodHandle getAssignableGuard(final MethodType type) {
-        return Guards.asType(assignableGuard, type);
-    }
-
-    private GuardedInvocation createGuardedDynamicMethodInvocation(final CallSiteDescriptor callSiteDescriptor,
-            final LinkerServices linkerServices, final String methodName, final Map<String, DynamicMethod> methodMap){
-        final MethodHandle inv = getDynamicMethodInvocation(callSiteDescriptor, linkerServices, methodName, methodMap);
-        return inv == null ? null : new GuardedInvocation(inv, getClassGuard(callSiteDescriptor.getMethodType()));
-    }
-
-    private MethodHandle getDynamicMethodInvocation(final CallSiteDescriptor callSiteDescriptor,
-            final LinkerServices linkerServices, final String methodName, final Map<String, DynamicMethod> methodMap) {
-        final DynamicMethod dynaMethod = getDynamicMethod(methodName, methodMap);
-        return dynaMethod != null ? dynaMethod.getInvocation(callSiteDescriptor, linkerServices) : null;
-    }
-
-    private DynamicMethod getDynamicMethod(final String methodName, final Map<String, DynamicMethod> methodMap) {
-        final DynamicMethod dynaMethod = methodMap.get(methodName);
-        return dynaMethod != null ? dynaMethod : getExplicitSignatureDynamicMethod(methodName, methodMap);
-    }
-
-    private SingleDynamicMethod getExplicitSignatureDynamicMethod(final String fullName,
-            final Map<String, DynamicMethod> methodsMap) {
-        // What's below is meant to support the "name(type, type, ...)" syntax that programmers can use in a method name
-        // to manually pin down an exact overloaded variant. This is not usually required, as the overloaded method
-        // resolution works correctly in almost every situation. However, in presence of many language-specific
-        // conversions with a radically dynamic language, most overloaded methods will end up being constantly selected
-        // at invocation time, so a programmer knowledgeable of the situation might choose to pin down an exact overload
-        // for performance reasons.
-
-        // Is the method name lexically of the form "name(types)"?
-        final int lastChar = fullName.length() - 1;
-        if(fullName.charAt(lastChar) != ')') {
-            return null;
-        }
-        final int openBrace = fullName.indexOf('(');
-        if(openBrace == -1) {
-            return null;
-        }
-
-        final String name = fullName.substring(0, openBrace);
-        final String signature = fullName.substring(openBrace + 1, lastChar);
-
-        // Find an existing method for the "name" part
-        final DynamicMethod simpleNamedMethod = methodsMap.get(name);
-        if(simpleNamedMethod == null) {
-            // explicit signature constructor access
-            // Java.type("java.awt.Color")["(int,int,int)"]
-            // will get Color(int,int,int) constructor of Color class.
-            if (name.isEmpty()) {
-                return getConstructorMethod(signature);
-            }
-
-            return null;
-        }
-
-        // Try to get a narrowed dynamic method for the explicit parameter types.
-        return simpleNamedMethod.getMethodForExactParamTypes(signature);
-    }
-
-    private static final MethodHandle IS_METHOD_HANDLE_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType(
-            boolean.class, MethodHandle.class));
-    private static final MethodHandle CONSTANT_NULL_DROP_METHOD_HANDLE = MethodHandles.dropArguments(
-            MethodHandles.constant(Object.class, null), 0, MethodHandle.class);
-
-    private GuardedInvocationComponent getPropertySetter(final CallSiteDescriptor callSiteDescriptor,
-            final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception {
-        if (name == null) {
-            return getUnnamedPropertySetter(callSiteDescriptor, linkerServices, operations);
-        }
-        return getNamedPropertySetter(callSiteDescriptor, linkerServices, operations, name);
-    }
-
-    private GuardedInvocationComponent getUnnamedPropertySetter(final CallSiteDescriptor callSiteDescriptor,
-            final LinkerServices linkerServices, final List<Operation> operations) throws Exception {
-        // Must have three arguments: target object, property name, and property value.
-        assertParameterCount(callSiteDescriptor, 3);
-
-        // We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be
-        // valid for us to convert return values proactively. Also, since we don't know what setters will be
-        // invoked, we'll conservatively presume Object return type. The one exception is void return.
-        final MethodType origType = callSiteDescriptor.getMethodType();
-        final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class);
-
-        // What's below is basically:
-        //   foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
-        //     get_setter_handle(type, linkerServices))
-        // only with a bunch of method signature adjustments. Basically, retrieve method setter
-        // MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next
-        // component's invocation.
-
-        // Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll
-        // abbreviate to R(O, N, V) going forward, although we don't really use R here (see above about using
-        // Object return type).
-        final MethodType setterType = type.dropParameterTypes(1, 2);
-        // Bind property setter handle to the expected setter type and linker services. Type is
-        // MethodHandle(Object, String, Object)
-        final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
-                callSiteDescriptor.changeMethodType(setterType), linkerServices);
-
-        // Cast getter to MethodHandle(O, N, V)
-        final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
-                MethodHandle.class));
-
-        // Handle to invoke the setter R(MethodHandle, O, V)
-        final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType);
-        // Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V)
-        final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType(
-                1));
-        final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
-                linkerServices, operations, null);
-
-        final MethodHandle fallbackFolded;
-        if(nextComponent == null) {
-            // Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null
-            fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
-                    type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
-        } else {
-            // Object(O, N, V)->Object(MethodHandle, O, N, V); adapts the next component's invocation to drop the
-            // extra argument resulting from fold
-            fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
-                    0, MethodHandle.class);
-        }
-
-        // fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V))
-        final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
-                    IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
-        if(nextComponent == null) {
-            return getClassGuardedInvocationComponent(compositeSetter, type);
-        }
-        return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
-    }
-
-    private GuardedInvocationComponent getNamedPropertySetter(final CallSiteDescriptor callSiteDescriptor,
-            final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception {
-        // Must have two arguments: target object and property value
-        assertParameterCount(callSiteDescriptor, 2);
-        final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
-                name.toString(), propertySetters);
-        // If we have a property setter with this name, this composite operation will always stop here
-        if(gi != null) {
-            return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
-        }
-        // If we don't have a property setter with this name, always fall back to the next operation in the
-        // composite (if any)
-        return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations, name);
-    }
-
-    private static final Lookup privateLookup = new Lookup(MethodHandles.lookup());
-
-    private static final MethodHandle IS_ANNOTATED_METHOD_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType(
-            boolean.class, AnnotatedDynamicMethod.class));
-    private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_METHOD = MethodHandles.dropArguments(
-            MethodHandles.constant(Object.class, null), 0, AnnotatedDynamicMethod.class);
-    private static final MethodHandle GET_ANNOTATED_METHOD = privateLookup.findVirtual(AnnotatedDynamicMethod.class,
-            "getTarget", MethodType.methodType(MethodHandle.class, CallSiteDescriptor.class, LinkerServices.class));
-    private static final MethodHandle GETTER_INVOKER = MethodHandles.invoker(MethodType.methodType(Object.class, Object.class));
-
-    private GuardedInvocationComponent getPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
-            final LinkerServices linkerServices, final List<Operation> ops, final Object name) throws Exception {
-        if (name == null) {
-            return getUnnamedPropertyGetter(callSiteDescriptor, linkerServices, ops);
-        }
-
-        return getNamedPropertyGetter(callSiteDescriptor, linkerServices, ops, name);
-    }
-
-    private GuardedInvocationComponent getUnnamedPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
-            final LinkerServices linkerServices, final List<Operation> ops) throws Exception {
-        // Since we can't know what kind of a getter we'll get back on different invocations, we'll just
-        // conservatively presume Object. Note we can't just coerce to a narrower call site type as the linking
-        // runtime might not allow coercing at that call site.
-        final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class);
-        // Must have exactly two arguments: receiver and name
-        assertParameterCount(callSiteDescriptor, 2);
-
-        // What's below is basically:
-        //   foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle)
-        // only with a bunch of method signature adjustments. Basically, retrieve method getter
-        // AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null,
-        // or delegate to next component's invocation.
-
-        final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType(
-                AnnotatedDynamicMethod.class));
-        final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments(
-                GET_ANNOTATED_METHOD, 1, callSiteDescriptor, linkerServices);
-        final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0,
-                callSiteBoundMethodGetter);
-        // Object(AnnotatedDynamicMethod, Object)->Object(AnnotatedDynamicMethod, T0)
-        final MethodHandle invokeHandleTyped = linkerServices.asType(callSiteBoundInvoker,
-                MethodType.methodType(type.returnType(), AnnotatedDynamicMethod.class, type.parameterType(0)));
-        // Since it's in the target of a fold, drop the unnecessary second argument
-        // Object(AnnotatedDynamicMethod, T0)->Object(AnnotatedDynamicMethod, T0, T1)
-        final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2,
-                type.parameterType(1));
-        final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
-                linkerServices, ops, null);
-
-        final MethodHandle fallbackFolded;
-        if(nextComponent == null) {
-            // Object(AnnotatedDynamicMethod)->Object(AnnotatedDynamicMethod, T0, T1); returns constant null
-            fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_METHOD, 1,
-                    type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedDynamicMethod.class));
-        } else {
-            // Object(T0, T1)->Object(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to
-            // drop the extra argument resulting from fold and to change its return type to Object.
-            final MethodHandle nextInvocation = nextComponent.getGuardedInvocation().getInvocation();
-            final MethodType nextType = nextInvocation.type();
-            fallbackFolded = MethodHandles.dropArguments(nextInvocation.asType(
-                    nextType.changeReturnType(Object.class)), 0, AnnotatedDynamicMethod.class);
-        }
-
-        // fold(Object(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1))
-        final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
-                    IS_ANNOTATED_METHOD_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
-        if(nextComponent == null) {
-            return getClassGuardedInvocationComponent(compositeGetter, type);
-        }
-        return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
-    }
-
-    private GuardedInvocationComponent getNamedPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
-            final LinkerServices linkerServices, final List<Operation> ops, final Object name) throws Exception {
-        // Must have exactly one argument: receiver
-        assertParameterCount(callSiteDescriptor, 1);
-        // Fixed name
-        final AnnotatedDynamicMethod annGetter = propertyGetters.get(name.toString());
-        if(annGetter == null) {
-            // We have no such property, always delegate to the next component operation
-            return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops, name);
-        }
-        final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices);
-        // NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being
-        // overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the
-        // method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If
-        // we're linking against a field getter, don't make the assumption.
-        // NOTE: No delegation to the next component operation if we have a property with this name, even if its
-        // value is null.
-        final ValidationType validationType = annGetter.validationType;
-        // TODO: we aren't using the type that declares the most generic getter here!
-        return new GuardedInvocationComponent(getter, getGuard(validationType,
-                callSiteDescriptor.getMethodType()), clazz, validationType);
-    }
-
-    private MethodHandle getGuard(final ValidationType validationType, final MethodType methodType) {
-        switch(validationType) {
-            case EXACT_CLASS: {
-                return getClassGuard(methodType);
-            }
-            case INSTANCE_OF: {
-                return getAssignableGuard(methodType);
-            }
-            case IS_ARRAY: {
-                return Guards.isArray(0, methodType);
-            }
-            case NONE: {
-                return null;
-            }
-            default: {
-                throw new AssertionError();
-            }
-        }
-    }
-
-    private static final MethodHandle IS_DYNAMIC_METHOD = Guards.isInstance(DynamicMethod.class,
-            MethodType.methodType(boolean.class, Object.class));
-    private static final MethodHandle OBJECT_IDENTITY = MethodHandles.identity(Object.class);
-
-    private GuardedInvocationComponent getMethodGetter(final CallSiteDescriptor callSiteDescriptor,
-            final LinkerServices linkerServices, final List<Operation> ops, final Object name) throws Exception {
-        // The created method handle will always return a DynamicMethod (or null), but since we don't want that type to
-        // be visible outside of this linker, declare it to return Object.
-        final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class);
-        if (name == null) {
-            return getUnnamedMethodGetter(callSiteDescriptor, linkerServices, ops, type);
-        }
-
-        return getNamedMethodGetter(callSiteDescriptor, linkerServices, ops, name, type);
-    }
-
-    private GuardedInvocationComponent getUnnamedMethodGetter(final CallSiteDescriptor callSiteDescriptor,
-            final LinkerServices linkerServices, final List<Operation> ops, final MethodType type) throws Exception {
-        // Must have exactly two arguments: receiver and name
-        assertParameterCount(callSiteDescriptor, 2);
-        final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
-                linkerServices, ops, null);
-        if(nextComponent == null || !InternalTypeUtilities.areAssignable(DynamicMethod.class,
-                nextComponent.getGuardedInvocation().getInvocation().type().returnType())) {
-            // No next component operation, or it can never produce a dynamic method; just return a component
-            // for this operation.
-            return getClassGuardedInvocationComponent(linkerServices.asType(getDynamicMethod, type), type);
-        }
-
-        // What's below is basically:
-        // foldArguments(guardWithTest(isNotNull, identity, nextComponent.invocation), getter) only with a
-        // bunch of method signature adjustments. Basically, execute method getter; if it returns a non-null
-        // DynamicMethod, use identity to return it, otherwise delegate to nextComponent's invocation.
-
-        final MethodHandle typedGetter = linkerServices.asType(getDynamicMethod, type);
-        // Since it is part of the foldArgument() target, it will have extra args that we need to drop.
-        final MethodHandle returnMethodHandle = linkerServices.asType(MethodHandles.dropArguments(
-                OBJECT_IDENTITY, 1, type.parameterList()), type.insertParameterTypes(0, Object.class));
-        final MethodHandle nextComponentInvocation = nextComponent.getGuardedInvocation().getInvocation();
-        // The assumption is that getGuardedInvocationComponent() already asType()'d it correctly modulo the
-        // return type.
-        assert nextComponentInvocation.type().changeReturnType(type.returnType()).equals(type);
-        // Since it is part of the foldArgument() target, we have to drop an extra arg it receives.
-        final MethodHandle nextCombinedInvocation = MethodHandles.dropArguments(nextComponentInvocation, 0,
-                Object.class);
-        // Assemble it all into a fold(guard(isNotNull, identity, nextInvocation), get)
-        final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
-                IS_DYNAMIC_METHOD, returnMethodHandle, nextCombinedInvocation), typedGetter);
-
-        return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
-    }
-
-    private GuardedInvocationComponent getNamedMethodGetter(final CallSiteDescriptor callSiteDescriptor,
-            final LinkerServices linkerServices, final List<Operation> ops, final Object name, final MethodType type)
-            throws Exception {
-        // Must have exactly one argument: receiver
-        assertParameterCount(callSiteDescriptor, 1);
-        final DynamicMethod method = getDynamicMethod(name.toString());
-        if(method == null) {
-            // We have no such method, always delegate to the next component
-            return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops, name);
-        }
-        // No delegation to the next component of the composite operation; if we have a method with that name,
-        // we'll always return it at this point.
-        return getClassGuardedInvocationComponent(linkerServices.asType(MethodHandles.dropArguments(
-                MethodHandles.constant(Object.class, method), 0, type.parameterType(0)), type), type);
-    }
-
-    static class MethodPair {
-        final MethodHandle method1;
-        final MethodHandle method2;
-
-        MethodPair(final MethodHandle method1, final MethodHandle method2) {
-            this.method1 = method1;
-            this.method2 = method2;
-        }
-
-        MethodHandle guardWithTest(final MethodHandle test) {
-            return MethodHandles.guardWithTest(test, method1, method2);
-        }
-    }
-
-    static MethodPair matchReturnTypes(final MethodHandle m1, final MethodHandle m2) {
-        final MethodType type1 = m1.type();
-        final MethodType type2 = m2.type();
-        final Class<?> commonRetType = InternalTypeUtilities.getCommonLosslessConversionType(type1.returnType(),
-                type2.returnType());
-        return new MethodPair(
-                m1.asType(type1.changeReturnType(commonRetType)),
-                m2.asType(type2.changeReturnType(commonRetType)));
-    }
-
-    private static void assertParameterCount(final CallSiteDescriptor descriptor, final int paramCount) {
-        if(descriptor.getMethodType().parameterCount() != paramCount) {
-            throw new BootstrapMethodError(descriptor.getOperation() + " must have exactly " + paramCount + " parameters.");
-        }
-    }
-
-    private static MethodHandle GET_PROPERTY_GETTER_HANDLE = MethodHandles.dropArguments(privateLookup.findOwnSpecial(
-            "getPropertyGetterHandle", Object.class, Object.class), 1, Object.class);
-    private final MethodHandle getPropertyGetterHandle = GET_PROPERTY_GETTER_HANDLE.bindTo(this);
-
-    /**
-     * @param id the property ID
-     * @return the method handle for retrieving the property, or null if the property does not exist
-     */
-    @SuppressWarnings("unused")
-    private Object getPropertyGetterHandle(final Object id) {
-        return propertyGetters.get(id);
-    }
-
-    // Type is MethodHandle(BeanLinker, MethodType, LinkerServices, Object, String, Object), of which the two "Object"
-    // args are dropped; this makes handles with first three args conform to "Object, String, Object" though, which is
-    // a typical property setter with variable name signature (target, name, value).
-    private static final MethodHandle GET_PROPERTY_SETTER_HANDLE = MethodHandles.dropArguments(MethodHandles.dropArguments(
-            privateLookup.findOwnSpecial("getPropertySetterHandle", MethodHandle.class, CallSiteDescriptor.class,
-                    LinkerServices.class, Object.class), 3, Object.class), 5, Object.class);
-    // Type is MethodHandle(MethodType, LinkerServices, Object, String, Object)
-    private final MethodHandle getPropertySetterHandle = GET_PROPERTY_SETTER_HANDLE.bindTo(this);
-
-    @SuppressWarnings("unused")
-    private MethodHandle getPropertySetterHandle(final CallSiteDescriptor setterDescriptor, final LinkerServices linkerServices,
-            final Object id) {
-        return getDynamicMethodInvocation(setterDescriptor, linkerServices, String.valueOf(id), propertySetters);
-    }
-
-    private static MethodHandle GET_DYNAMIC_METHOD = MethodHandles.dropArguments(privateLookup.findOwnSpecial(
-            "getDynamicMethod", Object.class, Object.class), 1, Object.class);
-    private final MethodHandle getDynamicMethod = GET_DYNAMIC_METHOD.bindTo(this);
-
-    @SuppressWarnings("unused")
-    // This method is marked to return Object instead of DynamicMethod as it's used as a linking component and we don't
-    // want to make the DynamicMethod type observable externally (e.g. as the return type of a MethodHandle returned for
-    // GET_METHOD linking).
-    private Object getDynamicMethod(final Object name) {
-        return getDynamicMethod(String.valueOf(name), methods);
-    }
-
-    /**
-     * Returns a dynamic method of the specified name.
-     *
-     * @param name name of the method
-     * @return the dynamic method (either {@link SimpleDynamicMethod} or {@link OverloadedDynamicMethod}, or null if the
-     * method with the specified name does not exist.
-     */
-    DynamicMethod getDynamicMethod(final String name) {
-        return getDynamicMethod(name, methods);
-    }
-
-    /**
-     * Find the most generic superclass that declares this getter. Since getters have zero args (aside from the
-     * receiver), they can't be overloaded, so we're free to link with an instanceof guard for the most generic one,
-     * creating more stable call sites.
-     * @param getter the getter
-     * @return getter with same name, declared on the most generic superclass/interface of the declaring class
-     */
-    private static Method getMostGenericGetter(final Method getter) {
-        return getMostGenericGetter(getter.getName(), getter.getReturnType(), getter.getDeclaringClass());
-    }
-
-    private static Method getMostGenericGetter(final String name, final Class<?> returnType, final Class<?> declaringClass) {
-        if(declaringClass == null) {
-            return null;
-        }
-        // Prefer interfaces
-        for(final Class<?> itf: declaringClass.getInterfaces()) {
-            final Method itfGetter = getMostGenericGetter(name, returnType, itf);
-            if(itfGetter != null) {
-                return itfGetter;
-            }
-        }
-        final Method superGetter = getMostGenericGetter(name, returnType, declaringClass.getSuperclass());
-        if(superGetter != null) {
-            return superGetter;
-        }
-        if(!CheckRestrictedPackage.isRestrictedClass(declaringClass)) {
-            try {
-                return declaringClass.getMethod(name);
-            } catch(final NoSuchMethodException e) {
-                // Intentionally ignored, meant to fall through
-            }
-        }
-        return null;
-    }
-
-    private static final class AnnotatedDynamicMethod {
-        private final SingleDynamicMethod method;
-        /*private*/ final ValidationType validationType;
-
-        AnnotatedDynamicMethod(final SingleDynamicMethod method, final ValidationType validationType) {
-            this.method = method;
-            this.validationType = validationType;
-        }
-
-        MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) {
-            return method.getInvocation(callSiteDescriptor, linkerServices);
-        }
-
-        @SuppressWarnings("unused")
-        MethodHandle getTarget(final CallSiteDescriptor desc, final LinkerServices linkerServices) {
-            final MethodHandle inv = linkerServices.filterInternalObjects(method.getTarget(desc));
-            assert inv != null;
-            return inv;
-        }
-    }
-}