This commit is contained in:
Abhijit Saha 2014-01-16 21:46:17 -08:00
commit 16f65b9e8e
15 changed files with 246 additions and 38 deletions

View File

@ -45,11 +45,11 @@ import jdk.nashorn.internal.runtime.ScriptObject;
@SuppressWarnings("serial")
public abstract class NashornException extends RuntimeException {
// script file name
private final String fileName;
private String fileName;
// script line number
private final int line;
private int line;
// script column number
private final int column;
private int column;
// underlying ECMA error object - lazily initialized
private Object ecmaError;
@ -124,6 +124,15 @@ public abstract class NashornException extends RuntimeException {
return fileName;
}
/**
* Set the source file name for this {@code NashornException}
*
* @param fileName the file name
*/
public final void setFileName(final String fileName) {
this.fileName = fileName;
}
/**
* Get the line number for this {@code NashornException}
*
@ -133,15 +142,33 @@ public abstract class NashornException extends RuntimeException {
return line;
}
/**
* Set the line number for this {@code NashornException}
*
* @param line the line number
*/
public final void setLineNumber(final int line) {
this.line = line;
}
/**
* Get the column for this {@code NashornException}
*
* @return the column
* @return the column number
*/
public final int getColumnNumber() {
return column;
}
/**
* Set the column for this {@code NashornException}
*
* @param column the column number
*/
public final void setColumnNumber(final int column) {
this.column = column;
}
/**
* Returns array javascript stack frames from the given exception object.
*
@ -208,9 +235,9 @@ public abstract class NashornException extends RuntimeException {
final Object thrown = getThrown();
if (thrown instanceof ScriptObject) {
ecmaError = ScriptObjectMirror.wrap(thrown, global);
setEcmaError(ScriptObjectMirror.wrap(thrown, global));
} else {
ecmaError = thrown;
setEcmaError(thrown);
}
return this;
@ -225,4 +252,14 @@ public abstract class NashornException extends RuntimeException {
public Object getEcmaError() {
return ecmaError;
}
/**
* Return the underlying ECMA error object, if available.
*
* @param ecmaError underlying ECMA Error object's mirror or whatever was thrown
* from script such as a String, Number or a Boolean.
*/
public void setEcmaError(final Object ecmaError) {
this.ecmaError = ecmaError;
}
}

View File

@ -2023,8 +2023,6 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return false;
}
method._new(ECMAException.class).dup();
final Source source = lc.getCurrentFunction().getSource();
final Expression expression = throwNode.getExpression();
@ -2037,7 +2035,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
method.load(source.getName());
method.load(line);
method.load(column);
method.invoke(ECMAException.THROW_INIT);
method.invoke(ECMAException.CREATE);
method.athrow();

View File

