--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFunction.java Fri Nov 21 17:44:57 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFunction.java Thu Nov 27 13:04:46 2014 +0100
@@ -48,6 +48,7 @@
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.runtime.linker.Bootstrap;
/**
* ECMA 15.3 Function Objects
@@ -204,11 +205,7 @@
* @return function with bound arguments
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
- public static ScriptFunction bind(final Object self, final Object... args) {
- if (!(self instanceof ScriptFunction)) {
- throw typeError("not.a.function", ScriptRuntime.safeToString(self));
- }
-
+ public static Object bind(final Object self, final Object... args) {
final Object thiz = (args.length == 0) ? UNDEFINED : args[0];
Object[] arguments;
@@ -219,7 +216,7 @@
arguments = ScriptRuntime.EMPTY_ARRAY;
}
- return ((ScriptFunctionImpl)self).makeBoundFunction(thiz, arguments);
+ return Bootstrap.bindCallable(self, thiz, arguments);
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java Fri Nov 21 17:44:57 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java Thu Nov 27 13:04:46 2014 +0100
@@ -28,6 +28,7 @@
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@@ -804,7 +805,7 @@
// name and object linked with BeansLinker. (Actually, an even stronger assumption is true: return value is
// constant for any given method name and object's class.)
return MethodHandles.dropArguments(MethodHandles.constant(Object.class,
- Bootstrap.bindDynamicMethod(methodGetter.invoke(source), source)), 0, Object.class);
+ Bootstrap.bindCallable(methodGetter.invoke(source), source, null)), 0, Object.class);
} catch(RuntimeException|Error e) {
throw e;
} catch(final Throwable t) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ScriptFunctionImpl.java Fri Nov 21 17:44:57 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ScriptFunctionImpl.java Thu Nov 27 13:04:46 2014 +0100
@@ -30,7 +30,6 @@
import java.lang.invoke.MethodHandle;
import java.util.ArrayList;
-
import jdk.nashorn.internal.runtime.AccessorProperty;
import jdk.nashorn.internal.runtime.GlobalFunctions;
import jdk.nashorn.internal.runtime.Property;
@@ -237,13 +236,13 @@
/**
* Same as {@link ScriptFunction#makeBoundFunction(Object, Object[])}. The only reason we override it is so that we
- * can expose it to methods in this package.
+ * can expose it.
* @param self the self to bind to this function. Can be null (in which case, null is bound as this).
* @param args additional arguments to bind to this function. Can be null or empty to not bind additional arguments.
* @return a function with the specified self and parameters bound.
*/
@Override
- protected ScriptFunction makeBoundFunction(final Object self, final Object[] args) {
+ public ScriptFunction makeBoundFunction(final Object self, final Object[] args) {
return super.makeBoundFunction(self, args);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IteratorAction.java Fri Nov 21 17:44:57 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IteratorAction.java Thu Nov 27 13:04:46 2014 +0100
@@ -25,11 +25,7 @@
package jdk.nashorn.internal.runtime.arrays;
-import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
-
-import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.runtime.Context;
-import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
@@ -98,17 +94,7 @@
* @return result of apply
*/
public final T apply() {
- final boolean strict;
- if (callbackfn instanceof ScriptFunction) {
- strict = ((ScriptFunction)callbackfn).isStrict();
- } else if (callbackfn instanceof JSObject &&
- ((JSObject)callbackfn).isFunction()) {
- strict = ((JSObject)callbackfn).isStrictFunction();
- } else if (Bootstrap.isDynamicMethod(callbackfn) || Bootstrap.isFunctionalInterfaceObject(callbackfn)) {
- strict = false;
- } else {
- throw typeError("not.a.function", ScriptRuntime.safeToString(callbackfn));
- }
+ final boolean strict = Bootstrap.isStrictCallable(callbackfn);
// for non-strict callback, need to translate undefined thisArg to be global object
thisArg = (thisArg == ScriptRuntime.UNDEFINED && !strict)? Context.getGlobal() : thisArg;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java Fri Nov 21 17:44:57 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java Thu Nov 27 13:04:46 2014 +0100
@@ -26,6 +26,7 @@
package jdk.nashorn.internal.runtime.linker;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantCallSite;
@@ -50,6 +51,8 @@
import jdk.nashorn.internal.codegen.RuntimeCallSite;
import jdk.nashorn.internal.lookup.MethodHandleFactory;
import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
+import jdk.nashorn.internal.objects.ScriptFunctionImpl;
+import jdk.nashorn.internal.runtime.ECMAException;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.OptimisticReturnFilters;
import jdk.nashorn.internal.runtime.ScriptFunction;
@@ -94,7 +97,7 @@
new NashornLinker(),
new NashornPrimitiveLinker(),
new NashornStaticClassLinker(),
- new BoundDynamicMethodLinker(),
+ new BoundCallableLinker(),
new JavaSuperAdapterLinker(),
new JSObjectLinker(nashornBeansLinker),
new BrowserJSObjectLinker(nashornBeansLinker),
@@ -136,19 +139,47 @@
}
return obj instanceof ScriptFunction ||
- ((obj instanceof JSObject) && ((JSObject)obj).isFunction()) ||
- isDynamicMethod(obj) ||
+ isJSObjectFunction(obj) ||
+ BeansLinker.isDynamicMethod(obj) ||
+ obj instanceof BoundCallable ||
isFunctionalInterfaceObject(obj) ||
obj instanceof StaticClass;
}
/**
+ * Returns true if the given object is a strict callable
+ * @param callable the callable object to be checked for strictness
+ * @return true if the obj is a strict callable, false if it is a non-strict callable.
+ * @throws ECMAException with {@code TypeError} if the object is not a callable.
+ */
+ public static boolean isStrictCallable(final Object callable) {
+ if (callable instanceof ScriptFunction) {
+ return ((ScriptFunction)callable).isStrict();
+ } else if (isJSObjectFunction(callable)) {
+ return ((JSObject)callable).isStrictFunction();
+ } else if (callable instanceof BoundCallable) {
+ return isStrictCallable(((BoundCallable)callable).getCallable());
+ } else if (BeansLinker.isDynamicMethod(callable) || callable instanceof StaticClass) {
+ return false;
+ }
+ throw notFunction(callable);
+ }
+
+ private static ECMAException notFunction(final Object obj) {
+ return typeError("not.a.function", ScriptRuntime.safeToString(obj));
+ }
+
+ private static boolean isJSObjectFunction(final Object obj) {
+ return obj instanceof JSObject && ((JSObject)obj).isFunction();
+ }
+
+ /**
* Returns if the given object is a dynalink Dynamic method
* @param obj object to be checked
* @return true if the obj is a dynamic method
*/
public static boolean isDynamicMethod(final Object obj) {
- return obj instanceof BoundDynamicMethod || BeansLinker.isDynamicMethod(obj);
+ return BeansLinker.isDynamicMethod(obj instanceof BoundCallable ? ((BoundCallable)obj).getCallable() : obj);
}
/**
@@ -370,14 +401,22 @@
}
/**
- * Binds a bean dynamic method (returned by invoking {@code dyn:getMethod} on an object linked with
- * {@code BeansLinker} to a receiver.
- * @param dynamicMethod the dynamic method to bind
+ * Binds any object Nashorn can use as a [[Callable]] to a receiver and optionally arguments.
+ * @param callable the callable to bind
* @param boundThis the bound "this" value.
- * @return a bound dynamic method.
+ * @param boundArgs the bound arguments. Can be either null or empty array to signify no arguments are bound.
+ * @return a bound callable.
+ * @throws ECMAException with {@code TypeError} if the object is not a callable.
*/
- public static Object bindDynamicMethod(final Object dynamicMethod, final Object boundThis) {
- return new BoundDynamicMethod(dynamicMethod, boundThis);
+ public static Object bindCallable(final Object callable, final Object boundThis, final Object[] boundArgs) {
+ if (callable instanceof ScriptFunctionImpl) {
+ return ((ScriptFunctionImpl)callable).makeBoundFunction(boundThis, boundArgs);
+ } else if (callable instanceof BoundCallable) {
+ return ((BoundCallable)callable).bind(boundArgs);
+ } else if (isCallable(callable)) {
+ return new BoundCallable(callable, boundThis, boundArgs);
+ }
+ throw notFunction(callable);
}
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BoundCallable.java Thu Nov 27 13:04:46 2014 +0100
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+package jdk.nashorn.internal.runtime.linker;
+
+import java.util.Arrays;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+
+/**
+ * Represents a Nashorn callable bound to a receiver and optionally arguments. Note that objects of this class
+ * are just the tuples of a callable and a bound this and arguments, without any behavior. All the behavior is
+ * defined in the {@code BoundCallableLinker}.
+ */
+public final class BoundCallable {
+ private final Object callable;
+ private final Object boundThis;
+ private final Object[] boundArgs;
+
+ BoundCallable(final Object callable, final Object boundThis, final Object[] boundArgs) {
+ this.callable = callable;
+ this.boundThis = boundThis;
+ this.boundArgs = isEmptyArray(boundArgs) ? ScriptRuntime.EMPTY_ARRAY : boundArgs.clone();
+ }
+
+ private BoundCallable(final BoundCallable original, final Object[] extraBoundArgs) {
+ this.callable = original.callable;
+ this.boundThis = original.boundThis;
+ this.boundArgs = original.concatenateBoundArgs(extraBoundArgs);
+ }
+
+ Object getCallable() {
+ return callable;
+ }
+
+ Object getBoundThis() {
+ return boundThis;
+ }
+
+ Object[] getBoundArgs() {
+ return boundArgs;
+ }
+
+ BoundCallable bind(final Object[] extraBoundArgs) {
+ if (isEmptyArray(extraBoundArgs)) {
+ return this;
+ }
+ return new BoundCallable(this, extraBoundArgs);
+ }
+
+ private Object[] concatenateBoundArgs(final Object[] extraBoundArgs) {
+ if (boundArgs.length == 0) {
+ return extraBoundArgs.clone();
+ }
+ final int origBoundArgsLen = boundArgs.length;
+ final int extraBoundArgsLen = extraBoundArgs.length;
+ final Object[] newBoundArgs = new Object[origBoundArgsLen + extraBoundArgsLen];
+ System.arraycopy(boundArgs, 0, newBoundArgs, 0, origBoundArgsLen);
+ System.arraycopy(extraBoundArgs, 0, newBoundArgs, origBoundArgsLen, extraBoundArgsLen);
+ return newBoundArgs;
+ }
+
+ private static boolean isEmptyArray(final Object[] a) {
+ return a == null || a.length == 0;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder b = new StringBuilder(callable.toString()).append(" on ").append(boundThis);
+ if (boundArgs.length != 0) {
+ b.append(" with ").append(Arrays.toString(boundArgs));
+ }
+ return b.toString();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java Thu Nov 27 13:04:46 2014 +0100
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+package jdk.nashorn.internal.runtime.linker;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.util.Arrays;
+import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.linker.GuardedInvocation;
+import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.internal.dynalink.linker.LinkerServices;
+import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
+import jdk.internal.dynalink.support.Guards;
+
+/**
+ * Links {@link BoundCallable} objects. Passes through to linker services for linking a callable (for either
+ * "dyn:call" or "dyn:new"), and modifies the returned invocation to deal with the receiver and argument binding.
+ */
+final class BoundCallableLinker implements TypeBasedGuardingDynamicLinker {
+ @Override
+ public boolean canLinkType(final Class<?> type) {
+ return type == BoundCallable.class;
+ }
+
+ @Override
+ public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
+ final Object objBoundCallable = linkRequest.getReceiver();
+ if(!(objBoundCallable instanceof BoundCallable)) {
+ return null;
+ }
+
+ final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
+ if (descriptor.getNameTokenCount() < 2 || !"dyn".equals(descriptor.getNameToken(CallSiteDescriptor.SCHEME))) {
+ return null;
+ }
+ final String operation = descriptor.getNameToken(CallSiteDescriptor.OPERATOR);
+ // We need to distinguish "dyn:new" from "dyn:call" because "dyn:call" sites have parameter list of the form
+ // "callee, this, args", while "dyn:call" sites have "callee, args" -- they lack the "this" parameter.
+ final boolean isCall;
+ if ("new".equals(operation)) {
+ isCall = false;
+ } else if ("call".equals(operation)) {
+ isCall = true;
+ } else {
+ // Only dyn:call and dyn:new are supported.
+ return null;
+ }
+ final BoundCallable boundCallable = (BoundCallable)objBoundCallable;
+ final Object callable = boundCallable.getCallable();
+ final Object boundThis = boundCallable.getBoundThis();
+
+ // We need to ask the linker services for a delegate invocation on the target callable.
+
+ // Replace arguments (boundCallable[, this], args) => (callable[, boundThis], boundArgs, args) when delegating
+ final Object[] args = linkRequest.getArguments();
+ final Object[] boundArgs = boundCallable.getBoundArgs();
+ final int argsLen = args.length;
+ final int boundArgsLen = boundArgs.length;
+ final Object[] newArgs = new Object[argsLen + boundArgsLen];
+ newArgs[0] = callable;
+ final int firstArgIndex;
+ if (isCall) {
+ newArgs[1] = boundThis;
+ firstArgIndex = 2;
+ } else {
+ firstArgIndex = 1;
+ }
+ System.arraycopy(boundArgs, 0, newArgs, firstArgIndex, boundArgsLen);
+ System.arraycopy(args, firstArgIndex, newArgs, firstArgIndex + boundArgsLen, argsLen - firstArgIndex);
+
+ // Use R(T0, T1, T2, ...) => R(callable.class, boundThis.class, boundArg0.class, ..., boundArgn.class, T2, ...)
+ // call site type when delegating to underlying linker (for dyn:new, there's no this).
+ final MethodType type = descriptor.getMethodType();
+ // Use R(T0, ...) => R(callable.class, ...)
+ MethodType newMethodType = descriptor.getMethodType().changeParameterType(0, callable.getClass());
+ if (isCall) {
+ // R(callable.class, T1, ...) => R(callable.class, boundThis.class, ...)
+ newMethodType = newMethodType.changeParameterType(1, boundThis.getClass());
+ }
+ // R(callable.class[, boundThis.class], T2, ...) => R(callable.class[, boundThis.class], boundArg0.class, ..., boundArgn.class, T2, ...)
+ for(int i = boundArgs.length; i-- > 0;) {
+ newMethodType = newMethodType.insertParameterTypes(firstArgIndex, boundArgs[i] == null ? Object.class : boundArgs[i].getClass());
+ }
+ final CallSiteDescriptor newDescriptor = descriptor.changeMethodType(newMethodType);
+
+ // Delegate to target's linker
+ final GuardedInvocation inv = linkerServices.getGuardedInvocation(linkRequest.replaceArguments(newDescriptor, newArgs));
+ if(inv == null) {
+ return null;
+ }
+
+ // Bind (callable[, boundThis], boundArgs) to the delegate handle
+ final MethodHandle boundHandle = MethodHandles.insertArguments(inv.getInvocation(), 0,
+ Arrays.copyOf(newArgs, firstArgIndex + boundArgs.length));
+ final Class<?> p0Type = type.parameterType(0);
+ final MethodHandle droppingHandle;
+ if (isCall) {
+ // Ignore incoming boundCallable and this
+ droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type, type.parameterType(1));
+ } else {
+ // Ignore incoming boundCallable
+ droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type);
+ }
+ // Identity guard on boundCallable object
+ final MethodHandle newGuard = Guards.getIdentityGuard(boundCallable);
+ return inv.replaceMethods(droppingHandle, newGuard.asType(newGuard.type().changeParameterType(0, p0Type)));
+ }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java Fri Nov 21 17:44:57 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +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.
- */
-
-package jdk.nashorn.internal.runtime.linker;
-
-import java.util.Objects;
-import jdk.internal.dynalink.beans.BeansLinker;
-
-/**
- * Represents a Dynalink dynamic method bound to a receiver. Note that objects of this class are just the tuples of
- * a method and a bound this, without any behavior. All the behavior is defined in the {@code BoundDynamicMethodLinker}.
- */
-final class BoundDynamicMethod {
- private final Object dynamicMethod;
- private final Object boundThis;
-
- BoundDynamicMethod(final Object dynamicMethod, final Object boundThis) {
- assert BeansLinker.isDynamicMethod(dynamicMethod);
- this.dynamicMethod = dynamicMethod;
- this.boundThis = boundThis;
- }
-
- Object getDynamicMethod() {
- return dynamicMethod;
- }
-
- Object getBoundThis() {
- return boundThis;
- }
-
- @Override
- public String toString() {
- return dynamicMethod.toString() + " on " + Objects.toString(boundThis);
- }
-}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java Fri Nov 21 17:44:57 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +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.
- */
-
-package jdk.nashorn.internal.runtime.linker;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import jdk.internal.dynalink.CallSiteDescriptor;
-import jdk.internal.dynalink.beans.BeansLinker;
-import jdk.internal.dynalink.linker.GuardedInvocation;
-import jdk.internal.dynalink.linker.LinkRequest;
-import jdk.internal.dynalink.linker.LinkerServices;
-import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
-import jdk.internal.dynalink.support.Guards;
-
-/**
- * Links {@code BoundDynamicMethod} objects. Passes through to Dynalink's BeansLinker for linking a dynamic method
- * (they only respond to "dyn:call"), and modifies the returned invocation to deal with the receiver binding.
- */
-final class BoundDynamicMethodLinker implements TypeBasedGuardingDynamicLinker {
- @Override
- public boolean canLinkType(final Class<?> type) {
- return type == BoundDynamicMethod.class;
- }
-
- @Override
- public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
- final Object objBoundDynamicMethod = linkRequest.getReceiver();
- if(!(objBoundDynamicMethod instanceof BoundDynamicMethod)) {
- return null;
- }
-
- final BoundDynamicMethod boundDynamicMethod = (BoundDynamicMethod)objBoundDynamicMethod;
- final Object dynamicMethod = boundDynamicMethod.getDynamicMethod();
- final Object boundThis = boundDynamicMethod.getBoundThis();
-
- // Replace arguments (boundDynamicMethod, this, ...) => (dynamicMethod, boundThis, ...) when delegating to
- // BeansLinker
- final Object[] args = linkRequest.getArguments();
- args[0] = dynamicMethod;
- args[1] = boundThis;
-
- // Use R(T0, T1, ...) => R(dynamicMethod.class, boundThis.class, ...) call site type when delegating to
- // BeansLinker.
- final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
- final MethodType type = descriptor.getMethodType();
- final Class<?> dynamicMethodClass = dynamicMethod.getClass();
- final CallSiteDescriptor newDescriptor = descriptor.changeMethodType(
- type.changeParameterType(0, dynamicMethodClass).changeParameterType(1, boundThis.getClass()));
-
- // Delegate to BeansLinker
- final GuardedInvocation inv = NashornBeansLinker.getGuardedInvocation(BeansLinker.getLinkerForClass(dynamicMethodClass),
- linkRequest.replaceArguments(newDescriptor, args), linkerServices);
- if(inv == null) {
- return null;
- }
-
- // Bind (dynamicMethod, boundThis) to the handle
- final MethodHandle boundHandle = MethodHandles.insertArguments(inv.getInvocation(), 0, dynamicMethod, boundThis);
- final Class<?> p0Type = type.parameterType(0);
- // Ignore incoming (boundDynamicMethod, this)
- final MethodHandle droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type, type.parameterType(1));
- // Identity guard on boundDynamicMethod object
- final MethodHandle newGuard = Guards.getIdentityGuard(boundDynamicMethod);
-
- return inv.replaceMethods(droppingHandle, newGuard.asType(newGuard.type().changeParameterType(0, p0Type)));
- }
-}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java Fri Nov 21 17:44:57 2014 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java Thu Nov 27 13:04:46 2014 +0100
@@ -165,7 +165,7 @@
*/
@SuppressWarnings("unused")
private static Object bindDynamicMethod(final Object dynamicMethod, final Object boundThis) {
- return dynamicMethod == null ? ScriptRuntime.UNDEFINED : Bootstrap.bindDynamicMethod(dynamicMethod, boundThis);
+ return dynamicMethod == null ? ScriptRuntime.UNDEFINED : Bootstrap.bindCallable(dynamicMethod, boundThis, null);
}
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8051778.js Thu Nov 27 13:04:46 2014 +0100
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2014 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.
+ *
+ * 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.
+ */
+
+/**
+ * JDK-8051778: support bind on all Nashorn callables
+ *
+ * @test
+ * @run
+ */
+
+var bind = Function.prototype.bind;
+
+// Bind a POJO method
+var l = new java.util.ArrayList();
+var l_add_foo = bind.call(l.add, l, "foo");
+l_add_foo();
+print("l=" + l);
+
+// Bind a BoundCallable
+var l_add = bind.call(l.add, l);
+var l_add_foo2 = bind.call(l_add, null, "foo2");
+l_add_foo2();
+print("l=" + l);
+
+// Bind a POJO method retrieved from one instance to a different but
+// compatible instance.
+var l2 = new java.util.ArrayList();
+var l2_size = bind.call(l.size, l2);
+print("l2_size()=" + l2_size());
+
+// Bind a Java type object (used as a constructor).
+var construct_two = bind.call(java.lang.Integer, null, 2);
+print("Bound Integer(2) constructor: " + new construct_two())
+
+// Bind a @FunctionalInterface proxying to an object literal. NOTE: the
+// expected value of this.a is always "original" and never "bound". This
+// might seem counterintuitive, but we are not binding the apply()
+// function of the object literal that defines the BiFunction behaviour,
+// we are binding the SAM proxy object instead, and it is always
+// forwarding to the apply() function with "this" set to the object
+// literal. Basically, binding "this" for SAM proxies is useless; only
+// binding arguments makes sense.
+var f1 = new java.util.function.BiFunction() {
+ apply: function(x, y) {
+ return "BiFunction with literal: " + this.a + ", " + x + ", " + y;
+ },
+ a: "unbound"
+};
+print((bind.call(f1, {a: "bound"}))(1, 2))
+print((bind.call(f1, {a: "bound"}, 3))(4))
+print((bind.call(f1, {a: "bound"}, 5, 6))())
+
+// Bind a @FunctionalInterface proxying to a function. With the same
+// reasoning as above (binding the proxy vs. binding the JS function),
+// the value of this.a will always be undefined, and never "bound".
+var f2 = new java.util.function.BiFunction(
+ function(x, y) {
+ return "BiFunction with function: " + this.a + ", " + x + ", " + y;
+ }
+);
+print((bind.call(f2, {a: "bound"}))(7, 8))
+print((bind.call(f2, {a: "bound"}, 9))(10))
+print((bind.call(f2, {a: "bound"}, 11, 12))())
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8051778.js.EXPECTED Thu Nov 27 13:04:46 2014 +0100
@@ -0,0 +1,10 @@
+l=[foo]
+l=[foo, foo2]
+l2_size()=0
+Bound Integer(2) constructor: 2
+BiFunction with literal: unbound, 1, 2
+BiFunction with literal: unbound, 3, 4
+BiFunction with literal: unbound, 5, 6
+BiFunction with function: undefined, 7, 8
+BiFunction with function: undefined, 9, 10
+BiFunction with function: undefined, 11, 12