8073733: TypeError messages with "call" and "new" could be improved
authorsundar
Tue, 04 Aug 2015 18:18:54 +0530
changeset 32048 8023426b93ab
parent 31945 eeea9adfd1e3
child 32049 af8f6292d54d
8073733: TypeError messages with "call" and "new" could be improved Reviewed-by: attila, mhaupt
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SharedScopeCall.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties
nashorn/test/script/basic/JDK-8026016.js.EXPECTED
nashorn/test/script/basic/JDK-8073733.js
nashorn/test/script/basic/JDK-8073733.js.EXPECTED
nashorn/test/script/basic/errors.js.EXPECTED
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Wed Jul 05 20:44:11 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Tue Aug 04 18:18:54 2015 +0530
@@ -1480,7 +1480,7 @@
                     }
                     @Override
                     void consumeStack() {
-                        dynamicCall(2 + argsCount, flags);
+                        dynamicCall(2 + argsCount, flags, ident.getName());
                     }
                 }.emit();
             }
@@ -1538,7 +1538,7 @@
                     @Override
                     void consumeStack() {
                         // Ordinary call
-                        dynamicCall(2 + argsCount, flags);
+                        dynamicCall(2 + argsCount, flags, "eval");
                         method._goto(eval_done);
 
                         method.label(invoke_direct_eval);
@@ -1610,7 +1610,7 @@
                     }
                     @Override
                     void consumeStack() {
-                        dynamicCall(2 + argCount, flags);
+                        dynamicCall(2 + argCount, flags, node.getProperty());
                     }
                 }.emit();
 
@@ -1637,7 +1637,7 @@
                     void consumeStack() {
                         final int flags = getCallSiteFlags();
                         //assert callNodeType.equals(callee.getReturnType()) : callNodeType + " != " + callee.getReturnType();
-                        dynamicCall(2 + argsCount, flags);
+                        dynamicCall(2 + argsCount, flags, origCallee.getName());
                     }
                 }.emit();
                 return false;
@@ -1667,7 +1667,7 @@
                     @Override
                     void consumeStack() {
                         final int flags = getCallSiteFlags();
-                        dynamicCall(2 + argsCount, flags);
+                        dynamicCall(2 + argsCount, flags, null);
                     }
                 }.emit();
                 return false;
@@ -1687,7 +1687,7 @@
                         @Override
                         void consumeStack() {
                             final int flags = getCallSiteFlags() | CALLSITE_SCOPE;
-                            dynamicCall(2 + argsCount, flags);
+                            dynamicCall(2 + argsCount, flags, null);
                         }
                 }.emit();
                 return false;
@@ -3707,10 +3707,12 @@
         final CallNode callNode = (CallNode)unaryNode.getExpression();
         final List<Expression> args   = callNode.getArgs();
 
+        final Expression func = callNode.getFunction();
         // Load function reference.
-        loadExpressionAsObject(callNode.getFunction()); // must detect type error
-
-        method.dynamicNew(1 + loadArgs(args), getCallSiteFlags());
+        loadExpressionAsObject(func); // must detect type error
+
+        method.dynamicNew(1 + loadArgs(args), getCallSiteFlags(),
+            func instanceof IdentNode? ((IdentNode)func).getName() : null);
     }
 
     private void loadNOT(final UnaryNode unaryNode) {
@@ -4818,11 +4820,11 @@
             return method.dynamicGetIndex(resultBounds.within(expression.getType()), nonOptimisticFlags(flags), isMethod);
         }
 
-        MethodEmitter dynamicCall(final int argCount, final int flags) {
+        MethodEmitter dynamicCall(final int argCount, final int flags, final String msg) {
             if (isOptimistic) {
-                return method.dynamicCall(getOptimisticCoercedType(), argCount, getOptimisticFlags(flags));
-            }
-            return method.dynamicCall(resultBounds.within(expression.getType()), argCount, nonOptimisticFlags(flags));
+                return method.dynamicCall(getOptimisticCoercedType(), argCount, getOptimisticFlags(flags), msg);
+            }
+            return method.dynamicCall(resultBounds.within(expression.getType()), argCount, nonOptimisticFlags(flags), msg);
         }
 
         int getOptimisticFlags(final int flags) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java	Wed Jul 05 20:44:11 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java	Tue Aug 04 18:18:54 2015 +0530
