8017950: error.stack should be a string rather than an array
Reviewed-by: hannesw, jlaskey
--- 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);
}
}