@ -38,7 +38,6 @@ import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.objects.ScriptFunctionImpl;
import jdk.nashorn.internal.runtime.ECMAException;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
@ -75,7 +74,7 @@ public final class NativeError extends ScriptObject {
static final String FILENAME = "__fileName__";
/** Message property name */
@Property(name = NativeError.MESSAGE)
@Property(name = NativeError.MESSAGE, attributes = Attribute.NOT_ENUMERABLE)
public Object instMessage;
/** ECMA 15.11.4.2 Error.prototype.name */
@ -93,6 +92,7 @@ public final class NativeError extends ScriptObject {
return $nasgenmap$;
}
@SuppressWarnings("LeakingThisInConstructor")
private NativeError(final Object msg, final ScriptObject proto, final PropertyMap map) {
super(proto, map);
if (msg != UNDEFINED) {
@ -100,6 +100,7 @@ public final class NativeError extends ScriptObject {
} else {
this.delete(NativeError.MESSAGE, false);
}
initException(this);
}
NativeError(final Object msg, final Global global) {
@ -129,6 +130,14 @@ public final class NativeError extends ScriptObject {
return new NativeError(msg);
}
// This is called NativeError, NativeTypeError etc. to
// associate a ECMAException with the ECMA Error object.
@SuppressWarnings("unused")
static void initException(final ScriptObject self) {
// ECMAException constructor has side effects
new ECMAException(self, null);
}
/**
* Nashorn extension: Error.captureStackTrace. Capture stack trace at the point of call into the Error object provided.
*
@ -136,16 +145,17 @@ public final class NativeError extends ScriptObject {
* @param errorObj the error object
* @return undefined
*/
@SuppressWarnings("unused")
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object captureStackTrace(final Object self, final Object errorObj) {
Global.checkObject(errorObj);
final ScriptObject sobj = (ScriptObject)errorObj;
new ECMAException(sobj, null); //constructor has side effects
sobj.delete("stack", false);
final ScriptFunction getStack = ScriptFunctionImpl.makeFunction("getStack", GET_STACK);
final ScriptFunction setStack = ScriptFunctionImpl.makeFunction("setStack", SET_STACK);
sobj.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack);
initException(sobj);
sobj.delete(STACK, false);
if (! sobj.has("stack")) {
final ScriptFunction getStack = ScriptFunctionImpl.makeFunction("getStack", GET_STACK);
final ScriptFunction setStack = ScriptFunctionImpl.makeFunction("setStack", SET_STACK);
sobj.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack);
}
return UNDEFINED;
}
@ -226,7 +236,11 @@ public final class NativeError extends ScriptObject {
public static Object setLineNumber(final Object self, final Object value) {
Global.checkObject(self);
final ScriptObject sobj = (ScriptObject)self;
sobj.set(LINENUMBER, value, false);
if (sobj.hasOwnProperty(LINENUMBER)) {
sobj.put(LINENUMBER, value, false);
} else {
sobj.addOwnProperty(LINENUMBER, Attribute.NOT_ENUMERABLE, value);
}
return value;
}
@ -254,7 +268,11 @@ public final class NativeError extends ScriptObject {
public static Object setColumnNumber(final Object self, final Object value) {
Global.checkObject(self);
final ScriptObject sobj = (ScriptObject)self;
sobj.set(COLUMNNUMBER, value, false);
if (sobj.hasOwnProperty(COLUMNNUMBER)) {
sobj.put(COLUMNNUMBER, value, false);
} else {
sobj.addOwnProperty(COLUMNNUMBER, Attribute.NOT_ENUMERABLE, value);
}
return value;
}
@ -282,7 +300,11 @@ public final class NativeError extends ScriptObject {
public static Object setFileName(final Object self, final Object value) {
Global.checkObject(self);
final ScriptObject sobj = (ScriptObject)self;
sobj.set(FILENAME, value, false);
if (sobj.hasOwnProperty(FILENAME)) {
sobj.put(FILENAME, value, false);
} else {
sobj.addOwnProperty(FILENAME, Attribute.NOT_ENUMERABLE, value);
}
return value;
}
@ -304,10 +326,12 @@ public final class NativeError extends ScriptObject {
final Object exception = ECMAException.getException(sobj);
if (exception instanceof Throwable) {
return getScriptStackString(sobj, (Throwable)exception);
Object value = getScriptStackString(sobj, (Throwable)exception);
sobj.put(STACK, value, false);
return value;
}
return "";
return UNDEFINED;
}
/**

View File

@ -44,7 +44,7 @@ import jdk.nashorn.internal.runtime.ScriptObject;
public final class NativeEvalError extends ScriptObject {
/** message property in instance */
@Property(name = NativeError.MESSAGE)
@Property(name = NativeError.MESSAGE, attributes = Attribute.NOT_ENUMERABLE)
public Object instMessage;
/** error name property */
@ -62,6 +62,7 @@ public final class NativeEvalError extends ScriptObject {
return $nasgenmap$;
}
@SuppressWarnings("LeakingThisInConstructor")
private NativeEvalError(final Object msg, final ScriptObject proto, final PropertyMap map) {
super(proto, map);
if (msg != UNDEFINED) {
@ -69,6 +70,7 @@ public final class NativeEvalError extends ScriptObject {
} else {
this.delete(NativeError.MESSAGE, false);
}
NativeError.initException(this);
}
NativeEvalError(final Object msg, final Global global) {

View File

@ -44,7 +44,7 @@ import jdk.nashorn.internal.runtime.ScriptObject;
public final class NativeRangeError extends ScriptObject {
/** message property in instance */
@Property(name = NativeError.MESSAGE)
@Property(name = NativeError.MESSAGE, attributes = Attribute.NOT_ENUMERABLE)
public Object instMessage;
/** error name property */
@ -62,6 +62,7 @@ public final class NativeRangeError extends ScriptObject {
return $nasgenmap$;
}
@SuppressWarnings("LeakingThisInConstructor")
private NativeRangeError(final Object msg, final ScriptObject proto, final PropertyMap map) {
super(proto, map);
if (msg != UNDEFINED) {
@ -69,6 +70,7 @@ public final class NativeRangeError extends ScriptObject {
} else {
this.delete(NativeError.MESSAGE, false);
}
NativeError.initException(this);
}
NativeRangeError(final Object msg, final Global global) {

View File

@ -44,7 +44,7 @@ import jdk.nashorn.internal.runtime.ScriptObject;
public final class NativeReferenceError extends ScriptObject {
/** message property in instance */
@Property(name = NativeError.MESSAGE)
@Property(name = NativeError.MESSAGE, attributes = Attribute.NOT_ENUMERABLE)
public Object instMessage;
/** error name property */
@ -62,6 +62,7 @@ public final class NativeReferenceError extends ScriptObject {
return $nasgenmap$;
}
@SuppressWarnings("LeakingThisInConstructor")
private NativeReferenceError(final Object msg, final ScriptObject proto, final PropertyMap map) {
super(proto, map);
if (msg != UNDEFINED) {
@ -69,6 +70,7 @@ public final class NativeReferenceError extends ScriptObject {
} else {
this.delete(NativeError.MESSAGE, false);
}
NativeError.initException(this);
}
NativeReferenceError(final Object msg, final Global global) {

View File

@ -44,7 +44,7 @@ import jdk.nashorn.internal.runtime.ScriptObject;
public final class NativeSyntaxError extends ScriptObject {
/** message property in instance */
@Property(name = NativeError.MESSAGE)
@Property(name = NativeError.MESSAGE, attributes = Attribute.NOT_ENUMERABLE)
public Object instMessage;
/** error name property */
@ -62,6 +62,7 @@ public final class NativeSyntaxError extends ScriptObject {
return $nasgenmap$;
}
@SuppressWarnings("LeakingThisInConstructor")
NativeSyntaxError(final Object msg, final Global global) {
super(global.getSyntaxErrorPrototype(), global.getSyntaxErrorMap());
if (msg != UNDEFINED) {
@ -69,6 +70,7 @@ public final class NativeSyntaxError extends ScriptObject {
} else {
this.delete(NativeError.MESSAGE, false);
}
NativeError.initException(this);
}
private NativeSyntaxError(final Object msg) {

View File

@ -44,7 +44,7 @@ import jdk.nashorn.internal.runtime.ScriptObject;
public final class NativeTypeError extends ScriptObject {
/** message property in instance */
@Property(name = NativeError.MESSAGE)
@Property(name = NativeError.MESSAGE, attributes = Attribute.NOT_ENUMERABLE)
public Object instMessage;
/** error name property */
@ -62,6 +62,7 @@ public final class NativeTypeError extends ScriptObject {
return $nasgenmap$;
}
@SuppressWarnings("LeakingThisInConstructor")
NativeTypeError(final Object msg, final Global global) {
super(global.getTypeErrorPrototype(), global.getTypeErrorMap());
if (msg != UNDEFINED) {
@ -69,6 +70,7 @@ public final class NativeTypeError extends ScriptObject {
} else {
delete(NativeError.MESSAGE, false);
}
NativeError.initException(this);
}
private NativeTypeError(final Object msg) {

View File

@ -43,7 +43,7 @@ import jdk.nashorn.internal.runtime.ScriptObject;
public final class NativeURIError extends ScriptObject {
/** message property in instance */
@Property(name = NativeError.MESSAGE)
@Property(name = NativeError.MESSAGE, attributes = Attribute.NOT_ENUMERABLE)
public Object instMessage;
/** error name property */
@ -61,6 +61,7 @@ public final class NativeURIError extends ScriptObject {
return $nasgenmap$;
}
@SuppressWarnings("LeakingThisInConstructor")
NativeURIError(final Object msg, final Global global) {
super(global.getURIErrorPrototype(), global.getURIErrorMap());
if (msg != UNDEFINED) {
@ -68,6 +69,7 @@ public final class NativeURIError extends ScriptObject {
} else {
this.delete(NativeError.MESSAGE, false);
}
NativeError.initException(this);
}
private NativeURIError(final Object msg) {

View File

@ -25,7 +25,7 @@
package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
import static jdk.nashorn.internal.codegen.CompilerConstants.virtualField;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
@ -33,6 +33,7 @@ import javax.script.ScriptException;
import jdk.nashorn.api.scripting.NashornException;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.codegen.CompilerConstants.FieldAccess;
import jdk.nashorn.internal.objects.NativeError;
/**
* Exception used to implement ECMAScript "throw" from scripts. The actual thrown
@ -44,9 +45,9 @@ import jdk.nashorn.internal.codegen.CompilerConstants.FieldAccess;
@SuppressWarnings("serial")
public final class ECMAException extends NashornException {
/**
* Method handle pointing to the constructor {@link ECMAException#ECMAException(Object, String, int, int)},
* Method handle pointing to the constructor {@link ECMAException#create(Object, String, int, int)},
*/
public static final Call THROW_INIT = constructorNoLookup(ECMAException.class, Object.class, String.class, int.class, int.class);
public static final Call CREATE = staticCallNoLookup(ECMAException.class, "create", ECMAException.class, Object.class, String.class, int.class, int.class);
/** 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);
@ -57,23 +58,21 @@ public final class ECMAException extends NashornException {
public final Object thrown;
/**
* Constructor. This is called from generated code to implement the {@code throw}
* instruction from generated script code
* Constructor. Called from the factory method 'create'.
*
* @param thrown object to be thrown
* @param fileName script file name
* @param line line number of throw
* @param column column number of throw
*/
public ECMAException(final Object thrown, final String fileName, final int line, final int column) {
private ECMAException(final Object thrown, final String fileName, final int line, final int column) {
super(ScriptRuntime.safeToString(thrown), asThrowable(thrown), fileName, line, column);
this.thrown = thrown;
setExceptionToThrown();
}
/**
* Constructor. This is called from runtime code in Nashorn to throw things like
* type errors.
* Constructor. This is called from the runtime code.
*
* @param thrown object to be thrown
* @param cause Java exception that triggered this throw
@ -84,6 +83,35 @@ public final class ECMAException extends NashornException {
setExceptionToThrown();
}
/**
* Factory method to retrieve the underlying exception or create an exception.
* This method is called from the generated code.
*
* @param thrown object to be thrown
* @param fileName script file name
* @param line line number of throw
* @param column column number of throw
* @return ECMAException object
*/
public static ECMAException create(final Object thrown, final String fileName, final int line, final int column) {
// If thrown object is an Error or sub-object like TypeError, then
// an ECMAException object has been already initialized at constructor.
if (thrown instanceof ScriptObject) {
ScriptObject sobj = (ScriptObject)thrown;
Object exception = getException(sobj);
if (exception instanceof ECMAException) {
// copy over file name, line number and column number.
final ECMAException ee = (ECMAException)exception;
ee.setFileName(fileName);
ee.setLineNumber(line);
ee.setColumnNumber(column);
return ee;
}
}
return new ECMAException(thrown, fileName, line, column);
}
/**
* Get the thrown object
* @return thrown object
@ -257,6 +285,8 @@ public final class ECMAException extends NashornException {
final ScriptObject sobj = (ScriptObject)thrown;
if (!sobj.has(EXCEPTION_PROPERTY)) {
sobj.addOwnProperty(EXCEPTION_PROPERTY, Property.NOT_ENUMERABLE, this);
} else {
sobj.set(EXCEPTION_PROPERTY, this, false);
}
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2014, 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-8031983: Error objects should capture stack at the constructor
*
* @test
* @run
*/
var e = new Error();
print("hello");
try {
throw e;
} catch (e) {
print(e.lineNumber);
print(e.stack.replace(/\\/g, '/'));
}
Error.captureStackTrace(e);
try {
throw e;
} catch (e) {
print(e.lineNumber);
print(e.stack.replace(/\\/g, '/'));
}
var obj = {};
Error.captureStackTrace(obj);
try {
throw obj;
} catch (e) {
print(e.stack.replace(/\\/g, '/'));
}

View File

@ -0,0 +1,9 @@
hello
35
Error
at <program> (test/script/basic/JDK-8031983.js:31)
43
Error
at <program> (test/script/basic/JDK-8031983.js:41)
[object Object]
at <program> (test/script/basic/JDK-8031983.js:50)

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2014, 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-8032004: instance property "message" of Error objects should be non-enumerable
*
* @test
* @run
*/
function check(obj) {
if (obj.propertyIsEnumerable("message")) {
fail(obj.name + " object's message property is enumerable!");
}
}
check(new Error("test"));
check(new EvalError("test"));
check(new RangeError("test"));
check(new ReferenceError("test"));
check(new SyntaxError("test"));
check(new TypeError("test"));
check(new URIError("test"));

View File

@ -1 +1 @@
{"message":"type error"}
{}

View File

@ -12,6 +12,6 @@ finally 4
try 5
rethrow 5
finally 5
Error: try 5 thrown in line 71
Error: try 5 thrown in line 74
try 6
finally 6