/*
 * 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.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * 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.
 */

package jdk.nashorn.internal.objects;

import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import jdk.nashorn.api.scripting.NashornException;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
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.runtime.ECMAException;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;

ECMA 15.11 Error Objects
/** * ECMA 15.11 Error Objects */
@ScriptClass("Error") public final class NativeError extends ScriptObject { static final MethodHandle GET_COLUMNNUMBER = findOwnMH("getColumnNumber", Object.class, Object.class); static final MethodHandle SET_COLUMNNUMBER = findOwnMH("setColumnNumber", Object.class, Object.class, Object.class); static final MethodHandle GET_LINENUMBER = findOwnMH("getLineNumber", Object.class, Object.class); static final MethodHandle SET_LINENUMBER = findOwnMH("setLineNumber", Object.class, Object.class, Object.class); static final MethodHandle GET_FILENAME = findOwnMH("getFileName", Object.class, Object.class); static final MethodHandle SET_FILENAME = findOwnMH("setFileName", Object.class, Object.class, Object.class); static final MethodHandle GET_STACK = findOwnMH("getStack", Object.class, Object.class); static final MethodHandle SET_STACK = findOwnMH("setStack", Object.class, Object.class, Object.class); // message property name static final String MESSAGE = "message"; // name property name static final String NAME = "name"; // stack property name static final String STACK = "__stack__"; // lineNumber property name static final String LINENUMBER = "__lineNumber__"; // columnNumber property name static final String COLUMNNUMBER = "__columnNumber__"; // fileName property name static final String FILENAME = "__fileName__";
Message property name
/** Message property name */
@Property(name = NativeError.MESSAGE, attributes = Attribute.NOT_ENUMERABLE) public Object instMessage;
ECMA 15.11.4.2 Error.prototype.name
/** ECMA 15.11.4.2 Error.prototype.name */
@Property(attributes = Attribute.NOT_ENUMERABLE, where = Where.PROTOTYPE) public Object name;
ECMA 15.11.4.3 Error.prototype.message
/** ECMA 15.11.4.3 Error.prototype.message */
@Property(attributes = Attribute.NOT_ENUMERABLE, where = Where.PROTOTYPE) public Object message;
Nashorn extension: underlying exception
/** Nashorn extension: underlying exception */
@Property(attributes = Attribute.NOT_ENUMERABLE) public Object nashornException; // initialized by nasgen private static PropertyMap $nasgenmap$; @SuppressWarnings("LeakingThisInConstructor") private NativeError(final Object msg, final ScriptObject proto, final PropertyMap map) { super(proto, map); if (msg != UNDEFINED) { this.instMessage = JSType.toString(msg); } else { this.delete(NativeError.MESSAGE, false); } initException(this); } NativeError(final Object msg, final Global global) { this(msg, global.getErrorPrototype(), $nasgenmap$); } private NativeError(final Object msg) { this(msg, Global.instance()); } @Override public String getClassName() { return "Error"; }
ECMA 15.11.2 The Error Constructor
Params:
  • newObj – true if this is being instantiated with a new
  • self – self reference
  • msg – error message
Returns:NativeError instance
/** * ECMA 15.11.2 The Error Constructor * * @param newObj true if this is being instantiated with a new * @param self self reference * @param msg error message * * @return NativeError instance */
@Constructor public static NativeError constructor(final boolean newObj, final Object self, final Object msg) { return new NativeError(msg); } // This is called NativeError, NativeTypeError etc. to // associate a ECMAException with the ECMA Error object. 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.
Params:
  • self – self reference
  • errorObj – the error object
Returns:undefined
/** * Nashorn extension: Error.captureStackTrace. Capture stack trace at the point of call into the Error object provided. * * @param self self reference * @param errorObj the error object * @return undefined */
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object captureStackTrace(final Object self, final Object errorObj) { final ScriptObject sobj = Global.checkObject(errorObj); initException(sobj); sobj.delete(STACK, false); if (! sobj.has("stack")) { final ScriptFunction getStack = ScriptFunction.createBuiltin("getStack", GET_STACK); final ScriptFunction setStack = ScriptFunction.createBuiltin("setStack", SET_STACK); sobj.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack); } return UNDEFINED; }
Nashorn extension: Error.dumpStack dumps the stack of the current thread.
Params:
  • self – self reference
