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