/** * Nashorn extension: Error.prototype.stack * "stack" property is a string typed value containing JavaScript stack frames. * Each frame information is separated bv "\n" character. * * @param self self reference * * @return value of "stack" property */ public static Object getStack(final Object self) { final ScriptObject sobj = Global.checkObject(self); if (sobj.has(STACK)) { return sobj.get(STACK); } final Object exception = ECMAException.getException(sobj); if (exception instanceof Throwable) { final Object value = getScriptStackString(sobj, (Throwable)exception); if (sobj.hasOwnProperty(STACK)) { sobj.put(STACK, value, false); } else { sobj.addOwnProperty(STACK, Attribute.NOT_ENUMERABLE, value); } return value; } return UNDEFINED; }
@Override public Object getDefaultValue(final Class<?> hint) { return inGlobal(new Callable<Object>() { @Override public Object call() { try { return sobj.getDefaultValue(hint); } catch (final ECMAException e) { // We're catching ECMAException (likely TypeError), and translating it to // UnsupportedOperationException. This in turn will be translated into TypeError of the // caller's Global by JSType#toPrimitive(JSObject,Class) therefore ensuring that it's // recognized as "instanceof TypeError" in the caller. throw new UnsupportedOperationException(e.getMessage(), e); } } }); }
Response buildResponse(NasapiException ex, ECMAException outerScriptException, HttpServletRequest request) { LoggerFactory.getLogger(ex.getClass()).warn(ex.getMessage() + buildScriptInfoMessage(outerScriptException) + buildRequestInfoMessage(request)); Map<String,Object> body = new HashMap<String,Object>(); body.put("$error", ex.getMessage()); return Response.status(ex.getStatusCode()) .entity(body) .build(); }
String buildScriptInfoMessage(ECMAException outerScriptException) { String result = ""; if (outerScriptException != null) { result = " [at:- " + outerScriptException.getFileName() + ":" + outerScriptException.getLineNumber() + "," + outerScriptException.getColumnNumber() + "]"; } return result; }
@Override @Produces(MediaType.APPLICATION_JSON) public Response toResponse(ECMAException ex) { Object cause = ex.getCause(); if (cause != null && cause instanceof NasapiException) { return buildResponse((NasapiException)cause, ex, request); } LoggerFactory.getLogger(ex.getClass()).warn(ex.getMessage() + buildScriptInfoMessage(ex)); Map<String,Object> body = new HashMap<String,Object>(); body.put("$error", ex.getMessage()); return Response.status(500).entity(body).build(); }
/** * Nashorn extension: Error.prototype.getStackTrace() * "stack" property is an array typed value containing {@link StackTraceElement} * objects of JavaScript stack frames. * * @param self self reference * * @return stack trace as a script array. */ @Function(attributes = Attribute.NOT_ENUMERABLE) public static Object getStackTrace(final Object self) { final ScriptObject sobj = Global.checkObject(self); final Object exception = ECMAException.getException(sobj); Object[] res; if (exception instanceof Throwable) { res = NashornException.getScriptFrames((Throwable)exception); } else { res = ScriptRuntime.EMPTY_ARRAY; } return new NativeArray(res); }
/** * Is this a ECMAScript SyntaxError thrown for parse issue at the given line and column? * * @param exp Throwable to check * @param line line number to check * @param column column number to check * * @return true if the given Throwable is a ECMAScript SyntaxError at given line, column */ boolean isSyntaxErrorAt(final Throwable exp, final int line, final int column) { if (exp instanceof ECMAException) { final ECMAException eexp = (ECMAException)exp; if (eexp.getThrown() instanceof NativeSyntaxError) { return isParseErrorAt(eexp.getCause(), line, column); } } return false; }
/** * Nashorn extension: Error.captureStackTrace. Capture stack trace at the point of call into the Error object provided. * * @param self self reference * @param errorObj the error object * @return undefined */ @SuppressWarnings("unused") @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object captureStackTrace(final Object self, final Object errorObj) { Global.checkObject(errorObj); final ScriptObject sobj = (ScriptObject)errorObj; new ECMAException(sobj, null); //constructor has side effects sobj.delete("stack", false); final ScriptFunction getStack = ScriptFunctionImpl.makeFunction("getStack", GET_STACK); final ScriptFunction setStack = ScriptFunctionImpl.makeFunction("setStack", SET_STACK); sobj.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack); return UNDEFINED; }
/** * Nashorn extension: Error.prototype.getStackTrace() * "stack" property is an array typed value containing {@link StackTraceElement} * objects of JavaScript stack frames. * * @param self self reference * * @return stack trace as a script array. */ @Function(attributes = Attribute.NOT_ENUMERABLE) public static Object getStackTrace(final Object self) { Global.checkObject(self); final ScriptObject sobj = (ScriptObject)self; final Object exception = ECMAException.getException(sobj); Object[] res; if (exception instanceof Throwable) { res = NashornException.getScriptFrames((Throwable)exception); } else { res = ScriptRuntime.EMPTY_ARRAY; } return new NativeArray(res); }
/** * Nashorn extension: Error.prototype.stack * "stack" property is a string typed value containing JavaScript stack frames. * Each frame information is separated bv "\n" character. * * @param self self reference * * @return value of "stack" property */ public static Object getStack(final Object self) { Global.checkObject(self); final ScriptObject sobj = (ScriptObject)self; if (sobj.has(STACK)) { return sobj.get(STACK); } final Object exception = ECMAException.getException(sobj); if (exception instanceof Throwable) { return getScriptStackString(sobj, (Throwable)exception); } return ""; }
@Override public boolean enterThrowNode(final ThrowNode throwNode) { lineNumber(throwNode); if (throwNode.isSyntheticRethrow()) { //do not wrap whatever this is in an ecma exception, just rethrow it load(throwNode.getExpression()); method.athrow(); return false; } method._new(ECMAException.class).dup(); final Source source = lc.getCurrentFunction().getSource(); final Expression expression = throwNode.getExpression(); final int position = throwNode.position(); final int line = throwNode.getLineNumber(); final int column = source.getColumn(position); load(expression, Type.OBJECT); method.load(source.getName()); method.load(line); method.load(column); method.invoke(ECMAException.THROW_INIT); method.athrow(); return false; }
/** * Nashorn extension: Error.captureStackTrace. Capture stack trace at the point of call into the Error object provided. * * @param self self reference * @param errorObj the error object * @return undefined */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object captureStackTrace(final Object self, final Object errorObj) { Global.checkObject(errorObj); final ScriptObject sobj = (ScriptObject)errorObj; final ECMAException exp = new ECMAException(sobj, null); sobj.set("stack", getScriptStackString(sobj, exp), false); return UNDEFINED; }
protected RuntimeException getExceptionToThrow(ScriptException e) { Throwable cause = e.getCause(); String message; if (cause instanceof ECMAException) { message = cause.toString(); } else { message = e.getMessage(); } return new SlimFixtureException(false, message, e); }
@SuppressWarnings("unused") static void initException(final ScriptObject self) { // ECMAException constructor has side effects new ECMAException(self, null); }
private static ECMAException notAnObject(final Object obj) { return typeError("not.an.object", ScriptRuntime.safeToString(obj)); }
ECMAException typeError() { return ECMAErrors.typeError("extend." + outcome, classList); }
private static ECMAException notFunction(final Object obj) { return typeError("not.a.function", ScriptRuntime.safeToString(obj)); }
@Override public boolean enterThrowNode(final ThrowNode throwNode) { if(!method.isReachable()) { return false; } enterStatement(throwNode); if (throwNode.isSyntheticRethrow()) { method.beforeJoinPoint(throwNode); //do not wrap whatever this is in an ecma exception, just rethrow it final IdentNode exceptionExpr = (IdentNode)throwNode.getExpression(); final Symbol exceptionSymbol = exceptionExpr.getSymbol(); method.load(exceptionSymbol, EXCEPTION_TYPE); method.checkcast(EXCEPTION_TYPE.getTypeClass()); method.athrow(); return false; } final Source source = getCurrentSource(); final Expression expression = throwNode.getExpression(); final int position = throwNode.position(); final int line = throwNode.getLineNumber(); final int column = source.getColumn(position); // NOTE: we first evaluate the expression, and only after it was evaluated do we create the new ECMAException // object and then somewhat cumbersomely move it beneath the evaluated expression on the stack. The reason for // this is that if expression is optimistic (or contains an optimistic subexpression), we'd potentially access // the not-yet-<init>ialized object on the stack from the UnwarrantedOptimismException handler, and bytecode // verifier forbids that. loadExpressionAsObject(expression); method.load(source.getName()); method.load(line); method.load(column); method.invoke(ECMAException.CREATE); method.beforeJoinPoint(throwNode); method.athrow(); return false; }