@@ -2132,10 +2132,25 @@
      * @return the method emitter
      */
     MethodEmitter dynamicNew(final int argCount, final int flags) {
+        return dynamicNew(argCount, flags, null);
+    }
+
+    /**
+     * Generate a dynamic new
+     *
+     * @param argCount  number of arguments
+     * @param flags     callsite flags
+     * @param msg        additional message to be used when reporting error
+     *
+     * @return the method emitter
+     */
+    MethodEmitter dynamicNew(final int argCount, final int flags, final String msg) {
         assert !isOptimistic(flags);
         debug("dynamic_new", "argcount=", argCount);
         final String signature = getDynamicSignature(Type.OBJECT, argCount);
-        method.visitInvokeDynamicInsn("dyn:new", signature, LINKERBOOTSTRAP, flags);
+        method.visitInvokeDynamicInsn(
+                msg != null && msg.length() < LARGE_STRING_THRESHOLD? "dyn:new:" + NameCodec.encode(msg) : "dyn:new",
+                signature, LINKERBOOTSTRAP, flags);
         pushType(Type.OBJECT); //TODO fix result type
         return this;
     }
@@ -2150,10 +2165,26 @@
      * @return the method emitter
      */
     MethodEmitter dynamicCall(final Type returnType, final int argCount, final int flags) {
+        return dynamicCall(returnType, argCount, flags, null);
+    }
+
+    /**
+     * Generate a dynamic call
+     *
+     * @param returnType return type
+     * @param argCount   number of arguments
+     * @param flags      callsite flags
+     * @param msg        additional message to be used when reporting error
+     *
+     * @return the method emitter
+     */
+    MethodEmitter dynamicCall(final Type returnType, final int argCount, final int flags, final String msg) {
         debug("dynamic_call", "args=", argCount, "returnType=", returnType);
         final String signature = getDynamicSignature(returnType, argCount); // +1 because the function itself is the 1st parameter for dynamic calls (what you call - call target)
         debug("   signature", signature);
-        method.visitInvokeDynamicInsn("dyn:call", signature, LINKERBOOTSTRAP, flags);
+        method.visitInvokeDynamicInsn(
+                msg != null && msg.length() < LARGE_STRING_THRESHOLD? "dyn:call:" + NameCodec.encode(msg) : "dyn:call",
+                signature, LINKERBOOTSTRAP, flags);
         pushType(returnType);
 
         return this;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SharedScopeCall.java	Wed Jul 05 20:44:11 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SharedScopeCall.java	Tue Aug 04 18:18:54 2015 +0530
@@ -169,7 +169,7 @@
                 slot += type.getSlots();
             }
             // Shared scope calls disabled in optimistic world. TODO is this right?
-            method.dynamicCall(returnType, 2 + paramTypes.length, flags);
+            method.dynamicCall(returnType, 2 + paramTypes.length, flags, symbol.getName());
         }
 
         method._return(returnType);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java	Wed Jul 05 20:44:11 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java	Tue Aug 04 18:18:54 2015 +0530
@@ -96,8 +96,12 @@
 
         switch (operator) {
         case "new":
-        case "call":
-            throw lookupTypeError("cant.call.undefined", desc);
+        case "call": {
+            final String name = desc.getNameTokenCount() > 2? desc.getNameToken(2) : null;
+            final String msg = name != null? "cant.call.undefined.arg" : "cant.call.undefined";
+            throw typeError(msg, name);
+        }
+
         case "callMethod":
             throw lookupTypeError("cant.read.property.of.undefined", desc);
         // NOTE: we support getElem and setItem as JavaScript doesn't distinguish items from properties. Nashorn itself
@@ -125,7 +129,8 @@
     }
 
     private static ECMAException lookupTypeError(final String msg, final CallSiteDescriptor desc) {
-        return typeError(msg, desc.getNameTokenCount() > 2 ? desc.getNameToken(2) : null);
+        final String name = desc.getNameToken(2);
+        return typeError(msg, name != null && !name.isEmpty()? name : null);
     }
 
     private static final MethodHandle GET_METHOD = findOwnMH("get", Object.class, Object.class);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Wed Jul 05 20:44:11 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Tue Aug 04 18:18:54 2015 +0530
