package com.oracle.truffle.js.runtime;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.ImportStatic;
import com.oracle.truffle.api.interop.ExceptionType;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.js.lang.JavaScriptLanguage;
import com.oracle.truffle.js.runtime.builtins.JSError;
import com.oracle.truffle.js.runtime.builtins.JSFunction;
import com.oracle.truffle.js.runtime.objects.JSDynamicObject;
import com.oracle.truffle.js.runtime.objects.JSObject;
import com.oracle.truffle.js.runtime.objects.Null;
import com.oracle.truffle.js.runtime.objects.Undefined;
@ImportStatic({JSConfig.class})
@ExportLibrary(value = InteropLibrary.class, delegateTo = "exceptionObject")
public final class UserScriptException extends GraalJSException {
private static final long serialVersionUID = -6624166672101791072L;
final Object exceptionObject;
private UserScriptException(Object exceptionObject, Node originatingNode, int stackTraceLimit) {
super(getMessage(exceptionObject), originatingNode, stackTraceLimit);
this.exceptionObject = exceptionObject;
}
private UserScriptException(Throwable exception, Node originatingNode, int stackTraceLimit) {
super(exception.toString(), exception, originatingNode, stackTraceLimit);
this.exceptionObject = exception;
}
@TruffleBoundary
public static UserScriptException createCapture(Object exceptionObject, Node originatingNode, int stackTraceLimit, DynamicObject skipFramesUpTo) {
return fillInStackTrace(new UserScriptException(exceptionObject, originatingNode, stackTraceLimit), skipFramesUpTo, true);
}
@TruffleBoundary
public static UserScriptException create(Object exceptionObject, Node originatingNode, int stackTraceLimit) {
return fillInStackTrace(new UserScriptException(exceptionObject, originatingNode, stackTraceLimit), Undefined.instance, false);
}
@TruffleBoundary
public static UserScriptException create(Object exceptionObject) {
int stackTraceLimit = JavaScriptLanguage.getCurrentJSRealm().getContext().getContextOptions().getStackTraceLimit();
return create(exceptionObject, null, stackTraceLimit);
}
@Override
public Object getErrorObject() {
return exceptionObject;
}
@SuppressWarnings("static-method")
@ExportMessage
public boolean isException() {
return true;
}
@SuppressWarnings("static-method")
@ExportMessage
public RuntimeException throwException() {
throw this;
}
@SuppressWarnings("static-method")
@ExportMessage
public ExceptionType getExceptionType() {
return ExceptionType.RUNTIME_ERROR;
}
@TruffleBoundary
private static String getMessage(Object exc) {
if (JSRuntime.isObject(exc)) {
DynamicObject errorObj = (DynamicObject) exc;
DynamicObject prototype = JSObject.getPrototype(errorObj);
if (prototype != Null.instance) {
Object constructor = JSDynamicObject.getOrDefault(prototype, JSObject.CONSTRUCTOR, null);
if (JSFunction.isJSFunction(constructor)) {
String name = JSFunction.getName((DynamicObject) constructor);
if (!name.isEmpty()) {
Object message = JSDynamicObject.getOrDefault(errorObj, JSError.MESSAGE, null);
if (JSRuntime.isString(message)) {
return name + ": " + message;
}
return name;
}
}
}
}
return JSRuntime.safeToString(exc);
}
}