--- old/./README 2017-01-24 15:05:11.000000000 +0100 +++ new/./README 2017-01-24 15:05:11.000000000 +0100 @@ -18,7 +18,7 @@ http://mercurial.selenic.com/wiki/ForestExtension -and downlaoded using +and downloaded using hg clone https://bitbucket.org/gxti/hgforest @@ -39,7 +39,7 @@ - How to build? To build Nashorn, you need to install JDK 9. You may use the Nashorn -forest build (recommended) or down load from java.net. You will need to +forest build (recommended) or download from java.net. You will need to set JAVA_HOME environmental variable to point to your JDK installation directory. --- old/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java 2017-01-24 15:05:12.000000000 +0100 +++ new/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java 2017-01-24 15:05:12.000000000 +0100 @@ -395,39 +395,45 @@ } /** - * Applies argument filters to both the invocation and the guard (if there - * is one) with {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)}. + * Applies argument filters to both the invocation and the guard + * (if it exists and has at least {@code pos + 1} parameters) with + * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)}. * @param pos the position of the first argument being filtered * @param filters the argument filters * @return a filtered invocation */ public GuardedInvocation filterArguments(final int pos, final MethodHandle... filters) { - return replaceMethods(MethodHandles.filterArguments(invocation, pos, filters), guard == null ? null : - MethodHandles.filterArguments(guard, pos, filters)); + return replaceMethods(MethodHandles.filterArguments(invocation, pos, filters), + guard == null || pos >= guard.type().parameterCount() ? + guard : MethodHandles.filterArguments(guard, pos, filters)); } /** * Makes an invocation that drops arguments in both the invocation and the - * guard (if there is one) with {@link MethodHandles#dropArguments(MethodHandle, int, List)}. + * guard (if it exists and has at least {@code pos} parameters) with + * {@link MethodHandles#dropArguments(MethodHandle, int, List)}. * @param pos the position of the first argument being dropped * @param valueTypes the types of the values being dropped * @return an invocation that drops arguments */ public GuardedInvocation dropArguments(final int pos, final List> valueTypes) { - return replaceMethods(MethodHandles.dropArguments(invocation, pos, valueTypes), guard == null ? null : - MethodHandles.dropArguments(guard, pos, valueTypes)); + return replaceMethods(MethodHandles.dropArguments(invocation, pos, valueTypes), + guard == null || pos > guard.type().parameterCount() ? + guard : MethodHandles.dropArguments(guard, pos, valueTypes)); } /** * Makes an invocation that drops arguments in both the invocation and the - * guard (if there is one) with {@link MethodHandles#dropArguments(MethodHandle, int, Class...)}. + * guard (if it exists and has at least {@code pos} parameters) with + * {@link MethodHandles#dropArguments(MethodHandle, int, Class...)}. * @param pos the position of the first argument being dropped * @param valueTypes the types of the values being dropped * @return an invocation that drops arguments */ public GuardedInvocation dropArguments(final int pos, final Class... valueTypes) { - return replaceMethods(MethodHandles.dropArguments(invocation, pos, valueTypes), guard == null ? null : - MethodHandles.dropArguments(guard, pos, valueTypes)); + return replaceMethods(MethodHandles.dropArguments(invocation, pos, valueTypes), + guard == null || pos > guard.type().parameterCount() ? + guard : MethodHandles.dropArguments(guard, pos, valueTypes)); } --- old/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/linker/NashornLinkerExporter.java 2017-01-24 15:05:13.000000000 +0100 +++ new/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/linker/NashornLinkerExporter.java 2017-01-24 15:05:13.000000000 +0100 @@ -38,7 +38,7 @@ /** * This linker exporter is a service provider that exports Nashorn Dynalink - * linkers to external users. Other languague runtimes that use Dynalink + * linkers to external users. Other language runtimes that use Dynalink * can use the linkers exported by this provider to support tight integration * of Nashorn objects. */ --- old/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java 2017-01-24 15:05:14.000000000 +0100 +++ new/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java 2017-01-24 15:05:14.000000000 +0100 @@ -735,7 +735,7 @@ /** * Name getter - ECMA Function.name * - * @param self self refence + * @param self self reference * @return the name, or undefined if none */ public static Object G$name(final Object self) { @@ -1120,12 +1120,19 @@ assert appliedRequest != null; // Bootstrap.isCallable() returned true for args[1], so it must produce a linkage. final Class applyFnType = descType.parameterType(0); - MethodHandle inv = appliedInvocation.getInvocation(); //method handle from apply invocation. the applied function invocation + // Invocation and guard handles from apply invocation. + MethodHandle inv = appliedInvocation.getInvocation(); + MethodHandle guard = appliedInvocation.getGuard(); if (isApply && !isFailedApplyToCall) { if (passesArgs) { // Make sure that the passed argArray is converted to Object[] the same way NativeFunction.apply() would do it. inv = MH.filterArguments(inv, 2, NativeFunction.TO_APPLY_ARGS); + // Some guards (non-strict functions with non-primitive this) have a this-object parameter, so we + // need to apply this transformations to them as well. + if (guard.type().parameterCount() > 2) { + guard = MH.filterArguments(guard, 2, NativeFunction.TO_APPLY_ARGS); + } } else { // If the original call site doesn't pass argArray, pass in an empty array inv = MH.insertArguments(inv, 2, (Object) ScriptRuntime.EMPTY_ARRAY); @@ -1144,12 +1151,25 @@ if (!passesThis) { // If the original call site doesn't pass in a thisArg, pass in Global/undefined as needed - inv = bindImplicitThis(appliedFn, inv); + inv = bindImplicitThis(appliedFnNeedsWrappedThis, inv); + // guard may have this-parameter that needs to be inserted + if (guard.type().parameterCount() > 1) { + guard = bindImplicitThis(appliedFnNeedsWrappedThis, guard); + } } else if (appliedFnNeedsWrappedThis) { // target function needs a wrapped this, so make sure we filter for that inv = MH.filterArguments(inv, 1, WRAP_THIS); + // guard may have this-parameter that needs to be wrapped + if (guard.type().parameterCount() > 1) { + guard = MH.filterArguments(guard, 1, WRAP_THIS); + } } + + final MethodType guardType = guard.type(); // Needed for combining guards below + + // We need to account for the dropped (apply|call) function argument. inv = MH.dropArguments(inv, 0, applyFnType); + guard = MH.dropArguments(guard, 0, applyFnType); /* * Dropargs can only be non-()V in the case of isApply && !isFailedApplyToCall, which @@ -1160,15 +1180,6 @@ inv = MH.dropArguments(inv, 4 + i, dropArgs.parameterType(i)); } - MethodHandle guard = appliedInvocation.getGuard(); - // If the guard checks the value of "this" but we aren't passing thisArg, insert the default one - if (!passesThis && guard.type().parameterCount() > 1) { - guard = bindImplicitThis(appliedFn, guard); - } - final MethodType guardType = guard.type(); - - // We need to account for the dropped (apply|call) function argument. - guard = MH.dropArguments(guard, 0, descType.parameterType(0)); // Take the "isApplyFunction" guard, and bind it to this function. MethodHandle applyFnGuard = MH.insertArguments(IS_APPLY_FUNCTION, 2, this); //TODO replace this with switchpoint // Adapt the guard to receive all the arguments that the original guard does. @@ -1244,9 +1255,9 @@ return ScriptObject.adaptHandleToVarArgCallSite(arrayConvertingGuard, descParamCount); } - private static MethodHandle bindImplicitThis(final Object fn, final MethodHandle mh) { + private static MethodHandle bindImplicitThis(final boolean needsWrappedThis, final MethodHandle mh) { final MethodHandle bound; - if (fn instanceof ScriptFunction && ((ScriptFunction) fn).needsWrappedThis()) { + if (needsWrappedThis) { bound = MH.filterArguments(mh, 1, SCRIPTFUNCTION_GLOBALFILTER); } else { bound = mh; --- /dev/null 2017-01-24 15:05:15.000000000 +0100 +++ new/test/script/basic/JDK-8166186.js 2017-01-24 15:05:15.000000000 +0100 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2016, 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. + */ + +/** + * 8166186: ClassCastException with arguments usage + * + * @test + * @run + */ + +function F (arg) { + print("F called"); + Function.prototype.call.apply(G, arguments); +} + +function G (){ + print("G called"); + print(this); + if (C++ > 5) return; + F("argument " + C); +} + +var C = 0; + +G(); --- /dev/null 2017-01-24 15:05:16.000000000 +0100 +++ new/test/script/basic/JDK-8166186.js.EXPECTED 2017-01-24 15:05:16.000000000 +0100 @@ -0,0 +1,20 @@ +G called +[object global] +F called +G called +argument 1 +F called +G called +argument 2 +F called +G called +argument 3 +F called +G called +argument 4 +F called +G called +argument 5 +F called +G called +argument 6