Wed, 26 Jun 2013 19:42:17 +0530
8014781: support Error.captureStackTrace
Reviewed-by: jlaskey, hannesw
1.1 --- a/src/jdk/nashorn/api/scripting/NashornException.java Wed Jun 26 15:40:52 2013 +0200 1.2 +++ b/src/jdk/nashorn/api/scripting/NashornException.java Wed Jun 26 19:42:17 2013 +0530 1.3 @@ -25,6 +25,9 @@ 1.4 1.5 package jdk.nashorn.api.scripting; 1.6 1.7 +import java.util.ArrayList; 1.8 +import java.util.List; 1.9 +import jdk.nashorn.internal.codegen.CompilerConstants; 1.10 import jdk.nashorn.internal.runtime.ECMAErrors; 1.11 1.12 /** 1.13 @@ -136,4 +139,52 @@ 1.14 return column; 1.15 } 1.16 1.17 + /** 1.18 + * Returns array javascript stack frames from the given exception object. 1.19 + * 1.20 + * @param exception exception from which stack frames are retrieved and filtered 1.21 + * @return array of javascript stack frames 1.22 + */ 1.23 + public static StackTraceElement[] getScriptFrames(final Throwable exception) { 1.24 + final StackTraceElement[] frames = ((Throwable)exception).getStackTrace(); 1.25 + final List<StackTraceElement> filtered = new ArrayList<>(); 1.26 + for (final StackTraceElement st : frames) { 1.27 + if (ECMAErrors.isScriptFrame(st)) { 1.28 + final String className = "<" + st.getFileName() + ">"; 1.29 + String methodName = st.getMethodName(); 1.30 + if (methodName.equals(CompilerConstants.RUN_SCRIPT.symbolName())) { 1.31 + methodName = "<program>"; 1.32 + } 1.33 + filtered.add(new StackTraceElement(className, methodName, 1.34 + st.getFileName(), st.getLineNumber())); 1.35 + } 1.36 + } 1.37 + return filtered.toArray(new StackTraceElement[filtered.size()]); 1.38 + } 1.39 + 1.40 + /** 1.41 + * Return a formatted script stack trace string with frames information separated by '\n' 1.42 + * 1.43 + * @param exception exception for which script stack string is returned 1.44 + * @return formatted stack trace string 1.45 + */ 1.46 + public static String getScriptStackString(final Throwable exception) { 1.47 + final StringBuilder buf = new StringBuilder(); 1.48 + final StackTraceElement[] frames = getScriptFrames((Throwable)exception); 1.49 + for (final StackTraceElement st : frames) { 1.50 + buf.append(st.getMethodName()); 1.51 + buf.append(" @ "); 1.52 + buf.append(st.getFileName()); 1.53 + buf.append(':'); 1.54 + buf.append(st.getLineNumber()); 1.55 + buf.append('\n'); 1.56 + } 1.57 + final int len = buf.length(); 1.58 + // remove trailing '\n' 1.59 + if (len > 0) { 1.60 + assert buf.charAt(len - 1) == '\n'; 1.61 + buf.deleteCharAt(len - 1); 1.62 + } 1.63 + return buf.toString(); 1.64 + } 1.65 }
2.1 --- a/src/jdk/nashorn/internal/objects/NativeError.java Wed Jun 26 15:40:52 2013 +0200 2.2 +++ b/src/jdk/nashorn/internal/objects/NativeError.java Wed Jun 26 19:42:17 2013 +0530 2.3 @@ -32,6 +32,7 @@ 2.4 import java.lang.invoke.MethodHandles; 2.5 import java.util.ArrayList; 2.6 import java.util.List; 2.7 +import jdk.nashorn.api.scripting.NashornException; 2.8 import jdk.nashorn.internal.codegen.CompilerConstants; 2.9 import jdk.nashorn.internal.lookup.MethodHandleFactory; 2.10 import jdk.nashorn.internal.objects.annotations.Attribute; 2.11 @@ -119,6 +120,20 @@ 2.12 } 2.13 2.14 /** 2.15 + * Nashorn extension: Error.captureStackTrace. Capture stack trace at the point of call into the Error object provided. 2.16 + * 2.17 + * @param self self reference 2.18 + */ 2.19 + @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 2.20 + public static Object captureStackTrace(final Object self, final Object errorObj) { 2.21 + Global.checkObject(errorObj); 2.22 + final ScriptObject sobj = (ScriptObject)errorObj; 2.23 + final ECMAException exp = new ECMAException(sobj, null); 2.24 + sobj.set("stack", NashornException.getScriptStackString(exp), false); 2.25 + return UNDEFINED; 2.26 + } 2.27 + 2.28 + /** 2.29 * Nashorn extension: Error.dumpStack 2.30 * dumps the stack of the current thread. 2.31 * 2.32 @@ -163,7 +178,7 @@ 2.33 final Object exception = ECMAException.getException(sobj); 2.34 Object[] res; 2.35 if (exception instanceof Throwable) { 2.36 - res = getScriptFrames((Throwable)exception); 2.37 + res = NashornException.getScriptFrames((Throwable)exception); 2.38 } else { 2.39 res = ScriptRuntime.EMPTY_ARRAY; 2.40 } 2.41 @@ -272,25 +287,8 @@ 2.42 } 2.43 2.44 final Object exception = ECMAException.getException(sobj); 2.45 - final StringBuilder buf = new StringBuilder(); 2.46 if (exception instanceof Throwable) { 2.47 - final Object[] frames = getScriptFrames((Throwable)exception); 2.48 - for (final Object fr : frames) { 2.49 - final StackTraceElement st = (StackTraceElement)fr; 2.50 - buf.append(st.getMethodName()); 2.51 - buf.append(" @ "); 2.52 - buf.append(st.getFileName()); 2.53 - buf.append(':'); 2.54 - buf.append(st.getLineNumber()); 2.55 - buf.append('\n'); 2.56 - } 2.57 - final int len = buf.length(); 2.58 - // remove trailing '\n' 2.59 - if (len > 0) { 2.60 - assert buf.charAt(len - 1) == '\n'; 2.61 - buf.deleteCharAt(len - 1); 2.62 - } 2.63 - return buf.toString(); 2.64 + return NashornException.getScriptStackString((Throwable)exception); 2.65 } else { 2.66 return ""; 2.67 } 2.68 @@ -364,21 +362,4 @@ 2.69 throw new MethodHandleFactory.LookupException(e); 2.70 } 2.71 } 2.72 - 2.73 - private static Object[] getScriptFrames(final Throwable exception) { 2.74 - final StackTraceElement[] frames = ((Throwable)exception).getStackTrace(); 2.75 - final List<StackTraceElement> filtered = new ArrayList<>(); 2.76 - for (final StackTraceElement st : frames) { 2.77 - if (ECMAErrors.isScriptFrame(st)) { 2.78 - final String className = "<" + st.getFileName() + ">"; 2.79 - String methodName = st.getMethodName(); 2.80 - if (methodName.equals(CompilerConstants.RUN_SCRIPT.symbolName())) { 2.81 - methodName = "<program>"; 2.82 - } 2.83 - filtered.add(new StackTraceElement(className, methodName, 2.84 - st.getFileName(), st.getLineNumber())); 2.85 - } 2.86 - } 2.87 - return filtered.toArray(); 2.88 - } 2.89 }
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/test/script/basic/JDK-8014781.js Wed Jun 26 19:42:17 2013 +0530 3.3 @@ -0,0 +1,40 @@ 3.4 +/* 3.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3.7 + * 3.8 + * This code is free software; you can redistribute it and/or modify it 3.9 + * under the terms of the GNU General Public License version 2 only, as 3.10 + * published by the Free Software Foundation. 3.11 + * 3.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 3.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 3.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 3.15 + * version 2 for more details (a copy is included in the LICENSE file that 3.16 + * accompanied this code). 3.17 + * 3.18 + * You should have received a copy of the GNU General Public License version 3.19 + * 2 along with this work; if not, write to the Free Software Foundation, 3.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 3.21 + * 3.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 3.23 + * or visit www.oracle.com if you need additional information or have any 3.24 + * questions. 3.25 + */ 3.26 + 3.27 +/** 3.28 + * JDK-8014781: support Error.captureStackTrace 3.29 + * 3.30 + * @test 3.31 + * @run 3.32 + */ 3.33 + 3.34 +function MyError() { 3.35 + Error.captureStackTrace(this); 3.36 +} 3.37 + 3.38 +function func() { 3.39 + return new MyError(); 3.40 +} 3.41 + 3.42 +var e = func(); 3.43 +print(e.stack.replace(/\\/g, '/'));
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/test/script/basic/JDK-8014781.js.EXPECTED Wed Jun 26 19:42:17 2013 +0530 4.3 @@ -0,0 +1,3 @@ 4.4 +MyError @ test/script/basic/JDK-8014781.js:32 4.5 +func @ test/script/basic/JDK-8014781.js:36 4.6 +<program> @ test/script/basic/JDK-8014781.js:39