package com.oracle.truffle.js.nodes.access;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.DynamicObjectLibrary;
import com.oracle.truffle.api.object.Property;
import com.oracle.truffle.js.nodes.JavaScriptBaseNode;
import com.oracle.truffle.js.nodes.access.InitErrorObjectNodeFactory.DefineStackPropertyNodeGen;
import com.oracle.truffle.js.nodes.function.CreateMethodPropertyNode;
import com.oracle.truffle.js.runtime.Errors;
import com.oracle.truffle.js.runtime.GraalJSException;
import com.oracle.truffle.js.runtime.GraalJSException.JSStackTraceElement;
import com.oracle.truffle.js.runtime.JSContext;
import com.oracle.truffle.js.runtime.builtins.JSError;
import com.oracle.truffle.js.runtime.objects.JSAttributes;
import com.oracle.truffle.js.runtime.objects.JSObjectUtil;
import com.oracle.truffle.js.runtime.objects.JSProperty;
public final class InitErrorObjectNode extends JavaScriptBaseNode {
@Child private PropertySetNode setException;
@Child private PropertySetNode setFormattedStack;
@Child private DynamicObjectLibrary setMessage;
@Child private DynamicObjectLibrary setErrors;
@Child private DefineStackPropertyNode defineStackProperty;
private final boolean defaultColumnNumber;
@Child private CreateMethodPropertyNode setLineNumber;
@Child private CreateMethodPropertyNode setColumnNumber;
private InitErrorObjectNode(JSContext context, boolean defaultColumnNumber) {
this.setException = PropertySetNode.createSetHidden(JSError.EXCEPTION_PROPERTY_NAME, context);
this.setFormattedStack = PropertySetNode.createSetHidden(JSError.FORMATTED_STACK_NAME, context);
this.setMessage = JSObjectUtil.createDispatched(JSError.MESSAGE);
this.defineStackProperty = DefineStackPropertyNode.create();
this.defaultColumnNumber = defaultColumnNumber;
if (context.isOptionNashornCompatibilityMode()) {
this.setLineNumber = CreateMethodPropertyNode.create(context, JSError.LINE_NUMBER_PROPERTY_NAME);
this.setColumnNumber = CreateMethodPropertyNode.create(context, JSError.COLUMN_NUMBER_PROPERTY_NAME);
}
}
public static InitErrorObjectNode create(JSContext context) {
return new InitErrorObjectNode(context, false);
}
public static InitErrorObjectNode create(JSContext context, boolean defaultColumnNumber) {
return new InitErrorObjectNode(context, defaultColumnNumber);
}
public DynamicObject execute(DynamicObject errorObj, GraalJSException exception, String messageOpt) {
return execute(errorObj, exception, messageOpt, null);
}
public DynamicObject execute(DynamicObject errorObj, GraalJSException exception, String messageOpt, DynamicObject errorsOpt) {
if (messageOpt != null) {
setMessage.putWithFlags(errorObj, JSError.MESSAGE, messageOpt, JSError.MESSAGE_ATTRIBUTES);
}
if (errorsOpt != null) {
setErrorsNode().putWithFlags(errorObj, JSError.ERRORS_NAME, errorsOpt, JSError.ERRORS_ATTRIBUTES);
}
setException.setValue(errorObj, exception);
setFormattedStack.setValue(errorObj, null);
defineStackProperty.execute(errorObj);
if (setLineNumber != null && exception.getJSStackTrace().length > 0) {
JSStackTraceElement topStackTraceElement = exception.getJSStackTrace()[0];
setLineNumber.executeVoid(errorObj, topStackTraceElement.getLineNumber());
setColumnNumber.executeVoid(errorObj, defaultColumnNumber ? JSError.DEFAULT_COLUMN_NUMBER : topStackTraceElement.getColumnNumber());
}
return errorObj;
}
private DynamicObjectLibrary setErrorsNode() {
DynamicObjectLibrary errorsLib = setErrors;
if (errorsLib == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
setErrors = errorsLib = insert(JSObjectUtil.createDispatched(JSError.ERRORS_NAME));
}
return errorsLib;
}
public abstract static class DefineStackPropertyNode extends JavaScriptBaseNode {
static DefineStackPropertyNode create() {
return DefineStackPropertyNodeGen.create();
}
abstract void execute(DynamicObject errorObj);
@Specialization(limit = "3")
void doCached(DynamicObject errorObj,
@CachedLibrary("errorObj") DynamicObjectLibrary objectLibrary) {
Property stackProperty = objectLibrary.getProperty(errorObj, JSError.STACK_NAME);
int attrs = JSAttributes.getDefaultNotEnumerable();
if (stackProperty != null) {
if (!JSProperty.isConfigurable(stackProperty)) {
throw Errors.createTypeErrorCannotRedefineProperty(JSError.STACK_NAME);
}
if (JSProperty.isEnumerable(stackProperty)) {
attrs = JSAttributes.getDefault();
}
}
objectLibrary.putConstant(errorObj, JSError.STACK_NAME, JSError.STACK_PROXY, attrs | JSProperty.PROXY);
}
}
}