# HG changeset patch # Parent 354c809cd3255ea979a17cdc4e9369582df0e528 diff -r 354c809cd325 src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/StandardOperation.java --- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/StandardOperation.java Mon Nov 02 18:47:40 2015 +0100 +++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/StandardOperation.java Tue Nov 03 15:57:09 2015 +0100 @@ -127,7 +127,7 @@ */ SET_ELEMENT, /** - * Get the length of an array of size of a collection. Call sites with + * Get the length of an array or size of a collection. Call sites with * this operation should have a signature of (receiver)→value, * with all parameters and return type being of any type (either primitive * or reference). diff -r 354c809cd325 src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java --- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java Mon Nov 02 18:47:40 2015 +0100 +++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java Tue Nov 03 15:57:09 2015 +0100 @@ -359,43 +359,70 @@ } } - List operations = Arrays.asList( - CompositeOperation.getOperations( - NamedOperation.getBaseOperation(operation))); - final Object name = NamedOperation.getName(operation); + ComponentLinkRequest componentReq = new ComponentLinkRequest( + callSiteDescriptor, linkerServices); - while(!operations.isEmpty()) { - final GuardedInvocationComponent gic = - getGuardedInvocationComponent(callSiteDescriptor, - linkerServices, operations, name); + while(!componentReq.operations.isEmpty()) { + final GuardedInvocationComponent gic = getGuardedInvocationComponent(componentReq); if(gic != null) { return gic.getGuardedInvocation(); } - operations = pop(operations); + componentReq = componentReq.popOperations(); } return null; } - protected GuardedInvocationComponent getGuardedInvocationComponent( - final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, - final List operations, final Object name) + static class ComponentLinkRequest { + final CallSiteDescriptor descriptor; + final LinkerServices linkerServices; + final List operations; + final Object name; + + ComponentLinkRequest(final CallSiteDescriptor descriptor, + final LinkerServices linkerServices) { + this.descriptor = descriptor; + this.linkerServices = linkerServices; + final Operation operation = descriptor.getOperation(); + this.operations = Arrays.asList( + CompositeOperation.getOperations( + NamedOperation.getBaseOperation(operation))); + this.name = NamedOperation.getName(operation); + } + + private ComponentLinkRequest(final CallSiteDescriptor descriptor, + final LinkerServices linkerServices, + final List operations, final Object name) { + this.descriptor = descriptor; + this.linkerServices = linkerServices; + this.operations = operations; + this.name = name; + } + + ComponentLinkRequest popOperations() { + return new ComponentLinkRequest(descriptor, linkerServices, + operations.subList(1, operations.size()), name); + } + } + + + + protected GuardedInvocationComponent getGuardedInvocationComponent(final ComponentLinkRequest req) throws Exception { - if(operations.isEmpty()) { + if(req.operations.isEmpty()) { return null; } - final Operation op = operations.get(0); + final Operation op = req.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); + return getPropertyGetter(req.popOperations()); } // Either SET_PROPERTY:name(this, value) or SET_PROPERTY(this, name, value) if(op == StandardOperation.SET_PROPERTY) { - return getPropertySetter(callSiteDescriptor, linkerServices, pop(operations), name); + return getPropertySetter(req.popOperations()); } // Either GET_METHOD:name(this), or GET_METHOD(this, name) if(op == StandardOperation.GET_METHOD) { - return getMethodGetter(callSiteDescriptor, linkerServices, pop(operations), name); + return getMethodGetter(req.popOperations()); } return null; } @@ -485,16 +512,15 @@ 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 operations, final Object name) throws Exception { - if (name == null) { - return getUnnamedPropertySetter(callSiteDescriptor, linkerServices, operations); + private GuardedInvocationComponent getPropertySetter(final ComponentLinkRequest req) throws Exception { + if (req.name == null) { + return getUnnamedPropertySetter(req); } - return getNamedPropertySetter(callSiteDescriptor, linkerServices, operations, name); + return getNamedPropertySetter(req); } - private GuardedInvocationComponent getUnnamedPropertySetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List operations) throws Exception { + private GuardedInvocationComponent getUnnamedPropertySetter(final ComponentLinkRequest req) throws Exception { + final CallSiteDescriptor callSiteDescriptor = req.descriptor; // Must have three arguments: target object, property name, and property value. assertParameterCount(callSiteDescriptor, 3); @@ -503,6 +529,7 @@ // 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); + final LinkerServices linkerServices = req.linkerServices; // What's below is basically: // foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation), @@ -529,8 +556,7 @@ // 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 GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(req); final MethodHandle fallbackFolded; if(nextComponent == null) { @@ -553,19 +579,19 @@ return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); } - private GuardedInvocationComponent getNamedPropertySetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List operations, final Object name) throws Exception { + private GuardedInvocationComponent getNamedPropertySetter(final ComponentLinkRequest req) throws Exception { // Must have two arguments: target object and property value - assertParameterCount(callSiteDescriptor, 2); - final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices, - name.toString(), propertySetters); + assertParameterCount(req.descriptor, 2); + final GuardedInvocation gi = createGuardedDynamicMethodInvocation( + req.descriptor, req.linkerServices, req.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); + return getGuardedInvocationComponent(req); } private static final Lookup privateLookup = new Lookup(MethodHandles.lookup()); @@ -578,20 +604,19 @@ "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 ops, final Object name) throws Exception { - if (name == null) { - return getUnnamedPropertyGetter(callSiteDescriptor, linkerServices, ops); + private GuardedInvocationComponent getPropertyGetter(final ComponentLinkRequest req) throws Exception { + if (req.name == null) { + return getUnnamedPropertyGetter(req); } - return getNamedPropertyGetter(callSiteDescriptor, linkerServices, ops, name); + return getNamedPropertyGetter(req); } - private GuardedInvocationComponent getUnnamedPropertyGetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List ops) throws Exception { + private GuardedInvocationComponent getUnnamedPropertyGetter(final ComponentLinkRequest req) 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 CallSiteDescriptor callSiteDescriptor = req.descriptor; final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class); // Must have exactly two arguments: receiver and name assertParameterCount(callSiteDescriptor, 2); @@ -602,6 +627,7 @@ // AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null, // or delegate to next component's invocation. + final LinkerServices linkerServices = req.linkerServices; final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType( AnnotatedDynamicMethod.class)); final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments( @@ -615,8 +641,7 @@ // 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 GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(req); final MethodHandle fallbackFolded; if(nextComponent == null) { @@ -641,17 +666,17 @@ return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); } - private GuardedInvocationComponent getNamedPropertyGetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List ops, final Object name) throws Exception { + private GuardedInvocationComponent getNamedPropertyGetter(final ComponentLinkRequest req) throws Exception { + final CallSiteDescriptor callSiteDescriptor = req.descriptor; // Must have exactly one argument: receiver assertParameterCount(callSiteDescriptor, 1); // Fixed name - final AnnotatedDynamicMethod annGetter = propertyGetters.get(name.toString()); + final AnnotatedDynamicMethod annGetter = propertyGetters.get(req.name.toString()); if(annGetter == null) { // We have no such property, always delegate to the next component operation - return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops, name); + return getGuardedInvocationComponent(req); } - final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices); + final MethodHandle getter = annGetter.getInvocation(req); // 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 @@ -688,24 +713,26 @@ 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 ops, final Object name) throws Exception { + private GuardedInvocationComponent getMethodGetter(final ComponentLinkRequest req) throws Exception { + if (req.name == null) { + return getUnnamedMethodGetter(req); + } + + return getNamedMethodGetter(req); + } + + private static MethodType getMethodGetterType(final ComponentLinkRequest req) { // 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); + return req.descriptor.getMethodType().changeReturnType(Object.class); } - private GuardedInvocationComponent getUnnamedMethodGetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List ops, final MethodType type) throws Exception { + private GuardedInvocationComponent getUnnamedMethodGetter(final ComponentLinkRequest req) throws Exception { // Must have exactly two arguments: receiver and name - assertParameterCount(callSiteDescriptor, 2); - final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, - linkerServices, ops, null); + assertParameterCount(req.descriptor, 2); + final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(req); + final LinkerServices linkerServices = req.linkerServices; + final MethodType type = getMethodGetterType(req); 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 @@ -736,19 +763,19 @@ return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); } - private GuardedInvocationComponent getNamedMethodGetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List ops, final Object name, final MethodType type) + private GuardedInvocationComponent getNamedMethodGetter(final ComponentLinkRequest req) throws Exception { // Must have exactly one argument: receiver - assertParameterCount(callSiteDescriptor, 1); - final DynamicMethod method = getDynamicMethod(name.toString()); + assertParameterCount(req.descriptor, 1); + final DynamicMethod method = getDynamicMethod(req.name.toString()); if(method == null) { // We have no such method, always delegate to the next component - return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops, name); + return getGuardedInvocationComponent(req); } // 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( + final MethodType type = getMethodGetterType(req); + return getClassGuardedInvocationComponent(req.linkerServices.asType(MethodHandles.dropArguments( MethodHandles.constant(Object.class, method), 0, type.parameterType(0)), type), type); } @@ -878,8 +905,8 @@ this.validationType = validationType; } - MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) { - return method.getInvocation(callSiteDescriptor, linkerServices); + MethodHandle getInvocation(final ComponentLinkRequest req) { + return method.getInvocation(req.descriptor, req.linkerServices); } @SuppressWarnings("unused") diff -r 354c809cd325 src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeanLinker.java --- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeanLinker.java Mon Nov 02 18:47:40 2015 +0100 +++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeanLinker.java Tue Nov 03 15:57:09 2015 +0100 @@ -129,25 +129,23 @@ } @Override - protected GuardedInvocationComponent getGuardedInvocationComponent(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List operations, final Object name) throws Exception { - final GuardedInvocationComponent superGic = super.getGuardedInvocationComponent(callSiteDescriptor, - linkerServices, operations, name); + protected GuardedInvocationComponent getGuardedInvocationComponent(final ComponentLinkRequest req) throws Exception { + final GuardedInvocationComponent superGic = super.getGuardedInvocationComponent(req); if(superGic != null) { return superGic; } - if(operations.isEmpty()) { + if(req.operations.isEmpty()) { return null; } - final Operation op = operations.get(0); + final Operation op = req.operations.get(0); if(op == StandardOperation.GET_ELEMENT) { - return getElementGetter(callSiteDescriptor, linkerServices, pop(operations), name); + return getElementGetter(req.popOperations()); } if(op == StandardOperation.SET_ELEMENT) { - return getElementSetter(callSiteDescriptor, linkerServices, pop(operations), name); + return getElementSetter(req.popOperations()); } if(op == StandardOperation.GET_LENGTH) { - return getLengthGetter(callSiteDescriptor); + return getLengthGetter(req.descriptor); } return null; } @@ -165,12 +163,12 @@ ARRAY, LIST, MAP }; - private GuardedInvocationComponent getElementGetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List operations, final Object name) throws Exception { + private GuardedInvocationComponent getElementGetter(final ComponentLinkRequest req) throws Exception { + final CallSiteDescriptor callSiteDescriptor = req.descriptor; + final LinkerServices linkerServices = req.linkerServices; final MethodType callSiteType = callSiteDescriptor.getMethodType(); final Class declaredType = callSiteType.parameterType(0); - final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, - linkerServices, operations, name); + final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(req); // If declared type of receiver at the call site is already an array, a list or map, bind without guard. Thing // is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance they're @@ -206,6 +204,7 @@ // Convert the key to a number if we're working with a list or array final Object typedName; + final Object name = req.name; if(collectionType != CollectionType.MAP && name != null) { typedName = convertKeyToInteger(name, linkerServices); if(typedName == null) { @@ -394,8 +393,9 @@ private static final MethodHandle PUT_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "put", MethodType.methodType(Object.class, Object.class, Object.class)); - private GuardedInvocationComponent getElementSetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List operations, final Object name) throws Exception { + private GuardedInvocationComponent getElementSetter(final ComponentLinkRequest req) throws Exception { + final CallSiteDescriptor callSiteDescriptor = req.descriptor; + final LinkerServices linkerServices = req.linkerServices; final MethodType callSiteType = callSiteDescriptor.getMethodType(); final Class declaredType = callSiteType.parameterType(0); @@ -436,14 +436,14 @@ // In contrast to, say, getElementGetter, we only compute the nextComponent if the target object is not a map, // as maps will always succeed in setting the element and will never need to fall back to the next component // operation. - final GuardedInvocationComponent nextComponent = collectionType == CollectionType.MAP ? null : getGuardedInvocationComponent( - callSiteDescriptor, linkerServices, operations, name); + final GuardedInvocationComponent nextComponent = collectionType == CollectionType.MAP ? null : getGuardedInvocationComponent(req); if(gic == null) { return nextComponent; } // Convert the key to a number if we're working with a list or array final Object typedName; + final Object name = req.name; if(collectionType != CollectionType.MAP && name != null) { typedName = convertKeyToInteger(name, linkerServices); if(typedName == null) { diff -r 354c809cd325 src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/package-info.java --- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/package-info.java Mon Nov 02 18:47:40 2015 +0100 +++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/package-info.java Tue Nov 03 15:57:09 2015 +0100 @@ -83,7 +83,7 @@ /** *

- * Dynalink is a library for dynamic linking high-level operations on objects. + * Dynalink is a library for dynamic linking of high-level operations on objects. * These operations include "read a property", * "write a property", "invoke a function" and so on. Dynalink is primarily * useful for implementing programming languages where at least some expressions