@@ -150,7 +150,7 @@
     public static NashornCallSiteDescriptor get(final MethodHandles.Lookup lookup, final String name,
             final MethodType methodType, final int flags) {
         final String[] tokenizedName = CallSiteDescriptorFactory.tokenizeName(name);
-        assert tokenizedName.length == 2 || tokenizedName.length == 3;
+        assert tokenizedName.length >= 2;
         assert "dyn".equals(tokenizedName[0]);
         assert tokenizedName[1] != null;
         // TODO: see if we can move mangling/unmangling into Dynalink
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties	Wed Jul 05 20:44:11 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties	Tue Aug 04 18:18:54 2015 +0530
@@ -87,6 +87,7 @@
 
 # operations not permitted on undefined
 type.error.cant.call.undefined=Cannot call undefined
+type.error.cant.call.undefined.arg=Cannot call "{0}" that has undefined value
 type.error.cant.read.property.of.undefined=Cannot read property "{0}" from undefined
 type.error.cant.set.property.of.undefined=Cannot set property "{0}" of undefined
 type.error.cant.delete.property.of.undefined=Cannot delete property "{0}" of undefined
--- a/nashorn/test/script/basic/JDK-8026016.js.EXPECTED	Wed Jul 05 20:44:11 2017 +0200
+++ b/nashorn/test/script/basic/JDK-8026016.js.EXPECTED	Tue Aug 04 18:18:54 2015 +0530
@@ -1,182 +1,182 @@
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such method _,0
-no such method _,1
-no such method _,2
-no such method _,3
-no such method _,4
-no such method _,5
-no such method _,6
-no such method _,7
-no such method _,8
-no such method _,9
-no such method _,10
-no such method _,11
-no such method _,12
-no such method _,13
-no such method _,14
-no such method _,15
-no such method _,16
-no such method _,17
-no such method _,18
-no such method _,19
-no such method _,20
-no such method _,21
-no such method _,22
-no such method _,23
-no such method _,24
-no such method _,25
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+TypeError: Cannot call "_" that has undefined value
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such method _,0
+no such method _,1
+no such method _,2
+no such method _,3
+no such method _,4
+no such method _,5
+no such method _,6
+no such method _,7
+no such method _,8
+no such method _,9
+no such method _,10
+no such method _,11
+no such method _,12
+no such method _,13
+no such method _,14
+no such method _,15
+no such method _,16
+no such method _,17
+no such method _,18
+no such method _,19
+no such method _,20
+no such method _,21
+no such method _,22
+no such method _,23
+no such method _,24
+no such method _,25
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+TypeError: Cannot call "_" that has undefined value
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8073733.js	Tue Aug 04 18:18:54 2015 +0530
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, 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-8073733: TypeError messages with "call" and "new" could be improved
+ *
+ * @test
+ * @run
+ */
+
+var func = undefined;
+try {
+    func();
+} catch (e) {
+    print(e);
+}
+
+var obj = {};
+try {
+    obj.foo();
+} catch (e) {
+    print(e);
+}
+
+try {
+    new func();
+} catch (e) {
+    print(e);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8073733.js.EXPECTED	Tue Aug 04 18:18:54 2015 +0530
@@ -0,0 +1,3 @@
+TypeError: Cannot call "func" that has undefined value
+TypeError: Cannot call "foo" that has undefined value
+TypeError: Cannot call "func" that has undefined value
--- a/nashorn/test/script/basic/errors.js.EXPECTED	Wed Jul 05 20:44:11 2017 +0200
+++ b/nashorn/test/script/basic/errors.js.EXPECTED	Tue Aug 04 18:18:54 2015 +0530
@@ -1,31 +1,31 @@
-Error is a function
-EvalError is a function
-RangeError is a function
-ReferenceError is a function
-SyntaxError is a function
-TypeError is a function
-URIError is a function
-Error.arity 1
-EvalError.arity 1
-RangeError.arity 1
-ReferenceError.arity 1
-SyntaxError.arity 1
-TypeError.arity 1
-URIError.arity 1
-true
-my error
-Error
-thrown @ 49
-true
-ReferenceError
-"foo" is not defined
-true
-TypeError
-Cannot call undefined
-Error
-EvalError
-RangeError
-ReferenceError
-SyntaxError
-TypeError
-URIError
+Error is a function
+EvalError is a function
+RangeError is a function
+ReferenceError is a function
+SyntaxError is a function
+TypeError is a function
+URIError is a function
+Error.arity 1
+EvalError.arity 1
+RangeError.arity 1
+ReferenceError.arity 1
+SyntaxError.arity 1
+TypeError.arity 1
+URIError.arity 1
+true
+my error
+Error
+thrown @ 49
+true
+ReferenceError
+"foo" is not defined
+true
+TypeError
+Cannot call "foo_method" that has undefined value
+Error
+EvalError
+RangeError
+ReferenceError
+SyntaxError
+TypeError
+URIError