8166186: ClassCastException with arguments usage

Reviewed-by: attila, sundar
This commit is contained in:
Hannes Wallnöfer 2017-01-25 09:49:02 +01:00
parent b11a5c2059
commit a043135fe4
6 changed files with 109 additions and 27 deletions

View File

@ -18,7 +18,7 @@ Information about the forest extension can be found at
http://mercurial.selenic.com/wiki/ForestExtension
and downlaoded using
and downloaded using
hg clone https://bitbucket.org/gxti/hgforest

View File

@ -395,39 +395,45 @@ public class GuardedInvocation {
}
/**
* 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<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));
}
/**
* 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));
}

View File

@ -38,7 +38,7 @@ import jdk.nashorn.internal.runtime.linker.Bootstrap;
/**
* 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.
*/

View File

@ -735,7 +735,7 @@ public class ScriptFunction extends ScriptObject {
/**
* 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 @@ public class ScriptFunction extends ScriptObject {
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 @@ public class ScriptFunction extends ScriptObject {
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 @@ public class ScriptFunction extends ScriptObject {
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 @@ public class ScriptFunction extends ScriptObject {
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;

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2017, 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();

View File

@ -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