Returns:undefined
/** * Nashorn extension: Error.dumpStack * dumps the stack of the current thread. * * @param self self reference * * @return undefined */
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object dumpStack(final Object self) { Thread.dumpStack(); return UNDEFINED; }
Nashorn extension: Error.prototype.printStackTrace prints stack trace associated with the exception (if available). to the standard error stream.
Params:
  • self – self reference
Returns:result of ECMAException.printStackTrace(ScriptObject), which is typically undefined
/** * Nashorn extension: Error.prototype.printStackTrace * prints stack trace associated with the exception (if available). * to the standard error stream. * * @param self self reference * * @return result of {@link ECMAException#printStackTrace(ScriptObject)}, which is typically undefined */
@Function(attributes = Attribute.NOT_ENUMERABLE) public static Object printStackTrace(final Object self) { return ECMAException.printStackTrace(Global.checkObject(self)); }
Nashorn extension: Error.prototype.getStackTrace() "stack" property is an array typed value containing StackTraceElement objects of JavaScript stack frames.
Params:
  • self – self reference
Returns: stack trace as a script array.
/** * 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) { final ScriptObject sobj = Global.checkObject(self); final Object exception = ECMAException.getException(sobj); Object[] res; if (exception instanceof Throwable) { res = NashornException.getScriptFrames((Throwable)exception); } else { res = ScriptRuntime.EMPTY_ARRAY; } return new NativeArray(res); }
Nashorn extension: Error.prototype.lineNumber
Params:
  • self – self reference
Returns:line number from which error was thrown
/** * Nashorn extension: Error.prototype.lineNumber * * @param self self reference * * @return line number from which error was thrown */
public static Object getLineNumber(final Object self) { final ScriptObject sobj = Global.checkObject(self); return sobj.has(LINENUMBER) ? sobj.get(LINENUMBER) : ECMAException.getLineNumber(sobj); }
Nashorn extension: Error.prototype.lineNumber
Params:
  • self – self reference
  • value – value of line number
Returns:value that was set
/** * Nashorn extension: Error.prototype.lineNumber * * @param self self reference * @param value value of line number * * @return value that was set */
public static Object setLineNumber(final Object self, final Object value) { final ScriptObject sobj = Global.checkObject(self); if (sobj.hasOwnProperty(LINENUMBER)) { sobj.put(LINENUMBER, value, false); } else { sobj.addOwnProperty(LINENUMBER, Attribute.NOT_ENUMERABLE, value); } return value; }
Nashorn extension: Error.prototype.columnNumber
Params:
  • self – self reference
Returns:column number from which error was thrown
/** * Nashorn extension: Error.prototype.columnNumber * * @param self self reference * * @return column number from which error was thrown */
public static Object getColumnNumber(final Object self) { final ScriptObject sobj = Global.checkObject(self); return sobj.has(COLUMNNUMBER) ? sobj.get(COLUMNNUMBER) : ECMAException.getColumnNumber((ScriptObject)self); }
Nashorn extension: Error.prototype.columnNumber
Params:
  • self – self reference
  • value – value of column number
Returns:value that was set
/** * Nashorn extension: Error.prototype.columnNumber * * @param self self reference * @param value value of column number * * @return value that was set */
public static Object setColumnNumber(final Object self, final Object value) { final ScriptObject sobj = Global.checkObject(self); if (sobj.hasOwnProperty(COLUMNNUMBER)) { sobj.put(COLUMNNUMBER, value, false); } else { sobj.addOwnProperty(COLUMNNUMBER, Attribute.NOT_ENUMERABLE, value); } return value; }
Nashorn extension: Error.prototype.fileName
Params:
  • self – self reference
