8051778: support bind on all Nashorn callables

Thu, 27 Nov 2014 13:04:46 +0100

author
attila
date
Thu, 27 Nov 2014 13:04:46 +0100
changeset 1110
a56051d3cdf5
parent 1109
f39081a16f71
child 1111
32fa6a8e1f82

8051778: support bind on all Nashorn callables
Reviewed-by: hannesw, lagergren

src/jdk/nashorn/internal/objects/NativeFunction.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/NativeObject.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/linker/Bootstrap.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/linker/BoundCallable.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java file | annotate | diff | comparison | revisions
test/script/basic/JDK-8051778.js file | annotate | diff | comparison | revisions
test/script/basic/JDK-8051778.js.EXPECTED file | annotate | diff | comparison | revisions
     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

mercurial