1 /*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.nashorn.internal.objects;
27
28 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
29 import static jdk.nashorn.internal.lookup.Lookup.MH;
30
31 import java.lang.invoke.MethodHandle;
32 import java.lang.invoke.MethodHandles;
33
34 import jdk.nashorn.api.scripting.NashornException;
35 import jdk.nashorn.internal.objects.annotations.Attribute;
36 import jdk.nashorn.internal.objects.annotations.Constructor;
37 import jdk.nashorn.internal.objects.annotations.Function;
38 import jdk.nashorn.internal.objects.annotations.Property;
39 import jdk.nashorn.internal.objects.annotations.ScriptClass;
40 import jdk.nashorn.internal.objects.annotations.Where;
41 import jdk.nashorn.internal.runtime.ECMAException;
42 import jdk.nashorn.internal.runtime.JSType;
43 import jdk.nashorn.internal.runtime.PropertyMap;
44 import jdk.nashorn.internal.runtime.ScriptObject;
45 import jdk.nashorn.internal.runtime.ScriptFunction;
46 import jdk.nashorn.internal.runtime.ScriptRuntime;
47
48 /**
49 * ECMA 15.11 Error Objects
50 */
51 @ScriptClass("Error")
52 public final class NativeError extends ScriptObject {
53
54 static final MethodHandle GET_COLUMNNUMBER = findOwnMH("getColumnNumber", Object.class, Object.class);
55 static final MethodHandle SET_COLUMNNUMBER = findOwnMH("setColumnNumber", Object.class, Object.class, Object.class);
56 static final MethodHandle GET_LINENUMBER = findOwnMH("getLineNumber", Object.class, Object.class);
57 static final MethodHandle SET_LINENUMBER = findOwnMH("setLineNumber", Object.class, Object.class, Object.class);
58 static final MethodHandle GET_FILENAME = findOwnMH("getFileName", Object.class, Object.class);
59 static final MethodHandle SET_FILENAME = findOwnMH("setFileName", Object.class, Object.class, Object.class);
60 static final MethodHandle GET_STACK = findOwnMH("getStack", Object.class, Object.class);
61 static final MethodHandle SET_STACK = findOwnMH("setStack", Object.class, Object.class, Object.class);
62
63 // message property name
64 static final String MESSAGE = "message";
65 // name property name
66 static final String NAME = "name";
67 // stack property name
68 static final String STACK = "__stack__";
69 // lineNumber property name
70 static final String LINENUMBER = "__lineNumber__";
71 // columnNumber property name
72 static final String COLUMNNUMBER = "__columnNumber__";
73 // fileName property name
74 static final String FILENAME = "__fileName__";
75
76 /** Message property name */
77 @Property(name = NativeError.MESSAGE, attributes = Attribute.NOT_ENUMERABLE)
78 public Object instMessage;
79
80 /** ECMA 15.11.4.2 Error.prototype.name */
81 @Property(attributes = Attribute.NOT_ENUMERABLE, where = Where.PROTOTYPE)
82 public Object name;
83
84 /** ECMA 15.11.4.3 Error.prototype.message */
85 @Property(attributes = Attribute.NOT_ENUMERABLE, where = Where.PROTOTYPE)
86 public Object message;
87
88 /** Nashorn extension: underlying exception */
89 @Property(attributes = Attribute.NOT_ENUMERABLE)
90 public Object nashornException;
91
92 // initialized by nasgen
93 private static PropertyMap $nasgenmap$;
94
95 @SuppressWarnings("LeakingThisInConstructor")
96 private NativeError(final Object msg, final ScriptObject proto, final PropertyMap map) {
97 super(proto, map);
98 if (msg != UNDEFINED) {
99 this.instMessage = JSType.toString(msg);
100 } else {
101 this.delete(NativeError.MESSAGE, false);
102 }
103 initException(this);
104 }
105
106 NativeError(final Object msg, final Global global) {
107 this(msg, global.getErrorPrototype(), $nasgenmap$);
108 }
109
110 private NativeError(final Object msg) {
111 this(msg, Global.instance());
112 }
113
114 @Override
115 public String getClassName() {
116 return "Error";
117 }
118
119 /**
120 * ECMA 15.11.2 The Error Constructor
121 *
122 * @param newObj true if this is being instantiated with a new
123 * @param self self reference
124 * @param msg error message
125 *
126 * @return NativeError instance
127 */
128 @Constructor
129 public static Object constructor(final boolean newObj, final Object self, final Object msg) {
130 return new NativeError(msg);
131 }
132
133 // This is called NativeError, NativeTypeError etc. to
134 // associate a ECMAException with the ECMA Error object.
135 @SuppressWarnings("unused")
136 static void initException(final ScriptObject self) {
137 // ECMAException constructor has side effects
138 new ECMAException(self, null);
139 }
140
141 /**
142 * Nashorn extension: Error.captureStackTrace. Capture stack trace at the point of call into the Error object provided.
143 *
144 * @param self self reference
145 * @param errorObj the error object
146 * @return undefined
147 */
148 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
149 public static Object captureStackTrace(final Object self, final Object errorObj) {
150 Global.checkObject(errorObj);
151 final ScriptObject sobj = (ScriptObject)errorObj;
152 initException(sobj);
153 sobj.delete(STACK, false);
154 if (! sobj.has("stack")) {
155 final ScriptFunction getStack = ScriptFunctionImpl.makeFunction("getStack", GET_STACK);
156 final ScriptFunction setStack = ScriptFunctionImpl.makeFunction("setStack", SET_STACK);
157 sobj.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack);
158 }
159 return UNDEFINED;
160 }
161
162 /**
163 * Nashorn extension: Error.dumpStack
164 * dumps the stack of the current thread.
165 *
166 * @param self self reference
167 *
168 * @return undefined
169 */
170 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
171 public static Object dumpStack(final Object self) {
172 Thread.dumpStack();
173 return UNDEFINED;
174 }
175
176 /**
177 * Nashorn extension: Error.prototype.printStackTrace
178 * prints stack trace associated with the exception (if available).
179 * to the standard error stream.
180 *
181 * @param self self reference
182 *
183 * @return result of {@link ECMAException#printStackTrace(ScriptObject)}, which is typically undefined
184 */
185 @Function(attributes = Attribute.NOT_ENUMERABLE)
186 public static Object printStackTrace(final Object self) {
187 Global.checkObject(self);
188 return ECMAException.printStackTrace((ScriptObject)self);
189 }
190
191 /**
192 * Nashorn extension: Error.prototype.getStackTrace()
193 * "stack" property is an array typed value containing {@link StackTraceElement}
194 * objects of JavaScript stack frames.
195 *
196 * @param self self reference
197 *
198 * @return stack trace as a script array.
199 */
200 @Function(attributes = Attribute.NOT_ENUMERABLE)
201 public static Object getStackTrace(final Object self) {
202 Global.checkObject(self);
203 final ScriptObject sobj = (ScriptObject)self;
204 final Object exception = ECMAException.getException(sobj);
205 Object[] res;
206 if (exception instanceof Throwable) {
207 res = NashornException.getScriptFrames((Throwable)exception);
208 } else {
209 res = ScriptRuntime.EMPTY_ARRAY;
210 }
211
212 return new NativeArray(res);
213 }
214
215 /**
216 * Nashorn extension: Error.prototype.lineNumber
217 *
218 * @param self self reference
219 *
220 * @return line number from which error was thrown
221 */
222 public static Object getLineNumber(final Object self) {
223 Global.checkObject(self);
224 final ScriptObject sobj = (ScriptObject)self;
225 return sobj.has(LINENUMBER) ? sobj.get(LINENUMBER) : ECMAException.getLineNumber(sobj);
226 }
227
228 /**
229 * Nashorn extension: Error.prototype.lineNumber
230 *
231 * @param self self reference
232 * @param value value of line number
233 *
234 * @return value that was set
235 */
236 public static Object setLineNumber(final Object self, final Object value) {
237 Global.checkObject(self);
238 final ScriptObject sobj = (ScriptObject)self;
239 if (sobj.hasOwnProperty(LINENUMBER)) {
240 sobj.put(LINENUMBER, value, false);
241 } else {
242 sobj.addOwnProperty(LINENUMBER, Attribute.NOT_ENUMERABLE, value);
243 }
244 return value;
245 }
246
247 /**
248 * Nashorn extension: Error.prototype.columnNumber
249 *
250 * @param self self reference
251 *
252 * @return column number from which error was thrown
253 */
254 public static Object getColumnNumber(final Object self) {
255 Global.checkObject(self);
256 final ScriptObject sobj = (ScriptObject)self;
257 return sobj.has(COLUMNNUMBER) ? sobj.get(COLUMNNUMBER) : ECMAException.getColumnNumber((ScriptObject)self);
258 }
259
260 /**
261 * Nashorn extension: Error.prototype.columnNumber
262 *
263 * @param self self reference
264 * @param value value of column number
265 *
266 * @return value that was set
267 */
268 public static Object setColumnNumber(final Object self, final Object value) {
269 Global.checkObject(self);
270 final ScriptObject sobj = (ScriptObject)self;
271 if (sobj.hasOwnProperty(COLUMNNUMBER)) {
272 sobj.put(COLUMNNUMBER, value, false);
273 } else {
274 sobj.addOwnProperty(COLUMNNUMBER, Attribute.NOT_ENUMERABLE, value);
275 }
276 return value;
277 }
278
279 /**
280 * Nashorn extension: Error.prototype.fileName
281 *
282 * @param self self reference
283 *
284 * @return file name from which error was thrown
285 */
286 public static Object getFileName(final Object self) {
287 Global.checkObject(self);
288 final ScriptObject sobj = (ScriptObject)self;
289 return sobj.has(FILENAME) ? sobj.get(FILENAME) : ECMAException.getFileName((ScriptObject)self);
290 }
291
292 /**
293 * Nashorn extension: Error.prototype.fileName
294 *
295 * @param self self reference
296 * @param value value of file name
297 *
298 * @return value that was set
299 */
300 public static Object setFileName(final Object self, final Object value) {
301 Global.checkObject(self);
302 final ScriptObject sobj = (ScriptObject)self;
303 if (sobj.hasOwnProperty(FILENAME)) {
304 sobj.put(FILENAME, value, false);
305 } else {
306 sobj.addOwnProperty(FILENAME, Attribute.NOT_ENUMERABLE, value);
307 }
308 return value;
309 }
310
311 /**
312 * Nashorn extension: Error.prototype.stack
313 * "stack" property is a string typed value containing JavaScript stack frames.
314 * Each frame information is separated bv "\n" character.
315 *
316 * @param self self reference
317 *
318 * @return value of "stack" property
319 */
320 public static Object getStack(final Object self) {
321 Global.checkObject(self);
322 final ScriptObject sobj = (ScriptObject)self;
323 if (sobj.has(STACK)) {
324 return sobj.get(STACK);
325 }
326
327 final Object exception = ECMAException.getException(sobj);
328 if (exception instanceof Throwable) {
329 Object value = getScriptStackString(sobj, (Throwable)exception);
330 sobj.put(STACK, value, false);
331 return value;
332 }
333
334 return UNDEFINED;
335 }
336
337 /**
338 * Nashorn extension
339 * Accessed from {@link Global} while setting up the Error.prototype
340 *
341 * @param self self reference
342 * @param value value to set "stack" property to, must be {@code ScriptObject}
343 *
344 * @return value that was set
345 */
346 public static Object setStack(final Object self, final Object value) {
347 Global.checkObject(self);
348 final ScriptObject sobj = (ScriptObject)self;
349 sobj.set(STACK, value, false);
350 return value;
351 }
352
353 /**
354 * ECMA 15.11.4.4 Error.prototype.toString ( )
355 *
356 * @param self self reference
357 *
358 * @return this NativeError as a string
359 */
360 @Function(attributes = Attribute.NOT_ENUMERABLE)
361 public static Object toString(final Object self) {
362 // Step 1 and 2 : check if 'self' is object it not throw TypeError
363 Global.checkObject(self);
364
365 final ScriptObject sobj = (ScriptObject)self;
366
367 // Step 3 & 4 : get "name" and convert to String.
368 // But if message is undefined make it "Error".
369 Object name = sobj.get("name");
370 if (name == UNDEFINED) {
371 name = "Error";
372 } else {
373 name = JSType.toString(name);
374 }
375
376 // Steps 5, 6, & 7 : get "message" and convert to String.
377 // if 'message' is undefined make it "" (empty String).
378 Object msg = sobj.get("message");
379 if (msg == UNDEFINED) {
380 msg = "";
381 } else {
382 msg = JSType.toString(msg);
383 }
384
385 // Step 8 : if name is empty, return msg
386 if (((String)name).isEmpty()) {
387 return msg;
388 }
389
390 // Step 9 : if message is empty, return name
391 if (((String)msg).isEmpty()) {
392 return name;
393 }
394 // Step 10 : return name + ": " + msg
395 return name + ": " + msg;
396 }
397
398 private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
399 return MH.findStatic(MethodHandles.lookup(), NativeError.class, name, MH.type(rtype, types));
400 }
401
402 private static String getScriptStackString(final ScriptObject sobj, final Throwable exp) {
403 return JSType.toString(sobj) + "\n" + NashornException.getScriptStackString(exp);
404 }
405 }
--- EOF ---