Thu, 27 Nov 2014 13:04:46 +0100
8051778: support bind on all Nashorn callables
Reviewed-by: hannesw, lagergren
1.1 --- a/src/jdk/nashorn/internal/objects/NativeFunction.java Thu Nov 27 18:02:28 2014 +0100 1.2 +++ b/src/jdk/nashorn/internal/objects/NativeFunction.java Thu Nov 27 13:04:46 2014 +0100 1.3 @@ -48,6 +48,7 @@ 1.4 import jdk.nashorn.internal.runtime.ScriptFunction; 1.5 import jdk.nashorn.internal.runtime.ScriptObject; 1.6 import jdk.nashorn.internal.runtime.ScriptRuntime; 1.7 +import jdk.nashorn.internal.runtime.linker.Bootstrap; 1.8 1.9 /** 1.10 * ECMA 15.3 Function Objects 1.11 @@ -204,11 +205,7 @@ 1.12 * @return function with bound arguments 1.13 */ 1.14 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 1.15 - public static ScriptFunction bind(final Object self, final Object... args) { 1.16 - if (!(self instanceof ScriptFunction)) { 1.17 - throw typeError("not.a.function", ScriptRuntime.safeToString(self)); 1.18 - } 1.19 - 1.20 + public static Object bind(final Object self, final Object... args) { 1.21 final Object thiz = (args.length == 0) ? UNDEFINED : args[0]; 1.22 1.23 Object[] arguments; 1.24 @@ -219,7 +216,7 @@ 1.25 arguments = ScriptRuntime.EMPTY_ARRAY; 1.26 } 1.27 1.28 - return ((ScriptFunctionImpl)self).makeBoundFunction(thiz, arguments); 1.29 + return Bootstrap.bindCallable(self, thiz, arguments); 1.30 } 1.31 1.32 /**
2.1 --- a/src/jdk/nashorn/internal/objects/NativeObject.java Thu Nov 27 18:02:28 2014 +0100 2.2 +++ b/src/jdk/nashorn/internal/objects/NativeObject.java Thu Nov 27 13:04:46 2014 +0100 2.3 @@ -28,6 +28,7 @@ 2.4 import static jdk.nashorn.internal.lookup.Lookup.MH; 2.5 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 2.6 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 2.7 + 2.8 import java.lang.invoke.MethodHandle; 2.9 import java.lang.invoke.MethodHandles; 2.10 import java.lang.invoke.MethodType; 2.11 @@ -804,7 +805,7 @@ 2.12 // name and object linked with BeansLinker. (Actually, an even stronger assumption is true: return value is 2.13 // constant for any given method name and object's class.) 2.14 return MethodHandles.dropArguments(MethodHandles.constant(Object.class, 2.15 - Bootstrap.bindDynamicMethod(methodGetter.invoke(source), source)), 0, Object.class); 2.16 + Bootstrap.bindCallable(methodGetter.invoke(source), source, null)), 0, Object.class); 2.17 } catch(RuntimeException|Error e) { 2.18 throw e; 2.19 } catch(final Throwable t) {
3.1 --- a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java Thu Nov 27 18:02:28 2014 +0100 3.2 +++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java Thu Nov 27 13:04:46 2014 +0100 3.3 @@ -30,7 +30,6 @@ 3.4 3.5 import java.lang.invoke.MethodHandle; 3.6 import java.util.ArrayList; 3.7 - 3.8 import jdk.nashorn.internal.runtime.AccessorProperty; 3.9 import jdk.nashorn.internal.runtime.GlobalFunctions; 3.10 import jdk.nashorn.internal.runtime.Property; 3.11 @@ -237,13 +236,13 @@ 3.12 3.13 /** 3.14 * Same as {@link ScriptFunction#makeBoundFunction(Object, Object[])}. The only reason we override it is so that we 3.15 - * can expose it to methods in this package. 3.16 + * can expose it. 3.17 * @param self the self to bind to this function. Can be null (in which case, null is bound as this). 3.18 * @param args additional arguments to bind to this function. Can be null or empty to not bind additional arguments. 3.19 * @return a function with the specified self and parameters bound. 3.20 */ 3.21 @Override 3.22 - protected ScriptFunction makeBoundFunction(final Object self, final Object[] args) { 3.23 + public ScriptFunction makeBoundFunction(final Object self, final Object[] args) { 3.24 return super.makeBoundFunction(self, args); 3.25 } 3.26
4.1 --- a/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java Thu Nov 27 18:02:28 2014 +0100 4.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java Thu Nov 27 13:04:46 2014 +0100 4.3 @@ -25,11 +25,7 @@ 4.4 4.5 package jdk.nashorn.internal.runtime.arrays; 4.6 4.7 -import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 4.8 - 4.9 -import jdk.nashorn.api.scripting.JSObject; 4.10 import jdk.nashorn.internal.runtime.Context; 4.11 -import jdk.nashorn.internal.runtime.ScriptFunction; 4.12 import jdk.nashorn.internal.runtime.ScriptRuntime; 4.13 import jdk.nashorn.internal.runtime.linker.Bootstrap; 4.14 4.15 @@ -98,17 +94,7 @@ 4.16 * @return result of apply 4.17 */ 4.18 public final T apply() { 4.19 - final boolean strict; 4.20 - if (callbackfn instanceof ScriptFunction) { 4.21 - strict = ((ScriptFunction)callbackfn).isStrict(); 4.22 - } else if (callbackfn instanceof JSObject && 4.23 - ((JSObject)callbackfn).isFunction()) { 4.24 - strict = ((JSObject)callbackfn).isStrictFunction(); 4.25 - } else if (Bootstrap.isDynamicMethod(callbackfn) || Bootstrap.isFunctionalInterfaceObject(callbackfn)) { 4.26 - strict = false; 4.27 - } else { 4.28 - throw typeError("not.a.function", ScriptRuntime.safeToString(callbackfn)); 4.29 - } 4.30 + final boolean strict = Bootstrap.isStrictCallable(callbackfn); 4.31 4.32 // for non-strict callback, need to translate undefined thisArg to be global object 4.33 thisArg = (thisArg == ScriptRuntime.UNDEFINED && !strict)? Context.getGlobal() : thisArg;
5.1 --- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Thu Nov 27 18:02:28 2014 +0100 5.2 +++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Thu Nov 27 13:04:46 2014 +0100 5.3 @@ -26,6 +26,7 @@ 5.4 package jdk.nashorn.internal.runtime.linker; 5.5 5.6 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; 5.7 +import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 5.8 5.9 import java.lang.invoke.CallSite; 5.10 import java.lang.invoke.ConstantCallSite; 5.11 @@ -50,6 +51,8 @@ 5.12 import jdk.nashorn.internal.codegen.RuntimeCallSite; 5.13 import jdk.nashorn.internal.lookup.MethodHandleFactory; 5.14 import jdk.nashorn.internal.lookup.MethodHandleFunctionality; 5.15 +import jdk.nashorn.internal.objects.ScriptFunctionImpl; 5.16 +import jdk.nashorn.internal.runtime.ECMAException; 5.17 import jdk.nashorn.internal.runtime.JSType; 5.18 import jdk.nashorn.internal.runtime.OptimisticReturnFilters; 5.19 import jdk.nashorn.internal.runtime.ScriptFunction; 5.20 @@ -94,7 +97,7 @@ 5.21 new NashornLinker(), 5.22 new NashornPrimitiveLinker(), 5.23 new NashornStaticClassLinker(), 5.24 - new BoundDynamicMethodLinker(), 5.25 + new BoundCallableLinker(), 5.26 new JavaSuperAdapterLinker(), 5.27 new JSObjectLinker(nashornBeansLinker), 5.28 new BrowserJSObjectLinker(nashornBeansLinker), 5.29 @@ -136,19 +139,47 @@ 5.30 } 5.31 5.32 return obj instanceof ScriptFunction || 5.33 - ((obj instanceof JSObject) && ((JSObject)obj).isFunction()) || 5.34 - isDynamicMethod(obj) || 5.35 + isJSObjectFunction(obj) || 5.36 + BeansLinker.isDynamicMethod(obj) || 5.37 + obj instanceof BoundCallable || 5.38 isFunctionalInterfaceObject(obj) || 5.39 obj instanceof StaticClass; 5.40 } 5.41 5.42 /** 5.43 + * Returns true if the given object is a strict callable 5.44 + * @param callable the callable object to be checked for strictness 5.45 + * @return true if the obj is a strict callable, false if it is a non-strict callable. 5.46 + * @throws ECMAException with {@code TypeError} if the object is not a callable. 5.47 + */ 5.48 + public static boolean isStrictCallable(final Object callable) { 5.49 + if (callable instanceof ScriptFunction) { 5.50 + return ((ScriptFunction)callable).isStrict(); 5.51 + } else if (isJSObjectFunction(callable)) { 5.52 + return ((JSObject)callable).isStrictFunction(); 5.53 + } else if (callable instanceof BoundCallable) { 5.54 + return isStrictCallable(((BoundCallable)callable).getCallable()); 5.55 + } else if (BeansLinker.isDynamicMethod(callable) || callable instanceof StaticClass) { 5.56 + return false; 5.57 + } 5.58 + throw notFunction(callable); 5.59 + } 5.60 + 5.61 + private static ECMAException notFunction(final Object obj) { 5.62 + return typeError("not.a.function", ScriptRuntime.safeToString(obj)); 5.63 + } 5.64 + 5.65 + private static boolean isJSObjectFunction(final Object obj) { 5.66 + return obj instanceof JSObject && ((JSObject)obj).isFunction(); 5.67 + } 5.68 + 5.69 + /** 5.70 * Returns if the given object is a dynalink Dynamic method 5.71 * @param obj object to be checked 5.72 * @return true if the obj is a dynamic method 5.73 */ 5.74 public static boolean isDynamicMethod(final Object obj) { 5.75 - return obj instanceof BoundDynamicMethod || BeansLinker.isDynamicMethod(obj); 5.76 + return BeansLinker.isDynamicMethod(obj instanceof BoundCallable ? ((BoundCallable)obj).getCallable() : obj); 5.77 } 5.78 5.79 /** 5.80 @@ -370,14 +401,22 @@ 5.81 } 5.82 5.83 /** 5.84 - * Binds a bean dynamic method (returned by invoking {@code dyn:getMethod} on an object linked with 5.85 - * {@code BeansLinker} to a receiver. 5.86 - * @param dynamicMethod the dynamic method to bind 5.87 + * Binds any object Nashorn can use as a [[Callable]] to a receiver and optionally arguments. 5.88 + * @param callable the callable to bind 5.89 * @param boundThis the bound "this" value. 5.90 - * @return a bound dynamic method. 5.91 + * @param boundArgs the bound arguments. Can be either null or empty array to signify no arguments are bound. 5.92 + * @return a bound callable. 5.93 + * @throws ECMAException with {@code TypeError} if the object is not a callable. 5.94 */ 5.95 - public static Object bindDynamicMethod(final Object dynamicMethod, final Object boundThis) { 5.96 - return new BoundDynamicMethod(dynamicMethod, boundThis); 5.97 + public static Object bindCallable(final Object callable, final Object boundThis, final Object[] boundArgs) { 5.98 + if (callable instanceof ScriptFunctionImpl) { 5.99 + return ((ScriptFunctionImpl)callable).makeBoundFunction(boundThis, boundArgs); 5.100 + } else if (callable instanceof BoundCallable) { 5.101 + return ((BoundCallable)callable).bind(boundArgs); 5.102 + } else if (isCallable(callable)) { 5.103 + return new BoundCallable(callable, boundThis, boundArgs); 5.104 + } 5.105 + throw notFunction(callable); 5.106 } 5.107 5.108 /**
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/src/jdk/nashorn/internal/runtime/linker/BoundCallable.java Thu Nov 27 13:04:46 2014 +0100 6.3 @@ -0,0 +1,96 @@ 6.4 +/* 6.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6.7 + * 6.8 + * This code is free software; you can redistribute it and/or modify it 6.9 + * under the terms of the GNU General Public License version 2 only, as 6.10 + * published by the Free Software Foundation. Oracle designates this 6.11 + * particular file as subject to the "Classpath" exception as provided 6.12 + * by Oracle in the LICENSE file that accompanied this code. 6.13 + * 6.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 6.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 6.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 6.17 + * version 2 for more details (a copy is included in the LICENSE file that 6.18 + * accompanied this code). 6.19 + * 6.20 + * You should have received a copy of the GNU General Public License version 6.21 + * 2 along with this work; if not, write to the Free Software Foundation, 6.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 6.23 + * 6.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 6.25 + * or visit www.oracle.com if you need additional information or have any 6.26 + * questions. 6.27 + */ 6.28 + 6.29 +package jdk.nashorn.internal.runtime.linker; 6.30 + 6.31 +import java.util.Arrays; 6.32 +import jdk.nashorn.internal.runtime.ScriptRuntime; 6.33 + 6.34 +/** 6.35 + * Represents a Nashorn callable bound to a receiver and optionally arguments. Note that objects of this class 6.36 + * are just the tuples of a callable and a bound this and arguments, without any behavior. All the behavior is 6.37 + * defined in the {@code BoundCallableLinker}. 6.38 + */ 6.39 +public final class BoundCallable { 6.40 + private final Object callable; 6.41 + private final Object boundThis; 6.42 + private final Object[] boundArgs; 6.43 + 6.44 + BoundCallable(final Object callable, final Object boundThis, final Object[] boundArgs) { 6.45 + this.callable = callable; 6.46 + this.boundThis = boundThis; 6.47 + this.boundArgs = isEmptyArray(boundArgs) ? ScriptRuntime.EMPTY_ARRAY : boundArgs.clone(); 6.48 + } 6.49 + 6.50 + private BoundCallable(final BoundCallable original, final Object[] extraBoundArgs) { 6.51 + this.callable = original.callable; 6.52 + this.boundThis = original.boundThis; 6.53 + this.boundArgs = original.concatenateBoundArgs(extraBoundArgs); 6.54 + } 6.55 + 6.56 + Object getCallable() { 6.57 + return callable; 6.58 + } 6.59 + 6.60 + Object getBoundThis() { 6.61 + return boundThis; 6.62 + } 6.63 + 6.64 + Object[] getBoundArgs() { 6.65 + return boundArgs; 6.66 + } 6.67 + 6.68 + BoundCallable bind(final Object[] extraBoundArgs) { 6.69 + if (isEmptyArray(extraBoundArgs)) { 6.70 + return this; 6.71 + } 6.72 + return new BoundCallable(this, extraBoundArgs); 6.73 + } 6.74 + 6.75 + private Object[] concatenateBoundArgs(final Object[] extraBoundArgs) { 6.76 + if (boundArgs.length == 0) { 6.77 + return extraBoundArgs.clone(); 6.78 + } 6.79 + final int origBoundArgsLen = boundArgs.length; 6.80 + final int extraBoundArgsLen = extraBoundArgs.length; 6.81 + final Object[] newBoundArgs = new Object[origBoundArgsLen + extraBoundArgsLen]; 6.82 + System.arraycopy(boundArgs, 0, newBoundArgs, 0, origBoundArgsLen); 6.83 + System.arraycopy(extraBoundArgs, 0, newBoundArgs, origBoundArgsLen, extraBoundArgsLen); 6.84 + return newBoundArgs; 6.85 + } 6.86 + 6.87 + private static boolean isEmptyArray(final Object[] a) { 6.88 + return a == null || a.length == 0; 6.89 + } 6.90 + 6.91 + @Override 6.92 + public String toString() { 6.93 + final StringBuilder b = new StringBuilder(callable.toString()).append(" on ").append(boundThis); 6.94 + if (boundArgs.length != 0) { 6.95 + b.append(" with ").append(Arrays.toString(boundArgs)); 6.96 + } 6.97 + return b.toString(); 6.98 + } 6.99 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/src/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java Thu Nov 27 13:04:46 2014 +0100 7.3 @@ -0,0 +1,132 @@ 7.4 +/* 7.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 7.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 7.7 + * 7.8 + * This code is free software; you can redistribute it and/or modify it 7.9 + * under the terms of the GNU General Public License version 2 only, as 7.10 + * published by the Free Software Foundation. Oracle designates this 7.11 + * particular file as subject to the "Classpath" exception as provided 7.12 + * by Oracle in the LICENSE file that accompanied this code. 7.13 + * 7.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 7.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 7.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 7.17 + * version 2 for more details (a copy is included in the LICENSE file that 7.18 + * accompanied this code). 7.19 + * 7.20 + * You should have received a copy of the GNU General Public License version 7.21 + * 2 along with this work; if not, write to the Free Software Foundation, 7.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 7.23 + * 7.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 7.25 + * or visit www.oracle.com if you need additional information or have any 7.26 + * questions. 7.27 + */ 7.28 + 7.29 +package jdk.nashorn.internal.runtime.linker; 7.30 + 7.31 +import java.lang.invoke.MethodHandle; 7.32 +import java.lang.invoke.MethodHandles; 7.33 +import java.lang.invoke.MethodType; 7.34 +import java.util.Arrays; 7.35 +import jdk.internal.dynalink.CallSiteDescriptor; 7.36 +import jdk.internal.dynalink.linker.GuardedInvocation; 7.37 +import jdk.internal.dynalink.linker.LinkRequest; 7.38 +import jdk.internal.dynalink.linker.LinkerServices; 7.39 +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; 7.40 +import jdk.internal.dynalink.support.Guards; 7.41 + 7.42 +/** 7.43 + * Links {@link BoundCallable} objects. Passes through to linker services for linking a callable (for either 7.44 + * "dyn:call" or "dyn:new"), and modifies the returned invocation to deal with the receiver and argument binding. 7.45 + */ 7.46 +final class BoundCallableLinker implements TypeBasedGuardingDynamicLinker { 7.47 + @Override 7.48 + public boolean canLinkType(final Class<?> type) { 7.49 + return type == BoundCallable.class; 7.50 + } 7.51 + 7.52 + @Override 7.53 + public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { 7.54 + final Object objBoundCallable = linkRequest.getReceiver(); 7.55 + if(!(objBoundCallable instanceof BoundCallable)) { 7.56 + return null; 7.57 + } 7.58 + 7.59 + final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor(); 7.60 + if (descriptor.getNameTokenCount() < 2 || !"dyn".equals(descriptor.getNameToken(CallSiteDescriptor.SCHEME))) { 7.61 + return null; 7.62 + } 7.63 + final String operation = descriptor.getNameToken(CallSiteDescriptor.OPERATOR); 7.64 + // We need to distinguish "dyn:new" from "dyn:call" because "dyn:call" sites have parameter list of the form 7.65 + // "callee, this, args", while "dyn:call" sites have "callee, args" -- they lack the "this" parameter. 7.66 + final boolean isCall; 7.67 + if ("new".equals(operation)) { 7.68 + isCall = false; 7.69 + } else if ("call".equals(operation)) { 7.70 + isCall = true; 7.71 + } else { 7.72 + // Only dyn:call and dyn:new are supported. 7.73 + return null; 7.74 + } 7.75 + final BoundCallable boundCallable = (BoundCallable)objBoundCallable; 7.76 + final Object callable = boundCallable.getCallable(); 7.77 + final Object boundThis = boundCallable.getBoundThis(); 7.78 + 7.79 + // We need to ask the linker services for a delegate invocation on the target callable. 7.80 + 7.81 + // Replace arguments (boundCallable[, this], args) => (callable[, boundThis], boundArgs, args) when delegating 7.82 + final Object[] args = linkRequest.getArguments(); 7.83 + final Object[] boundArgs = boundCallable.getBoundArgs(); 7.84 + final int argsLen = args.length; 7.85 + final int boundArgsLen = boundArgs.length; 7.86 + final Object[] newArgs = new Object[argsLen + boundArgsLen]; 7.87 + newArgs[0] = callable; 7.88 + final int firstArgIndex; 7.89 + if (isCall) { 7.90 + newArgs[1] = boundThis; 7.91 + firstArgIndex = 2; 7.92 + } else { 7.93 + firstArgIndex = 1; 7.94 + } 7.95 + System.arraycopy(boundArgs, 0, newArgs, firstArgIndex, boundArgsLen); 7.96 + System.arraycopy(args, firstArgIndex, newArgs, firstArgIndex + boundArgsLen, argsLen - firstArgIndex); 7.97 + 7.98 + // Use R(T0, T1, T2, ...) => R(callable.class, boundThis.class, boundArg0.class, ..., boundArgn.class, T2, ...) 7.99 + // call site type when delegating to underlying linker (for dyn:new, there's no this). 7.100 + final MethodType type = descriptor.getMethodType(); 7.101 + // Use R(T0, ...) => R(callable.class, ...) 7.102 + MethodType newMethodType = descriptor.getMethodType().changeParameterType(0, callable.getClass()); 7.103 + if (isCall) { 7.104 + // R(callable.class, T1, ...) => R(callable.class, boundThis.class, ...) 7.105 + newMethodType = newMethodType.changeParameterType(1, boundThis.getClass()); 7.106 + } 7.107 + // R(callable.class[, boundThis.class], T2, ...) => R(callable.class[, boundThis.class], boundArg0.class, ..., boundArgn.class, T2, ...) 7.108 + for(int i = boundArgs.length; i-- > 0;) { 7.109 + newMethodType = newMethodType.insertParameterTypes(firstArgIndex, boundArgs[i] == null ? Object.class : boundArgs[i].getClass()); 7.110 + } 7.111 + final CallSiteDescriptor newDescriptor = descriptor.changeMethodType(newMethodType); 7.112 + 7.113 + // Delegate to target's linker 7.114 + final GuardedInvocation inv = linkerServices.getGuardedInvocation(linkRequest.replaceArguments(newDescriptor, newArgs)); 7.115 + if(inv == null) { 7.116 + return null; 7.117 + } 7.118 + 7.119 + // Bind (callable[, boundThis], boundArgs) to the delegate handle 7.120 + final MethodHandle boundHandle = MethodHandles.insertArguments(inv.getInvocation(), 0, 7.121 + Arrays.copyOf(newArgs, firstArgIndex + boundArgs.length)); 7.122 + final Class<?> p0Type = type.parameterType(0); 7.123 + final MethodHandle droppingHandle; 7.124 + if (isCall) { 7.125 + // Ignore incoming boundCallable and this 7.126 + droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type, type.parameterType(1)); 7.127 + } else { 7.128 + // Ignore incoming boundCallable 7.129 + droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type); 7.130 + } 7.131 + // Identity guard on boundCallable object 7.132 + final MethodHandle newGuard = Guards.getIdentityGuard(boundCallable); 7.133 + return inv.replaceMethods(droppingHandle, newGuard.asType(newGuard.type().changeParameterType(0, p0Type))); 7.134 + } 7.135 +}
8.1 --- a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java Thu Nov 27 18:02:28 2014 +0100 8.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 8.3 @@ -1,57 +0,0 @@ 8.4 -/* 8.5 - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 8.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 8.7 - * 8.8 - * This code is free software; you can redistribute it and/or modify it 8.9 - * under the terms of the GNU General Public License version 2 only, as 8.10 - * published by the Free Software Foundation. Oracle designates this 8.11 - * particular file as subject to the "Classpath" exception as provided 8.12 - * by Oracle in the LICENSE file that accompanied this code. 8.13 - * 8.14 - * This code is distributed in the hope that it will be useful, but WITHOUT 8.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 8.17 - * version 2 for more details (a copy is included in the LICENSE file that 8.18 - * accompanied this code). 8.19 - * 8.20 - * You should have received a copy of the GNU General Public License version 8.21 - * 2 along with this work; if not, write to the Free Software Foundation, 8.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 8.23 - * 8.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 8.25 - * or visit www.oracle.com if you need additional information or have any 8.26 - * questions. 8.27 - */ 8.28 - 8.29 -package jdk.nashorn.internal.runtime.linker; 8.30 - 8.31 -import java.util.Objects; 8.32 -import jdk.internal.dynalink.beans.BeansLinker; 8.33 - 8.34 -/** 8.35 - * Represents a Dynalink dynamic method bound to a receiver. Note that objects of this class are just the tuples of 8.36 - * a method and a bound this, without any behavior. All the behavior is defined in the {@code BoundDynamicMethodLinker}. 8.37 - */ 8.38 -final class BoundDynamicMethod { 8.39 - private final Object dynamicMethod; 8.40 - private final Object boundThis; 8.41 - 8.42 - BoundDynamicMethod(final Object dynamicMethod, final Object boundThis) { 8.43 - assert BeansLinker.isDynamicMethod(dynamicMethod); 8.44 - this.dynamicMethod = dynamicMethod; 8.45 - this.boundThis = boundThis; 8.46 - } 8.47 - 8.48 - Object getDynamicMethod() { 8.49 - return dynamicMethod; 8.50 - } 8.51 - 8.52 - Object getBoundThis() { 8.53 - return boundThis; 8.54 - } 8.55 - 8.56 - @Override 8.57 - public String toString() { 8.58 - return dynamicMethod.toString() + " on " + Objects.toString(boundThis); 8.59 - } 8.60 -}
9.1 --- a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java Thu Nov 27 18:02:28 2014 +0100 9.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 9.3 @@ -1,91 +0,0 @@ 9.4 -/* 9.5 - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 9.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 9.7 - * 9.8 - * This code is free software; you can redistribute it and/or modify it 9.9 - * under the terms of the GNU General Public License version 2 only, as 9.10 - * published by the Free Software Foundation. Oracle designates this 9.11 - * particular file as subject to the "Classpath" exception as provided 9.12 - * by Oracle in the LICENSE file that accompanied this code. 9.13 - * 9.14 - * This code is distributed in the hope that it will be useful, but WITHOUT 9.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 9.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 9.17 - * version 2 for more details (a copy is included in the LICENSE file that 9.18 - * accompanied this code). 9.19 - * 9.20 - * You should have received a copy of the GNU General Public License version 9.21 - * 2 along with this work; if not, write to the Free Software Foundation, 9.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 9.23 - * 9.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 9.25 - * or visit www.oracle.com if you need additional information or have any 9.26 - * questions. 9.27 - */ 9.28 - 9.29 -package jdk.nashorn.internal.runtime.linker; 9.30 - 9.31 -import java.lang.invoke.MethodHandle; 9.32 -import java.lang.invoke.MethodHandles; 9.33 -import java.lang.invoke.MethodType; 9.34 -import jdk.internal.dynalink.CallSiteDescriptor; 9.35 -import jdk.internal.dynalink.beans.BeansLinker; 9.36 -import jdk.internal.dynalink.linker.GuardedInvocation; 9.37 -import jdk.internal.dynalink.linker.LinkRequest; 9.38 -import jdk.internal.dynalink.linker.LinkerServices; 9.39 -import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; 9.40 -import jdk.internal.dynalink.support.Guards; 9.41 - 9.42 -/** 9.43 - * Links {@code BoundDynamicMethod} objects. Passes through to Dynalink's BeansLinker for linking a dynamic method 9.44 - * (they only respond to "dyn:call"), and modifies the returned invocation to deal with the receiver binding. 9.45 - */ 9.46 -final class BoundDynamicMethodLinker implements TypeBasedGuardingDynamicLinker { 9.47 - @Override 9.48 - public boolean canLinkType(final Class<?> type) { 9.49 - return type == BoundDynamicMethod.class; 9.50 - } 9.51 - 9.52 - @Override 9.53 - public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { 9.54 - final Object objBoundDynamicMethod = linkRequest.getReceiver(); 9.55 - if(!(objBoundDynamicMethod instanceof BoundDynamicMethod)) { 9.56 - return null; 9.57 - } 9.58 - 9.59 - final BoundDynamicMethod boundDynamicMethod = (BoundDynamicMethod)objBoundDynamicMethod; 9.60 - final Object dynamicMethod = boundDynamicMethod.getDynamicMethod(); 9.61 - final Object boundThis = boundDynamicMethod.getBoundThis(); 9.62 - 9.63 - // Replace arguments (boundDynamicMethod, this, ...) => (dynamicMethod, boundThis, ...) when delegating to 9.64 - // BeansLinker 9.65 - final Object[] args = linkRequest.getArguments(); 9.66 - args[0] = dynamicMethod; 9.67 - args[1] = boundThis; 9.68 - 9.69 - // Use R(T0, T1, ...) => R(dynamicMethod.class, boundThis.class, ...) call site type when delegating to 9.70 - // BeansLinker. 9.71 - final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor(); 9.72 - final MethodType type = descriptor.getMethodType(); 9.73 - final Class<?> dynamicMethodClass = dynamicMethod.getClass(); 9.74 - final CallSiteDescriptor newDescriptor = descriptor.changeMethodType( 9.75 - type.changeParameterType(0, dynamicMethodClass).changeParameterType(1, boundThis.getClass())); 9.76 - 9.77 - // Delegate to BeansLinker 9.78 - final GuardedInvocation inv = NashornBeansLinker.getGuardedInvocation(BeansLinker.getLinkerForClass(dynamicMethodClass), 9.79 - linkRequest.replaceArguments(newDescriptor, args), linkerServices); 9.80 - if(inv == null) { 9.81 - return null; 9.82 - } 9.83 - 9.84 - // Bind (dynamicMethod, boundThis) to the handle 9.85 - final MethodHandle boundHandle = MethodHandles.insertArguments(inv.getInvocation(), 0, dynamicMethod, boundThis); 9.86 - final Class<?> p0Type = type.parameterType(0); 9.87 - // Ignore incoming (boundDynamicMethod, this) 9.88 - final MethodHandle droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type, type.parameterType(1)); 9.89 - // Identity guard on boundDynamicMethod object 9.90 - final MethodHandle newGuard = Guards.getIdentityGuard(boundDynamicMethod); 9.91 - 9.92 - return inv.replaceMethods(droppingHandle, newGuard.asType(newGuard.type().changeParameterType(0, p0Type))); 9.93 - } 9.94 -}
10.1 --- a/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java Thu Nov 27 18:02:28 2014 +0100 10.2 +++ b/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java Thu Nov 27 13:04:46 2014 +0100 10.3 @@ -165,7 +165,7 @@ 10.4 */ 10.5 @SuppressWarnings("unused") 10.6 private static Object bindDynamicMethod(final Object dynamicMethod, final Object boundThis) { 10.7 - return dynamicMethod == null ? ScriptRuntime.UNDEFINED : Bootstrap.bindDynamicMethod(dynamicMethod, boundThis); 10.8 + return dynamicMethod == null ? ScriptRuntime.UNDEFINED : Bootstrap.bindCallable(dynamicMethod, boundThis, null); 10.9 } 10.10 10.11 /**
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/test/script/basic/JDK-8051778.js Thu Nov 27 13:04:46 2014 +0100 11.3 @@ -0,0 +1,83 @@ 11.4 +/* 11.5 + * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. 11.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 11.7 + * 11.8 + * This code is free software; you can redistribute it and/or modify it 11.9 + * under the terms of the GNU General Public License version 2 only, as 11.10 + * published by the Free Software Foundation. 11.11 + * 11.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 11.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11.15 + * version 2 for more details (a copy is included in the LICENSE file that 11.16 + * accompanied this code). 11.17 + * 11.18 + * You should have received a copy of the GNU General Public License version 11.19 + * 2 along with this work; if not, write to the Free Software Foundation, 11.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 11.21 + * 11.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 11.23 + * or visit www.oracle.com if you need additional information or have any 11.24 + * questions. 11.25 + */ 11.26 + 11.27 +/** 11.28 + * JDK-8051778: support bind on all Nashorn callables 11.29 + * 11.30 + * @test 11.31 + * @run 11.32 + */ 11.33 + 11.34 +var bind = Function.prototype.bind; 11.35 + 11.36 +// Bind a POJO method 11.37 +var l = new java.util.ArrayList(); 11.38 +var l_add_foo = bind.call(l.add, l, "foo"); 11.39 +l_add_foo(); 11.40 +print("l=" + l); 11.41 + 11.42 +// Bind a BoundCallable 11.43 +var l_add = bind.call(l.add, l); 11.44 +var l_add_foo2 = bind.call(l_add, null, "foo2"); 11.45 +l_add_foo2(); 11.46 +print("l=" + l); 11.47 + 11.48 +// Bind a POJO method retrieved from one instance to a different but 11.49 +// compatible instance. 11.50 +var l2 = new java.util.ArrayList(); 11.51 +var l2_size = bind.call(l.size, l2); 11.52 +print("l2_size()=" + l2_size()); 11.53 + 11.54 +// Bind a Java type object (used as a constructor). 11.55 +var construct_two = bind.call(java.lang.Integer, null, 2); 11.56 +print("Bound Integer(2) constructor: " + new construct_two()) 11.57 + 11.58 +// Bind a @FunctionalInterface proxying to an object literal. NOTE: the 11.59 +// expected value of this.a is always "original" and never "bound". This 11.60 +// might seem counterintuitive, but we are not binding the apply() 11.61 +// function of the object literal that defines the BiFunction behaviour, 11.62 +// we are binding the SAM proxy object instead, and it is always 11.63 +// forwarding to the apply() function with "this" set to the object 11.64 +// literal. Basically, binding "this" for SAM proxies is useless; only 11.65 +// binding arguments makes sense. 11.66 +var f1 = new java.util.function.BiFunction() { 11.67 + apply: function(x, y) { 11.68 + return "BiFunction with literal: " + this.a + ", " + x + ", " + y; 11.69 + }, 11.70 + a: "unbound" 11.71 +}; 11.72 +print((bind.call(f1, {a: "bound"}))(1, 2)) 11.73 +print((bind.call(f1, {a: "bound"}, 3))(4)) 11.74 +print((bind.call(f1, {a: "bound"}, 5, 6))()) 11.75 + 11.76 +// Bind a @FunctionalInterface proxying to a function. With the same 11.77 +// reasoning as above (binding the proxy vs. binding the JS function), 11.78 +// the value of this.a will always be undefined, and never "bound". 11.79 +var f2 = new java.util.function.BiFunction( 11.80 + function(x, y) { 11.81 + return "BiFunction with function: " + this.a + ", " + x + ", " + y; 11.82 + } 11.83 +); 11.84 +print((bind.call(f2, {a: "bound"}))(7, 8)) 11.85 +print((bind.call(f2, {a: "bound"}, 9))(10)) 11.86 +print((bind.call(f2, {a: "bound"}, 11, 12))())
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/test/script/basic/JDK-8051778.js.EXPECTED Thu Nov 27 13:04:46 2014 +0100 12.3 @@ -0,0 +1,10 @@ 12.4 +l=[foo] 12.5 +l=[foo, foo2] 12.6 +l2_size()=0 12.7 +Bound Integer(2) constructor: 2 12.8 +BiFunction with literal: unbound, 1, 2 12.9 +BiFunction with literal: unbound, 3, 4 12.10 +BiFunction with literal: unbound, 5, 6 12.11 +BiFunction with function: undefined, 7, 8 12.12 +BiFunction with function: undefined, 9, 10 12.13 +BiFunction with function: undefined, 11, 12