Returns:file name from which error was thrown
/** * Nashorn extension: Error.prototype.fileName * * @param self self reference * * @return file name from which error was thrown */
public static Object getFileName(final Object self) { final ScriptObject sobj = Global.checkObject(self); return sobj.has(FILENAME) ? sobj.get(FILENAME) : ECMAException.getFileName((ScriptObject)self); }
Nashorn extension: Error.prototype.fileName
Params:
  • self – self reference
  • value – value of file name
Returns:value that was set
/** * Nashorn extension: Error.prototype.fileName * * @param self self reference * @param value value of file name * * @return value that was set */
public static Object setFileName(final Object self, final Object value) { final ScriptObject sobj = Global.checkObject(self); if (sobj.hasOwnProperty(FILENAME)) { sobj.put(FILENAME, value, false); } else { sobj.addOwnProperty(FILENAME, Attribute.NOT_ENUMERABLE, value); } return value; }
Nashorn extension: Error.prototype.stack "stack" property is a string typed value containing JavaScript stack frames. Each frame information is separated bv "\n" character.
Params:
  • self – self reference
Returns: value of "stack" property
/** * Nashorn extension: Error.prototype.stack * "stack" property is a string typed value containing JavaScript stack frames. * Each frame information is separated bv "\n" character. * * @param self self reference * * @return value of "stack" property */
public static Object getStack(final Object self) { final ScriptObject sobj = Global.checkObject(self); if (sobj.has(STACK)) { return sobj.get(STACK); } final Object exception = ECMAException.getException(sobj); if (exception instanceof Throwable) { final Object value = getScriptStackString(sobj, (Throwable)exception); if (sobj.hasOwnProperty(STACK)) { sobj.put(STACK, value, false); } else { sobj.addOwnProperty(STACK, Attribute.NOT_ENUMERABLE, value); } return value; } return UNDEFINED; }
Nashorn extension Accessed from Global while setting up the Error.prototype
Params:
  • self – self reference
  • value – value to set "stack" property to, must be ScriptObject
Returns:value that was set
/** * Nashorn extension * Accessed from {@link Global} while setting up the Error.prototype * * @param self self reference * @param value value to set "stack" property to, must be {@code ScriptObject} * * @return value that was set */
public static Object setStack(final Object self, final Object value) { final ScriptObject sobj = Global.checkObject(self); if (sobj.hasOwnProperty(STACK)) { sobj.put(STACK, value, false); } else { sobj.addOwnProperty(STACK, Attribute.NOT_ENUMERABLE, value); } return value; }
ECMA 15.11.4.4 Error.prototype.toString ( )
Params:
  • self – self reference
Returns:this NativeError as a string
/** * ECMA 15.11.4.4 Error.prototype.toString ( ) * * @param self self reference * * @return this NativeError as a string */
@Function(attributes = Attribute.NOT_ENUMERABLE) public static Object toString(final Object self) { // Step 1 and 2 : check if 'self' is object it not throw TypeError final ScriptObject sobj = Global.checkObject(self); // Step 3 & 4 : get "name" and convert to String. // But if message is undefined make it "Error". Object name = sobj.get("name"); if (name == UNDEFINED) { name = "Error"; } else { name = JSType.toString(name); } // Steps 5, 6, & 7 : get "message" and convert to String. // if 'message' is undefined make it "" (empty String). Object msg = sobj.get("message"); if (msg == UNDEFINED) { msg = ""; } else { msg = JSType.toString(msg); } // Step 8 : if name is empty, return msg if (((String)name).isEmpty()) { return msg; } // Step 9 : if message is empty, return name if (((String)msg).isEmpty()) { return name; } // Step 10 : return name + ": " + msg return name + ": " + msg; } private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { return MH.findStatic(MethodHandles.lookup(), NativeError.class, name, MH.type(rtype, types)); } private static String getScriptStackString(final ScriptObject sobj, final Throwable exp) { return JSType.toString(sobj) + "\n" + NashornException.getScriptStackString(exp); } }