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