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