8017950: error.stack should be a string rather than an array
authorsundar
Wed, 26 Jun 2013 16:36:13 +0530
changeset 18616 05a084e63f71
parent 18615 3f6e6adcbc1a
child 18617 f6fe338f62c3
8017950: error.stack should be a string rather than an array Reviewed-by: hannesw, jlaskey
nashorn/src/jdk/nashorn/internal/objects/NativeError.java
nashorn/src/jdk/nashorn/internal/runtime/ECMAException.java
nashorn/test/script/basic/JDK-8012164.js
nashorn/test/script/basic/JDK-8012164.js.EXPECTED
nashorn/test/script/basic/JDK-8017950.js
nashorn/test/script/basic/JDK-8017950.js.EXPECTED
nashorn/test/script/basic/NASHORN-109.js
nashorn/test/script/basic/NASHORN-296.js
nashorn/test/script/basic/errorstack.js
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeError.java	Tue Jun 25 17:31:19 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeError.java	Wed Jun 26 16:36:13 2013 +0530
@@ -144,6 +144,30 @@
     }
 
     /**
+     * Nashorn extension: Error.prototype.getStackTrace()
+     * "stack" property is an array typed value containing {@link StackTraceElement}
+     * objects of JavaScript stack frames.
+     *
+     * @param self  self reference
+     *
+     * @return      stack trace as a script array.
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE)
+    public static Object getStackTrace(final Object self) {
+        Global.checkObject(self);
+        final ScriptObject sobj = (ScriptObject)self;
+        final Object exception = ECMAException.getException(sobj);
+        Object[] res;
+        if (exception instanceof Throwable) {
+            res = getScriptFrames((Throwable)exception);
+        } else {
+            res = ScriptRuntime.EMPTY_ARRAY;
+        }
+
+        return new NativeArray(res);
+    }
+
+    /**
      * Nashorn extension: Error.prototype.lineNumber
      *
      * @param self self reference
@@ -229,8 +253,8 @@
 
     /**
      * Nashorn extension: Error.prototype.stack
-     * "stack" property is an array typed value containing {@link StackTraceElement}
-     * objects of JavaScript stack frames.
+     * "stack" property is a string typed value containing JavaScript stack frames.
+     * Each frame information is separated bv "\n" character.
      *
      * @param self  self reference
      *
@@ -244,27 +268,28 @@
         }
 
         final Object exception = ECMAException.getException(sobj);
-        Object[] res;
+        final StringBuilder buf = new StringBuilder();
         if (exception instanceof Throwable) {
-            final StackTraceElement[] frames = ((Throwable)exception).getStackTrace();
-            final List<StackTraceElement> filtered = new ArrayList<>();
-            for (final StackTraceElement st : frames) {
-                if (ECMAErrors.isScriptFrame(st)) {
-                    final String className = "<" + st.getFileName() + ">";
-                    String methodName = st.getMethodName();
-                    if (methodName.equals(CompilerConstants.RUN_SCRIPT.symbolName())) {
-                        methodName = "<program>";
-                    }
-                    filtered.add(new StackTraceElement(className, methodName,
-                            st.getFileName(), st.getLineNumber()));
-                }
+            final Object[] frames = getScriptFrames((Throwable)exception);
+            for (final Object fr : frames) {
+                final StackTraceElement st = (StackTraceElement)fr;
+                buf.append(st.getMethodName());
+                buf.append(" @ ");
+                buf.append(st.getFileName());
+                buf.append(':');
+                buf.append(st.getLineNumber());
+                buf.append('\n');
             }
-            res = filtered.toArray();
+            final int len = buf.length();
+            // remove trailing '\n'
+            if (len > 0) {
+                assert buf.charAt(len - 1) == '\n';
+                buf.deleteCharAt(len - 1);
+            }
+            return buf.toString();
         } else {
-            res = ScriptRuntime.EMPTY_ARRAY;
+            return "";
         }
-
-        return new NativeArray(res);
     }
 
     /**
@@ -335,4 +360,21 @@
             throw new MethodHandleFactory.LookupException(e);
         }
     }
+
+    private static Object[] getScriptFrames(final Throwable exception) {
+        final StackTraceElement[] frames = ((Throwable)exception).getStackTrace();
+        final List<StackTraceElement> filtered = new ArrayList<>();
+        for (final StackTraceElement st : frames) {
+            if (ECMAErrors.isScriptFrame(st)) {
+                final String className = "<" + st.getFileName() + ">";
+                String methodName = st.getMethodName();
+                if (methodName.equals(CompilerConstants.RUN_SCRIPT.symbolName())) {
+                    methodName = "<program>";
+                }
+                filtered.add(new StackTraceElement(className, methodName,
+                        st.getFileName(), st.getLineNumber()));
+            }
+        }
+        return filtered.toArray();
+    }
 }
--- a/nashorn/src/jdk/nashorn/internal/runtime/ECMAException.java	Tue Jun 25 17:31:19 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ECMAException.java	Wed Jun 26 16:36:13 2013 +0530
@@ -51,7 +51,7 @@
     /** Field handle to the{@link ECMAException#thrown} field, so that it can be accessed from generated code */
     public static final FieldAccess THROWN = virtualField(ECMAException.class, "thrown", Object.class);
 
