8020223: ClassCastException: String can not be casted to ScriptFunction
Reviewed-by: attila, lagergren
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java Fri Jul 12 15:01:33 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java Fri Jul 12 15:27:16 2013 +0530
@@ -622,12 +622,15 @@
case "getMethod":
final FindProperty find = adaptee.findProperty(__call__, true);
if (find != null) {
- final ScriptFunctionImpl func = (ScriptFunctionImpl)getObjectValue(find);
- // TODO: It's a shame we need to produce a function bound to this and name, when we'd only need it bound
- // to name. Probably not a big deal, but if we can ever make it leaner, it'd be nice.
- return new GuardedInvocation(MH.dropArguments(MH.constant(Object.class,
- func.makeBoundFunction(this, new Object[] { name })), 0, Object.class),
- adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), __call__), testJSAdaptor(adaptee, null, null, null));
+ final Object value = getObjectValue(find);
+ if (value instanceof ScriptFunction) {
+ final ScriptFunctionImpl func = (ScriptFunctionImpl)value;
+ // TODO: It's a shame we need to produce a function bound to this and name, when we'd only need it bound
+ // to name. Probably not a big deal, but if we can ever make it leaner, it'd be nice.
+ return new GuardedInvocation(MH.dropArguments(MH.constant(Object.class,
+ func.makeBoundFunction(this, new Object[] { name })), 0, Object.class),
+ adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), __call__), testJSAdaptor(adaptee, null, null, null));
+ }
}
throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this));
default:
@@ -687,16 +690,19 @@
final MethodType type = desc.getMethodType();
if (findData != null) {
final String name = desc.getNameTokenCount() > 2 ? desc.getNameToken(2) : null;
- final ScriptFunction func = (ScriptFunction)getObjectValue(findData);
+ final Object value = getObjectValue(findData);
+ if (value instanceof ScriptFunction) {
+ final ScriptFunction func = (ScriptFunction)value;
- final MethodHandle methodHandle = getCallMethodHandle(findData, type,
+ final MethodHandle methodHandle = getCallMethodHandle(findData, type,
useName ? name : null);
- if (methodHandle != null) {
- return new GuardedInvocation(
- methodHandle,
- adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), hook),
- testJSAdaptor(adaptee, findData.getGetter(Object.class), findData.getOwner(), func));
- }
+ if (methodHandle != null) {
+ return new GuardedInvocation(
+ methodHandle,
+ adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), hook),
+ testJSAdaptor(adaptee, findData.getGetter(Object.class), findData.getOwner(), func));
+ }
+ }
}
switch (hook) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Fri Jul 12 15:01:33 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Fri Jul 12 15:27:16 2013 +0530
@@ -1978,7 +1978,12 @@
return noSuchProperty(desc, request);
}
- final ScriptFunction func = (ScriptFunction)getObjectValue(find);
+ final Object value = getObjectValue(find);
+ if (! (value instanceof ScriptFunction)) {
+ return createEmptyGetter(desc, name);
+ }
+
+ final ScriptFunction func = (ScriptFunction)value;
final Object thiz = scopeCall && func.isStrict() ? ScriptRuntime.UNDEFINED : this;
// TODO: It'd be awesome if we could bind "name" without binding "this".
return new GuardedInvocation(MH.dropArguments(MH.constant(ScriptFunction.class,
@@ -1998,8 +2003,13 @@
final boolean scopeAccess = isScope() && NashornCallSiteDescriptor.isScope(desc);
if (find != null) {
- final ScriptFunction func = (ScriptFunction)getObjectValue(find);
- MethodHandle methodHandle = getCallMethodHandle(func, desc.getMethodType(), name);
+ final Object value = getObjectValue(find);
+ ScriptFunction func = null;
+ MethodHandle methodHandle = null;
+ if (value instanceof ScriptFunction) {
+ func = (ScriptFunction)value;
+ methodHandle = getCallMethodHandle(func, desc.getMethodType(), name);
+ }
if (methodHandle != null) {
if (scopeAccess && func.isStrict()) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8020223.js Fri Jul 12 15:27:16 2013 +0530
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ *
+ * 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-8020223: ClassCastException: String can not be casted to ScriptFunction
+ *
+ * @test
+ * @run
+ */
+
+__noSuchMethod__ = "";
+
+try {
+ foo();
+ fail("Must have thrown exception");
+} catch (e) {
+ if (! (e instanceof TypeError)) {
+ fail("TypeError expected, got " + e);
+ }
+}
+
+__noSuchProperty__ = 23;
+
+try {
+ foo;
+ fail("Must have thrown exception");
+} catch (e) {
+ if (! (e instanceof ReferenceError)) {
+ fail("ReferenceError expected, got " + e);
+ }
+}
+
+var obj = new JSAdapter() {
+ __get__: 332,
+ __call__: "hello"
+}
+
+try {
+ obj.foo; // should just be undefined
+} catch (e) {
+ fail("unexpected error : " + e);
+}
+
+try {
+ obj.foo();
+ fail("Must have thrown exception");
+} catch(e) {
+ if (! (e instanceof TypeError)) {
+ fail("TypeError expected, got " + e);
+ }
+}