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