-    private static final String EXCEPTION_PROPERTY = "nashornException";
+    public static final String EXCEPTION_PROPERTY = "nashornException";
 
     /** Object thrown. */
     public final Object thrown;
--- a/nashorn/test/script/basic/JDK-8012164.js	Tue Jun 25 17:31:19 2013 +0530
+++ b/nashorn/test/script/basic/JDK-8012164.js	Wed Jun 26 16:36:13 2013 +0530
@@ -37,8 +37,9 @@
   try {
       throw new Error('foo');
   } catch (e) {
-      for (i in e.stack) {
-          printFrame(e.stack[i]);
+      var frames = e.getStackTrace();
+      for (i in frames) {
+          printFrame(frames[i]);
       }
   }
 }
--- a/nashorn/test/script/basic/JDK-8012164.js.EXPECTED	Tue Jun 25 17:31:19 2013 +0530
+++ b/nashorn/test/script/basic/JDK-8012164.js.EXPECTED	Wed Jun 26 16:36:13 2013 +0530
@@ -1,3 +1,3 @@
 <test/script/basic/JDK-8012164.js>.error(test/script/basic/JDK-8012164.js:38)
 <test/script/basic/JDK-8012164.js>.func(test/script/basic/JDK-8012164.js:33)
-<test/script/basic/JDK-8012164.js>.<program>(test/script/basic/JDK-8012164.js:46)
+<test/script/basic/JDK-8012164.js>.<program>(test/script/basic/JDK-8012164.js:47)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8017950.js	Wed Jun 26 16:36:13 2013 +0530
@@ -0,0 +1,47 @@
+/*
+ * 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-8017950: error.stack should be a string rather than an array
+ *
+ * @test
+ * @run
+ */
+
+function func() {
+    try {
+        throw new Error();
+    } catch (e){
+        print(e.stack.replace(/\\/g, '/'))
+    }
+}
+
+function f() { 
+    func()
+}
+
+function g() {
+    f()
+}
+
+g()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8017950.js.EXPECTED	Wed Jun 26 16:36:13 2013 +0530
@@ -0,0 +1,4 @@
+func @ test/script/basic/JDK-8017950.js:33
+f @ test/script/basic/JDK-8017950.js:40
+g @ test/script/basic/JDK-8017950.js:44
+<program> @ test/script/basic/JDK-8017950.js:47
--- a/nashorn/test/script/basic/NASHORN-109.js	Tue Jun 25 17:31:19 2013 +0530
+++ b/nashorn/test/script/basic/NASHORN-109.js	Wed Jun 26 16:36:13 2013 +0530
@@ -33,8 +33,9 @@
         throw new Error("error");
     }
 } catch (e) {
-    for (i in e.stack) { 
-        print(e.stack[i].methodName + ' ' + e.stack[i].lineNumber);
+    var frames = e.getStackTrace();
+    for (i in frames) {
+        print(frames[i].methodName + ' ' + frames[i].lineNumber);
     }
 }
 
--- a/nashorn/test/script/basic/NASHORN-296.js	Tue Jun 25 17:31:19 2013 +0530
+++ b/nashorn/test/script/basic/NASHORN-296.js	Wed Jun 26 16:36:13 2013 +0530
@@ -33,7 +33,7 @@
         load({ script: 'throw new Error()', name: name });
     } catch(e) {
         // normalize windows path separator to URL style
-        var actual = e.stack[0].fileName;
+        var actual = e.getStackTrace()[0].fileName;
         if (actual !== name) {
             fail("expected file name to be " + name +
                  ", actually got file name " + actual);
@@ -48,6 +48,6 @@
 try {
     throw new Error();
 } catch (e) {
-    test(e.stack[0].fileName.substring(6));
+    test(e.getStackTrace()[0].fileName.substring(6));
 }
 
--- a/nashorn/test/script/basic/errorstack.js	Tue Jun 25 17:31:19 2013 +0530
+++ b/nashorn/test/script/basic/errorstack.js	Wed Jun 26 16:36:13 2013 +0530
@@ -22,7 +22,7 @@
  */
 
 /**
- * "stack" property of Error objects. (nashorn extension).
+ * "getStackTrace()" method of Error objects. (nashorn extension).
  *
  * @test
  * @run
@@ -43,9 +43,9 @@
 try {
     func1();
 } catch (e) {
-    // "stack" is java.lang.StackTraceElement object
-    for (i in e.stack) {
-        print(e.stack[i].methodName + " : " + e.stack[i].lineNumber);
+    var frames = e.getStackTrace();
+    for (i in frames) {
+        print(frames[i].methodName + " : " + frames[i].lineNumber);
     }
 }