package com.oracle.truffle.trufflenode;
import static com.oracle.truffle.js.runtime.util.BufferUtil.asBaseBuffer;
import static com.oracle.truffle.trufflenode.ValueType.ARRAY_BUFFER_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.ARRAY_BUFFER_VIEW_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.ARRAY_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.BIGINT64ARRAY_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.BIGUINT64ARRAY_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.BIG_INT_VALUE;
import static com.oracle.truffle.trufflenode.ValueType.BOOLEAN_VALUE_FALSE;
import static com.oracle.truffle.trufflenode.ValueType.BOOLEAN_VALUE_TRUE;
import static com.oracle.truffle.trufflenode.ValueType.DATA_VIEW_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.DATE_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.EXTERNAL_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.FLOAT32ARRAY_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.FLOAT64ARRAY_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.FUNCTION_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.INT16ARRAY_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.INT32ARRAY_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.INT8ARRAY_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.LAZY_STRING_VALUE;
import static com.oracle.truffle.trufflenode.ValueType.MAP_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.NULL_VALUE;
import static com.oracle.truffle.trufflenode.ValueType.NUMBER_VALUE;
import static com.oracle.truffle.trufflenode.ValueType.ORDINARY_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.PROMISE_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.PROXY_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.REGEXP_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.SET_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.STRING_VALUE;
import static com.oracle.truffle.trufflenode.ValueType.SYMBOL_VALUE;
import static com.oracle.truffle.trufflenode.ValueType.UINT16ARRAY_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.UINT32ARRAY_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.UINT8ARRAY_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.UINT8CLAMPEDARRAY_OBJECT;
import static com.oracle.truffle.trufflenode.ValueType.UNDEFINED_VALUE;
import static com.oracle.truffle.trufflenode.ValueType.UNKNOWN_TYPE;
import static com.oracle.truffle.trufflenode.buffer.NIOBuffer.NIO_BUFFER_MODULE_NAME;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.InvalidPathException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.PolyglotException;
import com.oracle.js.parser.ir.FunctionNode;
import com.oracle.js.parser.ir.Module;
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.InstrumentInfo;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.TruffleFile;
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.debug.Breakpoint;
import com.oracle.truffle.api.debug.Debugger;
import com.oracle.truffle.api.debug.SuspendedCallback;
import com.oracle.truffle.api.debug.SuspendedEvent;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.nodes.ControlFlowException;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.DynamicObjectLibrary;
import com.oracle.truffle.api.object.HiddenKey;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.js.builtins.JSONBuiltins;
import com.oracle.truffle.js.builtins.helper.TruffleJSONParser;
import com.oracle.truffle.js.lang.JavaScriptLanguage;
import com.oracle.truffle.js.nodes.NodeFactory;
import com.oracle.truffle.js.nodes.ScriptNode;
import com.oracle.truffle.js.nodes.access.GetPrototypeNode;
import com.oracle.truffle.js.nodes.function.ConstructorRootNode;
import com.oracle.truffle.js.parser.GraalJSEvaluator;
import com.oracle.truffle.js.parser.GraalJSParserHelper;
import com.oracle.truffle.js.parser.JSParser;
import com.oracle.truffle.js.parser.JavaScriptTranslator;
import com.oracle.truffle.js.runtime.BigInt;
import com.oracle.truffle.js.runtime.Errors;
import com.oracle.truffle.js.runtime.Evaluator;
import com.oracle.truffle.js.runtime.ExitException;
import com.oracle.truffle.js.runtime.GraalJSException;
import com.oracle.truffle.js.runtime.ImportMetaInitializer;
import com.oracle.truffle.js.runtime.ImportModuleDynamicallyCallback;
import com.oracle.truffle.js.runtime.JSAgentWaiterList;
import com.oracle.truffle.js.runtime.JSArguments;
import com.oracle.truffle.js.runtime.JSConfig;
import com.oracle.truffle.js.runtime.JSContext;
import com.oracle.truffle.js.runtime.JSContextOptions;
import com.oracle.truffle.js.runtime.JSErrorType;
import com.oracle.truffle.js.runtime.JSException;
import com.oracle.truffle.js.runtime.JSParserOptions;
import com.oracle.truffle.js.runtime.JSRealm;
import com.oracle.truffle.js.runtime.JSRuntime;
import com.oracle.truffle.js.runtime.JavaScriptRootNode;
import com.oracle.truffle.js.runtime.PrepareStackTraceCallback;
import com.oracle.truffle.js.runtime.PromiseHook;
import com.oracle.truffle.js.runtime.PromiseRejectionTracker;
import com.oracle.truffle.js.runtime.RegexCompilerInterface;
import com.oracle.truffle.js.runtime.SafeInteger;
import com.oracle.truffle.js.runtime.Symbol;
import com.oracle.truffle.js.runtime.UserScriptException;
import com.oracle.truffle.js.runtime.array.ScriptArray;
import com.oracle.truffle.js.runtime.array.TypedArray;
import com.oracle.truffle.js.runtime.array.TypedArrayFactory;
import com.oracle.truffle.js.runtime.builtins.JSArgumentsArray;
import com.oracle.truffle.js.runtime.builtins.JSArray;
import com.oracle.truffle.js.runtime.builtins.JSArrayBuffer;
import com.oracle.truffle.js.runtime.builtins.JSArrayBufferView;
import com.oracle.truffle.js.runtime.builtins.JSBigInt;
import com.oracle.truffle.js.runtime.builtins.JSBoolean;
import com.oracle.truffle.js.runtime.builtins.JSClass;
import com.oracle.truffle.js.runtime.builtins.JSDataView;
import com.oracle.truffle.js.runtime.builtins.JSDate;
import com.oracle.truffle.js.runtime.builtins.JSError;
import com.oracle.truffle.js.runtime.builtins.JSFunction;
import com.oracle.truffle.js.runtime.builtins.JSFunctionData;
import com.oracle.truffle.js.runtime.builtins.JSMap;
import com.oracle.truffle.js.runtime.builtins.JSModuleNamespace;
import com.oracle.truffle.js.runtime.builtins.JSNumber;
import com.oracle.truffle.js.runtime.builtins.JSOrdinary;
import com.oracle.truffle.js.runtime.builtins.JSPromise;
import com.oracle.truffle.js.runtime.builtins.JSProxy;
import com.oracle.truffle.js.runtime.builtins.JSRegExp;
import com.oracle.truffle.js.runtime.builtins.JSSet;
import com.oracle.truffle.js.runtime.builtins.JSSharedArrayBuffer;
import com.oracle.truffle.js.runtime.builtins.JSString;
import com.oracle.truffle.js.runtime.builtins.JSSymbol;
import com.oracle.truffle.js.runtime.builtins.JSWeakMap;
import com.oracle.truffle.js.runtime.builtins.JSWeakSet;
import com.oracle.truffle.js.runtime.objects.JSAttributes;
import com.oracle.truffle.js.runtime.objects.JSCopyableObject;
import com.oracle.truffle.js.runtime.objects.JSDynamicObject;
import com.oracle.truffle.js.runtime.objects.JSLazyString;
import com.oracle.truffle.js.runtime.objects.JSModuleLoader;
import com.oracle.truffle.js.runtime.objects.JSModuleRecord;
import com.oracle.truffle.js.runtime.objects.JSModuleRecord.Status;
import com.oracle.truffle.js.runtime.objects.JSObject;
import com.oracle.truffle.js.runtime.objects.JSObjectUtil;
import com.oracle.truffle.js.runtime.objects.Null;
import com.oracle.truffle.js.runtime.objects.PropertyDescriptor;
import com.oracle.truffle.js.runtime.objects.ScriptOrModule;
import com.oracle.truffle.js.runtime.objects.Undefined;
import com.oracle.truffle.js.runtime.util.DirectByteBufferHelper;
import com.oracle.truffle.js.runtime.util.JSHashMap;
import com.oracle.truffle.js.runtime.util.Pair;
import com.oracle.truffle.js.runtime.util.TRegexUtil;
import com.oracle.truffle.trufflenode.buffer.NIOBuffer;
import com.oracle.truffle.trufflenode.info.Accessor;
import com.oracle.truffle.trufflenode.info.FunctionTemplate;
import com.oracle.truffle.trufflenode.info.ObjectTemplate;
import com.oracle.truffle.trufflenode.info.PropertyHandler;
import com.oracle.truffle.trufflenode.info.Script;
import com.oracle.truffle.trufflenode.info.UnboundScript;
import com.oracle.truffle.trufflenode.info.Value;
import com.oracle.truffle.trufflenode.node.ExecuteNativeFunctionNode;
import com.oracle.truffle.trufflenode.node.ExecuteNativePropertyHandlerNode;
import com.oracle.truffle.trufflenode.node.debug.SetBreakPointNode;
import com.oracle.truffle.trufflenode.serialization.Deserializer;
import com.oracle.truffle.trufflenode.serialization.Serializer;
import com.oracle.truffle.trufflenode.threading.JavaMessagePortData;
import com.oracle.truffle.trufflenode.threading.SharedMemMessagingBindings;
import com.oracle.truffle.trufflenode.threading.SharedMemMessagingManager;
@SuppressWarnings("static-method")
public final class GraalJSAccess {
private static final boolean VERBOSE = Boolean.getBoolean("truffle.node.js.verbose");
private static final boolean USE_NIO_BUFFER = !"false".equals(System.getProperty("node.buffer.nio"));
private static final boolean USE_SNAPSHOTS = !"false".equalsIgnoreCase(System.getProperty("truffle.node.js.snapshots"));
private static final HiddenKey PRIVATE_VALUES_KEY = new HiddenKey("PrivateValues");
private static final HiddenKey FUNCTION_TEMPLATE_DATA_KEY = new HiddenKey("FunctionTemplateData");
private static final HiddenKey INTERNAL_FIELD_COUNT_KEY = new HiddenKey("InternalFieldCount");
private static final HiddenKey INTERNAL_FIELD_ZERO_KEY = new HiddenKey("InternalField0");
private static final Symbol RESOLVER_RESOLVE = Symbol.create("Resolve");
private static final Symbol RESOLVER_REJECT = Symbol.create("Reject");
public static final HiddenKey HOLDER_KEY = new HiddenKey("Holder");
public static final HiddenKey EXTERNALIZED_KEY = new HiddenKey("Externalized");
private static final Object INT_PLACEHOLDER = new Object();
private static final Object SAFE_INT_PLACEHOLDER = new Object();
private static final Object DOUBLE_PLACEHOLDER = new Object();
private final Context evaluator;
private final JSContext mainJSContext;
private final JSRealm mainJSRealm;
private final NodeJSAgent agent;
private final Deallocator deallocator;
private ESModuleLoader moduleLoader;
private final TruffleLanguage.Env envForInstruments;
private final ByteBuffer sharedBuffer = ByteBuffer.allocateDirect(128).order(ByteOrder.nativeOrder());
private final Map<String, Reference<String>> sourceCodeCache = new WeakHashMap<>();
private final Map<Source, Object> hostDefinedOptionsMap = new WeakHashMap<>();
private final boolean exposeGC;
private GraalJSAccess(String[] args) throws Exception {
try {
Options options = Options.parseArguments(prepareArguments(args));
Context.Builder contextBuilder = options.getContextBuilder();
contextBuilder.option(JSContextOptions.DIRECT_BYTE_BUFFER_NAME, "true");
contextBuilder.option(JSContextOptions.V8_COMPATIBILITY_MODE_NAME, "true");
contextBuilder.option(JSContextOptions.INTL_402_NAME, "true");
contextBuilder.option(JSContextOptions.CLASS_FIELDS_NAME, "true");
contextBuilder.option(JSContextOptions.LOAD_NAME, "false");
contextBuilder.option(JSContextOptions.CONSOLE_NAME, "false");
contextBuilder.option(JSContextOptions.GLOBAL_ARGUMENTS_NAME, "false");
exposeGC = options.isGCExposed();
evaluator = contextBuilder.build();
mainJSRealm = JavaScriptLanguage.getJSRealm(evaluator);
} catch (IllegalArgumentException iaex) {
System.err.printf("ERROR: %s", iaex.getMessage());
System.exit(1);
throw iaex;
} catch (PolyglotException pex) {
int exitCode = 1;
String message = pex.getMessage();
boolean emptyMessage = message == null || message.isEmpty();
if (pex.isExit()) {
exitCode = pex.getExitStatus();
if (exitCode != 0 && !emptyMessage) {
System.err.println(message);
}
} else if (pex.isInternalError() || emptyMessage) {
pex.printStackTrace();
} else {
System.err.println("ERROR: " + message);
}
System.exit(exitCode);
throw pex;
}
mainJSContext = mainJSRealm.getContext();
assert mainJSContext != null : "JSContext initialized";
agent = new NodeJSAgent();
mainJSRealm.setAgent(agent);
agent.interopBoundaryEnter();
deallocator = new Deallocator();
envForInstruments = mainJSRealm.getEnv();
isolateEnableImportModuleDynamically(false);
}
private static String[] prepareArguments(String[] args) {
String options = System.getenv("NODE_POLYGLOT_OPTIONS");
if (options == null) {
return args;
}
String[] additionalArgs = options.split(" ");
String[] mergedArgs = new String[args.length + additionalArgs.length];
System.arraycopy(args, 0, mergedArgs, 0, args.length);
System.arraycopy(additionalArgs, 0, mergedArgs, args.length, additionalArgs.length);
return mergedArgs;
}
public static Object create(String[] args) throws Exception {
Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
return new GraalJSAccess(args);
}
public Object undefinedInstance() {
return Undefined.instance;
}
public Object nullInstance() {
return Null.instance;
}
public void resetSharedBuffer() {
asBaseBuffer(sharedBuffer).clear();
}
public ByteBuffer getSharedBuffer() {
return DirectByteBufferHelper.cast(sharedBuffer);
}
public int valueType(Object value) {
return valueType(value, false);
}
@TruffleBoundary
public int valueType(Object value, boolean useSharedBuffer) {
if (value == Undefined.instance) {
return UNDEFINED_VALUE;
} else if (value == Null.instance) {
return NULL_VALUE;
} else if (value == Boolean.TRUE) {
return BOOLEAN_VALUE_TRUE;
} else if (value == Boolean.FALSE) {
return BOOLEAN_VALUE_FALSE;
} else if (value instanceof String) {
return STRING_VALUE;
} else if (JSRuntime.isNumber(value)) {
if (useSharedBuffer) {
sharedBuffer.putDouble(((Number) value).doubleValue());
}
return NUMBER_VALUE;
} else if (JSDynamicObject.isJSDynamicObject(value)) {
return valueTypeJSObject((DynamicObject) value, useSharedBuffer);
} else if (JSRuntime.isForeignObject(value)) {
return valueTypeForeignObject((TruffleObject) value, useSharedBuffer);
} else if (JSRuntime.isString(value)) {
return LAZY_STRING_VALUE;
} else if (value instanceof Symbol) {
return SYMBOL_VALUE;
} else if (value instanceof BigInt) {
return BIG_INT_VALUE;
} else if (value instanceof Boolean) {
return ((Boolean) value).booleanValue() ? BOOLEAN_VALUE_TRUE : BOOLEAN_VALUE_FALSE;
}
if (value instanceof Throwable) {
valueTypeError(value);
}
return UNKNOWN_TYPE;
}
private int valueTypeForeignObject(TruffleObject value, boolean useSharedBuffer) {
InteropLibrary interop = InteropLibrary.getFactory().getUncached(value);
if (interop.isExecutable(value) || interop.isInstantiable(value)) {
return FUNCTION_OBJECT;
} else if (interop.isNull(value)) {
return NULL_VALUE;
} else if (interop.isBoolean(value)) {
try {
return interop.asBoolean(value) ? BOOLEAN_VALUE_TRUE : BOOLEAN_VALUE_FALSE;
} catch (UnsupportedMessageException e) {
valueTypeError(value);
return UNKNOWN_TYPE;
}
} else if (interop.isString(value)) {
return STRING_VALUE;
} else if (interop.isNumber(value)) {
return valueTypeForeignNumber(value, interop, useSharedBuffer);
} else {
return ORDINARY_OBJECT;
}
}
public int valueTypeForeignNumber(TruffleObject value, InteropLibrary interop, boolean useSharedBuffer) {
try {
return valueType(interop.asDouble(value), useSharedBuffer);
} catch (UnsupportedMessageException e) {
if (interop.fitsInLong(value)) {
try {
return valueType(interop.asLong(value), useSharedBuffer);
} catch (UnsupportedMessageException ignore) {
}
}
}
valueTypeError(value);
return UNKNOWN_TYPE;
}
private int valueTypeJSObject(DynamicObject obj, boolean useSharedBuffer) {
if (JSExternal.isJSExternalObject(obj)) {
return EXTERNAL_OBJECT;
} else if (JSFunction.isJSFunction(obj)) {
return FUNCTION_OBJECT;
} else if (JSArray.isJSArray(obj)) {
return ARRAY_OBJECT;
} else if (JSDate.isJSDate(obj)) {
return DATE_OBJECT;
} else if (JSRegExp.isJSRegExp(obj)) {
return REGEXP_OBJECT;
} else if (JSArrayBufferView.isJSArrayBufferView(obj)) {
return valueTypeArrayBufferView(obj, useSharedBuffer);
} else if (JSArrayBuffer.isJSDirectArrayBuffer(obj)) {
return ARRAY_BUFFER_OBJECT;
} else if (JSDataView.isJSDataView(obj)) {
if (useSharedBuffer) {
JSContext context = JSObject.getJSContext(obj);
sharedBuffer.putInt(arrayBufferViewByteLength(context, obj));
sharedBuffer.putInt(arrayBufferViewByteOffset(context, obj));
}
return DATA_VIEW_OBJECT;
} else if (JSMap.isJSMap(obj)) {
return MAP_OBJECT;
} else if (JSSet.isJSSet(obj)) {
return SET_OBJECT;
} else if (JSPromise.isJSPromise(obj)) {
return PROMISE_OBJECT;
} else if (JSProxy.isJSProxy(obj)) {
return PROXY_OBJECT;
} else {
return ORDINARY_OBJECT;
}
}
private int valueTypeArrayBufferView(DynamicObject obj, boolean useSharedBuffer) {
if (useSharedBuffer) {
JSContext context = JSObject.getJSContext(obj);
sharedBuffer.putInt(arrayBufferViewByteLength(context, obj));
sharedBuffer.putInt(arrayBufferViewByteOffset(context, obj));
}
ScriptArray array = JSObject.getArray(obj);
if (array instanceof TypedArray.DirectUint8Array) {
return UINT8ARRAY_OBJECT;
} else if (array instanceof TypedArray.DirectUint8ClampedArray) {
return UINT8CLAMPEDARRAY_OBJECT;
} else if (array instanceof TypedArray.DirectInt8Array) {
return INT8ARRAY_OBJECT;
} else if (array instanceof TypedArray.DirectUint16Array) {
return UINT16ARRAY_OBJECT;
} else if (array instanceof TypedArray.DirectInt16Array) {
return INT16ARRAY_OBJECT;
} else if (array instanceof TypedArray.DirectUint32Array) {
return UINT32ARRAY_OBJECT;
} else if (array instanceof TypedArray.DirectInt32Array) {
return INT32ARRAY_OBJECT;
} else if (array instanceof TypedArray.DirectFloat32Array) {
return FLOAT32ARRAY_OBJECT;
} else if (array instanceof TypedArray.DirectFloat64Array) {
return FLOAT64ARRAY_OBJECT;
} else if (array instanceof TypedArray.DirectBigInt64Array) {
return BIGINT64ARRAY_OBJECT;
} else if (array instanceof TypedArray.DirectBigUint64Array) {
return BIGUINT64ARRAY_OBJECT;
} else {
return ARRAY_BUFFER_VIEW_OBJECT;
}
}
@CompilerDirectives.TruffleBoundary
public static void valueTypeError(Object value) {
System.err.println("unknown type: " + ((value == null) ? null : value.getClass().getSimpleName()));
}
public double valueDouble(Object obj) {
return JSRuntime.toDouble(obj);
}
public long valueExternal(Object obj) {
return ((JSExternalObject) obj).getPointer();
}
public String valueUnknown(Object obj) {
return obj.toString();
}
public Object valueToObject(Object context, Object value) {
return JSRuntime.toObject(((JSRealm) context).getContext(), value);
}
public Object valueToInteger(Object value) {
if (value instanceof Double) {
double doubleValue = (Double) value;
if (doubleValue < Long.MIN_VALUE || Long.MAX_VALUE < doubleValue || doubleValue == 0) {
return value;
}
}
long integer = JSRuntime.toInteger(value);
if (JSRuntime.longIsRepresentableAsInt(integer)) {
return (int) integer;
} else {
return (double) integer;
}
}
public Object valueToInt32(Object value) {
return JSRuntime.toInt32(value);
}
public Object valueToUint32(Object value) {
return (double) JSRuntime.toUInt32(value);
}
public String valueToString(Object value) {
return JSRuntime.toString(value);
}
public boolean valueToBoolean(Object value) {
return JSRuntime.toBoolean(value);
}
public Object valueToNumber(Object value) {
return JSRuntime.toNumber(value);
}
public Object valueToArrayIndex(Object value) {
if (JSRuntime.isArrayIndex(value)) {
double index = JSRuntime.toDouble(value);
if (index == 0) {
index = 0;
}
resetSharedBuffer();
sharedBuffer.putDouble(index);
return index;
} else {
return null;
}
}
public int valueInt32Value(Object value) {
return JSRuntime.toInt32(value);
}
public double valueUint32Value(Object value) {
return JSRuntime.toUInt32(value);
}
public long valueIntegerValue(Object value) {
return JSRuntime.toInteger(value);
}
public boolean valueIsNativeError(Object object) {
return JSError.isJSError(object);
}
public boolean valueIsSetIterator(Object object) {
if (JSRuntime.isObject(object)) {
DynamicObject dynamicObject = (DynamicObject) object;
Object iteratedObj = JSObjectUtil.getHiddenProperty(dynamicObject, JSRuntime.ITERATED_OBJECT_ID);
return JSSet.isJSSet(iteratedObj);
}
return false;
}
public boolean valueIsMapIterator(Object object) {
if (JSRuntime.isObject(object)) {
DynamicObject dynamicObject = (DynamicObject) object;
Object iteratedObj = JSObjectUtil.getHiddenProperty(dynamicObject, JSRuntime.ITERATED_OBJECT_ID);
return JSMap.isJSMap(iteratedObj);
}
return false;
}
public boolean valueIsSharedArrayBuffer(Object object) {
return JSSharedArrayBuffer.isJSSharedArrayBuffer(object);
}
public boolean valueIsArgumentsObject(Object object) {
return JSArgumentsArray.isJSArgumentsObject(object);
}
public boolean valueIsBooleanObject(Object object) {
return JSBoolean.isJSBoolean(object);
}
public boolean valueIsNumberObject(Object object) {
return JSNumber.isJSNumber(object);
}
public boolean valueIsStringObject(Object object) {
return JSString.isJSString(object);
}
public boolean valueIsSymbolObject(Object object) {
return JSSymbol.isJSSymbol(object);
}
public boolean valueIsBigIntObject(Object object) {
return JSBigInt.isJSBigInt(object);
}
public boolean valueIsWeakMap(Object object) {
return JSWeakMap.isJSWeakMap(object);
}
public boolean valueIsWeakSet(Object object) {
return JSWeakSet.isJSWeakSet(object);
}
public boolean valueIsAsyncFunction(Object object) {
return JSFunction.isJSFunction(object) ? JSFunction.getFunctionData((DynamicObject) object).isAsync() : false;
}
public boolean valueIsGeneratorFunction(Object object) {
return JSFunction.isJSFunction(object) ? JSFunction.getFunctionData((DynamicObject) object).isGenerator() : false;
}
public boolean valueIsGeneratorObject(Object object) {
return (object instanceof DynamicObject) && DynamicObjectLibrary.getUncached().containsKey((DynamicObject) object, JSFunction.GENERATOR_STATE_ID);
}
public boolean valueIsModuleNamespaceObject(Object object) {
return JSModuleNamespace.isJSModuleNamespace(object);
}
public boolean valueEquals(Object left, Object right) {
return JSRuntime.equal(left, right);
}
public boolean valueStrictEquals(Object left, Object right) {
return JSRuntime.identical(left, right);
}
public boolean valueInstanceOf(Object left, Object right) {
if (left instanceof DynamicObject) {
DynamicObject function = (DynamicObject) right;
Object hasInstance = JSObject.get(function, Symbol.SYMBOL_HAS_INSTANCE);
if (hasInstance == Undefined.instance) {
Object prototype = JSObject.get(function, JSObject.PROTOTYPE);
if (prototype instanceof DynamicObject) {
return JSRuntime.isPrototypeOf((DynamicObject) left, (DynamicObject) prototype);
} else {
throw Errors.createTypeError("prototype is not an Object");
}
} else {
return JSRuntime.toBoolean(JSRuntime.call(hasInstance, function, new Object[]{left}));
}
} else {
return false;
}
}
public String valueTypeOf(Object value) {
return JSRuntime.typeof(value);
}
public Object objectNew(Object context) {
JSRealm jsRealm = (JSRealm) context;
return JSOrdinary.create(jsRealm.getContext(), jsRealm);
}
public boolean objectSet(Object object, Object key, Object value) {
DynamicObject dynamicObject = (DynamicObject) object;
if (key instanceof HiddenKey) {
JSObjectUtil.putHiddenProperty(dynamicObject, key, value);
} else {
JSObject.set(dynamicObject, JSRuntime.toPropertyKey(key), value);
}
return true;
}
public boolean objectSetIndex(Object object, int index, Object value) {
JSObject.set((DynamicObject) object, index, value);
return true;
}
public boolean objectForceSet(Object object, Object key, Object value, int attributes) {
Object propertyKey = JSRuntime.toPropertyKey(key);
JSObject.delete((DynamicObject) object, propertyKey);
PropertyDescriptor descriptor = propertyDescriptor(attributes, value);
return JSObject.defineOwnProperty((DynamicObject) object, propertyKey, descriptor);
}
public boolean objectSetPrivate(Object context, Object object, Object key, Object value) {
if (JSRuntime.isObject(object)) {
DynamicObject dynamicObject = (DynamicObject) object;
Object privateValues = JSObjectUtil.getHiddenProperty(dynamicObject, PRIVATE_VALUES_KEY);
if (privateValues == null) {
privateValues = objectNew(context);
JSObjectUtil.putHiddenProperty(dynamicObject, PRIVATE_VALUES_KEY, privateValues);
}
JSObject.set((DynamicObject) privateValues, key, value);
}
return true;
}
public Object objectGetPrivate(Object object, Object key) {
if (!JSDynamicObject.isJSDynamicObject(object)) {
return null;
}
DynamicObject dynamicObject = (DynamicObject) object;
DynamicObject privateValues = (DynamicObject) JSObjectUtil.getHiddenProperty(dynamicObject, PRIVATE_VALUES_KEY);
if (privateValues == null) {
return null;
} else if (JSObject.hasOwnProperty(privateValues, key)) {
return JSObject.get(privateValues, key);
} else {
return null;
}
}
public boolean objectDeletePrivate(Object object, Object key) {
if (!JSDynamicObject.isJSDynamicObject(object)) {
return true;
}
DynamicObject dynamicObject = (DynamicObject) object;
Object privateValues = JSObjectUtil.getHiddenProperty(dynamicObject, PRIVATE_VALUES_KEY);
if (privateValues == null) {
return true;
} else {
return JSObject.delete((DynamicObject) privateValues, key);
}
}
public Object objectGet(Object object, Object key) {
TruffleObject truffleObject;
if (object instanceof TruffleObject) {
truffleObject = (TruffleObject) object;
} else {
truffleObject = JSRuntime.toObject(mainJSContext, object);
}
Object value;
if (key instanceof HiddenKey) {
Object hiddenValue = JSObjectUtil.getHiddenProperty((DynamicObject) truffleObject, key);
if (hiddenValue == null) {
if (JSPromise.isJSPromise(object)) {
value = 0;
} else {
value = Undefined.instance;
}
} else {
value = hiddenValue;
}
} else {
value = JSObject.get(truffleObject, JSRuntime.toPropertyKey(key));
}
Object flatten = valueFlatten(value);
resetSharedBuffer();
asBaseBuffer(sharedBuffer).position(4);
sharedBuffer.putInt(0, valueType(flatten, true));
return flatten;
}
public Object objectGetIndex(Object object, int index) {
Object value = valueFlatten(JSObject.get((DynamicObject) object, index));
resetSharedBuffer();
asBaseBuffer(sharedBuffer).position(4);
sharedBuffer.putInt(0, valueType(value, true));
return value;
}
public Object objectGetOwnPropertyDescriptor(Object object, Object key) {
DynamicObject dynamicObject = (DynamicObject) object;
JSContext context = JSObject.getJSContext(dynamicObject);
PropertyDescriptor desc = JSObject.getOwnProperty(dynamicObject, key);
return JSRuntime.fromPropertyDescriptor(desc, context);
}
public boolean objectDefineProperty(Object object, Object key,
Object value, Object get, Object set,
boolean hasEnumerable, boolean enumerable,
boolean hasConfigurable, boolean configurable,
boolean hasWritable, boolean writable) {
DynamicObject dynamicObject = (DynamicObject) object;
PropertyDescriptor descriptor = PropertyDescriptor.createEmpty();
if (value != null) {
descriptor.setValue(value);
}
if (get != null) {
descriptor.setGet((DynamicObject) get);
}
if (set != null) {
descriptor.setSet((DynamicObject) set);
}
if (hasEnumerable) {
descriptor.setEnumerable(enumerable);
}
if (hasConfigurable) {
descriptor.setConfigurable(configurable);
}
if (hasWritable) {
descriptor.setWritable(writable);
}
return JSObject.defineOwnProperty(dynamicObject, key, descriptor);
}
public Object valueFlatten(Object value) {
if (value instanceof String) {
return value;
} else if (value instanceof JSLazyString) {
return ((JSLazyString) value).toString();
} else if (JSRuntime.isForeignObject(value)) {
InteropLibrary interop = InteropLibrary.getFactory().getUncached(value);
if (interop.isString(value)) {
try {
return interop.asString(value);
} catch (UnsupportedMessageException e) {
}
}
return value;
} else {
return value;
}
}
public boolean objectHas(Object object, Object key) {
return JSObject.hasProperty((DynamicObject) object, JSRuntime.toPropertyKey(key));
}
public boolean objectHasOwnProperty(Object object, Object key) {
return JSObject.hasOwnProperty((DynamicObject) object, key);
}
public boolean objectHasRealNamedProperty(Object object, Object key) {
Object obj = object;
if (JSProxy.isJSProxy(obj)) {
obj = JSProxy.getTarget((DynamicObject) obj);
}
return objectHasOwnProperty(obj, key);
}
public boolean objectDelete(Object object, Object key) {
return JSObject.delete((DynamicObject) object, JSRuntime.toPropertyKey(key));
}
public boolean objectDelete(Object object, long index) {
return JSObject.delete((DynamicObject) object, index);
}
@CompilerDirectives.TruffleBoundary
public boolean objectSetAccessor(Object object, Object name, long getterPtr, long setterPtr, Object data, int attributes) {
DynamicObject dynamicObject = (DynamicObject) object;
JSContext context = JSObject.getJSContext(dynamicObject);
int flags = propertyAttributes(attributes);
Accessor accessor = new Accessor(this, name, getterPtr, setterPtr, data, null, flags);
Pair<JSFunctionData, JSFunctionData> accessorFunctions = accessor.getFunctions(context);
JSRealm realm = context.getRealm();
DynamicObject getter = functionFromFunctionData(realm, accessorFunctions.getFirst(), dynamicObject);
DynamicObject setter = functionFromFunctionData(realm, accessorFunctions.getSecond(), dynamicObject);
JSObjectUtil.putAccessorProperty(context, dynamicObject, accessor.getName(), getter, setter, flags);
return true;
}
public Object objectClone(Object object) {
if (object instanceof JSCopyableObject) {
return ((JSCopyableObject) object).copy();
} else {
throw Errors.createTypeErrorFormat("Cannot copy %s", JSRuntime.safeToString(object));
}
}
public boolean objectSetPrototype(Object object, Object prototype) {
return JSObject.setPrototype((DynamicObject) object, (DynamicObject) prototype);
}
public Object objectGetPrototype(Object object) {
return JSObject.getPrototype((DynamicObject) object);
}
public String objectGetConstructorName(Object object) {
String name = "Object";
if (JSDynamicObject.isJSDynamicObject(object)) {
DynamicObject dynamicObject = (DynamicObject) object;
Object constructor = JSObject.get(dynamicObject, JSObject.CONSTRUCTOR);
if (JSFunction.isJSFunction(constructor)) {
name = JSFunction.getName((DynamicObject) constructor);
}
} else {
InteropLibrary interop = InteropLibrary.getUncached(object);
if (interop.hasMetaObject(object)) {
try {
Object metaObject = interop.getMetaObject(object);
Object interopName = InteropLibrary.getUncached(metaObject).getMetaSimpleName(metaObject);
name = InteropLibrary.getUncached(interopName).asString(interopName);
} catch (UnsupportedMessageException ex) {
throw Errors.shouldNotReachHere(ex);
}
}
}
return name;
}
private static String foreignStringToString(Object foreignString) throws UnsupportedMessageException {
if (foreignString instanceof String) {
return (String) foreignString;
} else {
return InteropLibrary.getFactory().getUncached(foreignString).asString(foreignString);
}
}
public Object objectGetOwnPropertyNames(Object object) {
Object[] namesArray;
if (JSDynamicObject.isJSDynamicObject(object)) {
DynamicObject dynamicObject = (DynamicObject) object;
List<String> names = JSObject.enumerableOwnNames(dynamicObject);
namesArray = names.toArray();
convertArrayIndicesToNumbers(namesArray);
} else {
assert JSRuntime.isForeignObject(object);
try {
List<Object> names = new ArrayList<>();
InteropLibrary library = InteropLibrary.getFactory().getUncached(object);
if (library.hasMembers(object)) {
Object members = library.getMembers(object);
InteropLibrary membersLibrary = InteropLibrary.getFactory().getUncached(members);
long size = membersLibrary.getArraySize(members);
for (long i = 0; i < size; i++) {
Object key = membersLibrary.readArrayElement(members, i);
names.add(foreignStringToString(key));
}
}
if (library.hasArrayElements(object)) {
long size = library.getArraySize(object);
for (long i = 0; i < size; i++) {
if (library.isArrayElementExisting(object, i)) {
names.add(JSRuntime.longToIntOrDouble(i));
}
}
}
namesArray = names.toArray();
} catch (UnsupportedMessageException | InvalidArrayIndexException ex) {
namesArray = new Object[0];
}
}
return JSArray.createConstantObjectArray(mainJSContext, namesArray);
}
public Object objectGetPropertyNames(Object object, boolean ownOnly,
boolean enumerableOnly, boolean configurableOnly, boolean writableOnly,
boolean skipIndices, boolean skipSymbols, boolean skipStrings,
boolean keepNumbers) {
Object[] propertyNames;
if (JSDynamicObject.isJSDynamicObject(object)) {
Set<Object> keys = new LinkedHashSet<>();
DynamicObject dynamicObject = (DynamicObject) object;
do {
JSClass jsclass = JSObject.getJSClass(dynamicObject);
Iterable<Object> ownKeys = jsclass.ownPropertyKeys(dynamicObject);
for (Object key : ownKeys) {
Object keyToStore = key;
if (key instanceof String) {
if (skipStrings) {
continue;
}
boolean index = JSRuntime.isArrayIndex((String) key);
if (index) {
if (skipIndices) {
continue;
}
if (keepNumbers) {
keyToStore = JSRuntime.stringToNumber((String) key);
}
}
} else {
assert key instanceof Symbol;
if (skipSymbols) {
continue;
}
}
PropertyDescriptor desc = jsclass.getOwnProperty(dynamicObject, key);
if ((enumerableOnly && (desc == null || !desc.getEnumerable())) || (configurableOnly && (desc == null || !desc.getConfigurable())) ||
(writableOnly && (desc == null || !desc.getWritable()))) {
continue;
}
keys.add(keyToStore);
}
dynamicObject = JSObject.getPrototype(dynamicObject);
} while (!ownOnly && dynamicObject != Null.instance);
propertyNames = keys.toArray();
} else {
assert JSRuntime.isForeignObject(object);
try {
List<Object> keys = new ArrayList<>();
InteropLibrary library = InteropLibrary.getFactory().getUncached(object);
if (!skipStrings && library.hasMembers(object)) {
Object members = library.getMembers(object);
InteropLibrary membersLibrary = InteropLibrary.getFactory().getUncached(members);
long size = membersLibrary.getArraySize(members);
for (long i = 0; i < size; i++) {
Object key = membersLibrary.readArrayElement(members, i);
String stringKey = foreignStringToString(key);
if (!writableOnly || library.isMemberWritable(object, stringKey)) {
keys.add(stringKey);
}
}
}
if (!skipIndices && library.hasArrayElements(object)) {
long size = library.getArraySize(object);
for (long i = 0; i < size; i++) {
if (library.isArrayElementExisting(object, i)) {
Object key;
if (keepNumbers) {
key = JSRuntime.longToIntOrDouble(i);
} else {
key = String.valueOf(i);
}
if (!writableOnly || library.isArrayElementWritable(object, i)) {
keys.add(key);
}
}
}
}
propertyNames = keys.toArray();
} catch (UnsupportedMessageException | InvalidArrayIndexException ex) {
propertyNames = new Object[0];
}
}
return JSArray.createConstantObjectArray(mainJSContext, propertyNames);
}
private void convertArrayIndicesToNumbers(Object[] namesArray) {
for (int i = 0; i < namesArray.length; i++) {
Object name = namesArray[i];
if (name instanceof String && JSRuntime.isArrayIndex((String) name)) {
namesArray[i] = JSRuntime.stringToNumber((String) name);
}
}
}
public Object objectGetRealNamedProperty(Object object, Object key) {
Object propertyKey = JSRuntime.toPropertyKey(key);
Object current = object;
while (JSRuntime.isObject(current)) {
DynamicObject currentDO = (DynamicObject) current;
if (JSProxy.isJSProxy(currentDO)) {
current = JSProxy.getTarget(currentDO);
} else {
if (JSObject.hasOwnProperty(currentDO, propertyKey)) {
return JSObject.get(currentDO, propertyKey);
}
current = JSObject.getPrototype(currentDO);
}
}
return null;
}
public int objectGetRealNamedPropertyAttributes(Object object, Object key) {
Object propertyKey = JSRuntime.toPropertyKey(key);
Object current = object;
while (JSRuntime.isObject(current)) {
DynamicObject currentDO = (DynamicObject) current;
if (JSProxy.isJSProxy(currentDO)) {
current = JSProxy.getTarget(currentDO);
} else {
PropertyDescriptor descriptor = JSObject.getOwnProperty(currentDO, propertyKey);
if (descriptor != null) {
int attributes = 0;
if (!descriptor.isAccessorDescriptor() && !descriptor.getWritable()) {
attributes |= 1;
}
if (!descriptor.getEnumerable()) {
attributes |= 2;
}
if (!descriptor.getConfigurable()) {
attributes |= 4;
}
return attributes;
}
current = JSObject.getPrototype(currentDO);
}
}
return -1;
}
public Object objectCreationContext(Object object) {
DynamicObject dynamicObject = (DynamicObject) object;
if (JSFunction.isJSFunction(object)) {
return JSFunction.getRealm(dynamicObject);
} else {
return objectCreationContextFromConstructor(dynamicObject);
}
}
private Object objectCreationContextFromConstructor(DynamicObject object) {
if (!JSProxy.isJSProxy(object)) {
DynamicObject prototype = JSObject.getPrototype(object);
if (prototype != Null.instance) {
Object constructor = JSRuntime.getDataProperty(prototype, JSObject.CONSTRUCTOR);
if (JSFunction.isJSFunction(constructor)) {
return JSFunction.getRealm((DynamicObject) constructor);
}
}
} else if (JSRuntime.isCallableProxy(object)) {
return objectCreationContext(JSProxy.getTarget(object));
}
throw new IllegalArgumentException("Cannot get creation context for this object");
}
public void objectSetIntegrityLevel(Object object, boolean freeze) {
if (JSDynamicObject.isJSDynamicObject(object)) {
JSObject.setIntegrityLevel((DynamicObject) object, freeze, true);
}
}
public Object arrayNew(Object context, int length) {
return JSArray.createConstantEmptyArray(((JSRealm) context).getContext(), length);
}
public long arrayLength(Object object) {
return JSArray.arrayGetLength((DynamicObject) object);
}
public Object arrayBufferNew(Object context, Object buffer, long pointer) {
ByteBuffer byteBuffer = (ByteBuffer) buffer;
if (pointer != 0) {
deallocator.register(byteBuffer, pointer);
}
DynamicObject arrayBuffer = JSArrayBuffer.createDirectArrayBuffer(((JSRealm) context).getContext(), byteBuffer);
JSObjectUtil.putHiddenProperty(arrayBuffer, EXTERNALIZED_KEY, pointer == 0);
return arrayBuffer;
}
public Object arrayBufferNew(Object context, int byteLength) {
return JSArrayBuffer.createDirectArrayBuffer(((JSRealm) context).getContext(), byteLength);
}
public Object arrayBufferGetContents(Object arrayBuffer) {
return JSArrayBuffer.getDirectByteBuffer((DynamicObject) arrayBuffer);
}
public Object arrayBufferViewBuffer(Object arrayBufferView) {
DynamicObject dynamicObject = (DynamicObject) arrayBufferView;
if (JSDataView.isJSDataView(arrayBufferView)) {
return JSDataView.getArrayBuffer(dynamicObject);
} else {
return JSArrayBufferView.getArrayBuffer(dynamicObject);
}
}
public int arrayBufferViewByteLength(Object arrayBufferView) {
DynamicObject dynamicObject = (DynamicObject) arrayBufferView;
return arrayBufferViewByteLength(JSObject.getJSContext(dynamicObject), dynamicObject);
}
public boolean arrayBufferIsExternal(Object arrayBuffer) {
return JSObjectUtil.getHiddenProperty((DynamicObject) arrayBuffer, EXTERNALIZED_KEY) == Boolean.TRUE;
}
public void arrayBufferExternalize(Object arrayBuffer) {
DynamicObject dynamicObject = (DynamicObject) arrayBuffer;
JSObjectUtil.putHiddenProperty(dynamicObject, EXTERNALIZED_KEY, true);
}
public void arrayBufferDetach(Object arrayBuffer) {
JSArrayBuffer.detachArrayBuffer((DynamicObject) arrayBuffer);
}
public static int arrayBufferViewByteLength(JSContext context, DynamicObject arrayBufferView) {
if (JSDataView.isJSDataView(arrayBufferView)) {
return JSDataView.typedArrayGetLength(arrayBufferView);
} else {
return JSArrayBufferView.getByteLength(arrayBufferView, context);
}
}
public int arrayBufferViewByteOffset(Object arrayBufferView) {
DynamicObject dynamicObject = (DynamicObject) arrayBufferView;
return arrayBufferViewByteOffset(JSObject.getJSContext(dynamicObject), dynamicObject);
}
public static int arrayBufferViewByteOffset(JSContext context, DynamicObject arrayBufferView) {
if (JSDataView.isJSDataView(arrayBufferView)) {
return JSDataView.typedArrayGetOffset(arrayBufferView);
} else {
return JSArrayBufferView.getByteOffset(arrayBufferView, context);
}
}
private static final ReferenceQueue<JSAgentWaiterList> agentWaiterListQueue = new ReferenceQueue<>();
private static final Map<Long, WeakReference<JSAgentWaiterList>> agentWaiterListMap = new HashMap<>();
private static class WeakAgentWaiterList extends WeakReference<JSAgentWaiterList> {
long pointer;
WeakAgentWaiterList(JSAgentWaiterList wl, long pointer) {
super(wl, agentWaiterListQueue);
this.pointer = pointer;
}
}
private static void pollAgentWaiterListQueue() {
WeakAgentWaiterList ref;
while ((ref = (WeakAgentWaiterList) agentWaiterListQueue.poll()) != null) {
if (agentWaiterListMap.get(ref.pointer).get() == null) {
agentWaiterListMap.remove(ref.pointer);
}
}
}
private static void updateWaiterList(DynamicObject sharedArrayBuffer, long pointer) {
synchronized (agentWaiterListMap) {
pollAgentWaiterListQueue();
assert JSSharedArrayBuffer.isJSSharedArrayBuffer(sharedArrayBuffer);
assert pointer != 0;
WeakReference<JSAgentWaiterList> ref = agentWaiterListMap.get(pointer);
JSAgentWaiterList wl = (ref == null) ? null : ref.get();
if (wl == null) {
ref = new WeakAgentWaiterList(JSSharedArrayBuffer.getWaiterList(sharedArrayBuffer), pointer);
agentWaiterListMap.put(pointer, ref);
} else {
JSSharedArrayBuffer.setWaiterList(sharedArrayBuffer, wl);
}
}
}
public Object sharedArrayBufferNew(Object context, Object buffer, long pointer, boolean externalized) {
ByteBuffer byteBuffer = (ByteBuffer) buffer;
DynamicObject sharedArrayBuffer = JSSharedArrayBuffer.createSharedArrayBuffer(((JSRealm) context).getContext(), byteBuffer);
JSObjectUtil.putHiddenProperty(sharedArrayBuffer, EXTERNALIZED_KEY, externalized);
if (externalized) {
updateWaiterList(sharedArrayBuffer, pointer);
} else {
deallocator.register(byteBuffer, pointer);
}
return sharedArrayBuffer;
}
public boolean sharedArrayBufferIsExternal(Object sharedArrayBuffer) {
return JSObjectUtil.getHiddenProperty((DynamicObject) sharedArrayBuffer, EXTERNALIZED_KEY) == Boolean.TRUE;
}
public Object sharedArrayBufferGetContents(Object sharedArrayBuffer) {
return JSSharedArrayBuffer.getDirectByteBuffer((DynamicObject) sharedArrayBuffer);
}
public void sharedArrayBufferExternalize(Object sharedArrayBuffer, long pointer) {
DynamicObject dynamicObject = (DynamicObject) sharedArrayBuffer;
JSObjectUtil.putHiddenProperty(dynamicObject, EXTERNALIZED_KEY, true);
updateWaiterList(dynamicObject, pointer);
}
public int typedArrayLength(Object typedArray) {
return JSArrayBufferView.typedArrayGetLength((DynamicObject) typedArray);
}
private Object typedArrayNew(Object arrayBuffer, int offset, int length, TypedArrayFactory factory) {
TypedArray arrayType = factory.createArrayType(true, offset != 0);
DynamicObject dynamicObject = (DynamicObject) arrayBuffer;
JSContext context = JSObject.getJSContext(dynamicObject);
return JSArrayBufferView.createArrayBufferView(context, dynamicObject, arrayType, offset, length);
}
public Object uint8ArrayNew(Object arrayBuffer, int offset, int length) {
return typedArrayNew(arrayBuffer, offset, length, TypedArrayFactory.Uint8Array);
}
public Object uint8ClampedArrayNew(Object arrayBuffer, int offset, int length) {
return typedArrayNew(arrayBuffer, offset, length, TypedArrayFactory.Uint8ClampedArray);
}
public Object int8ArrayNew(Object arrayBuffer, int offset, int length) {
return typedArrayNew(arrayBuffer, offset, length, TypedArrayFactory.Int8Array);
}
public Object uint16ArrayNew(Object arrayBuffer, int offset, int length) {
return typedArrayNew(arrayBuffer, offset, length, TypedArrayFactory.Uint16Array);
}
public Object int16ArrayNew(Object arrayBuffer, int offset, int length) {
return typedArrayNew(arrayBuffer, offset, length, TypedArrayFactory.Int16Array);
}
public Object uint32ArrayNew(Object arrayBuffer, int offset, int length) {
return typedArrayNew(arrayBuffer, offset, length, TypedArrayFactory.Uint32Array);
}
public Object int32ArrayNew(Object arrayBuffer, int offset, int length) {
return typedArrayNew(arrayBuffer, offset, length, TypedArrayFactory.Int32Array);
}
public Object float32ArrayNew(Object arrayBuffer, int offset, int length) {
return typedArrayNew(arrayBuffer, offset, length, TypedArrayFactory.Float32Array);
}
public Object float64ArrayNew(Object arrayBuffer, int offset, int length) {
return typedArrayNew(arrayBuffer, offset, length, TypedArrayFactory.Float64Array);
}
public Object bigInt64ArrayNew(Object arrayBuffer, int offset, int length) {
return typedArrayNew(arrayBuffer, offset, length, TypedArrayFactory.BigInt64Array);
}
public Object bigUint64ArrayNew(Object arrayBuffer, int offset, int length) {
return typedArrayNew(arrayBuffer, offset, length, TypedArrayFactory.BigUint64Array);
}
public Object dataViewNew(Object arrayBuffer, int offset, int length) {
DynamicObject dynamicObject = (DynamicObject) arrayBuffer;
JSContext context = JSObject.getJSContext(dynamicObject);
return JSDataView.createDataView(context, dynamicObject, offset, length);
}
public Object externalNew(Object context, long pointer) {
return JSExternal.create(((JSRealm) context).getContext(), pointer);
}
public Object integerNew(long value) {
return (double) value;
}
public Object numberNew(double value) {
return value;
}
public Object dateNew(Object context, double value) {
return JSDate.create(((JSRealm) context).getContext(), value);
}
public double dateValueOf(Object date) {
return JSDate.getTimeMillisField((DynamicObject) date);
}
public Object symbolNew(Object name) {
return Symbol.create((String) name);
}
public Object symbolName(Object symbol) {
return ((Symbol) symbol).getDescription();
}
public Object symbolGetIterator() {
return Symbol.SYMBOL_ITERATOR;
}
public Object functionNewInstance(Object function, Object[] arguments) {
DynamicObject functionObject = (DynamicObject) function;
JSFunctionData functionData = JSFunction.getFunctionData(functionObject);
Object[] callArguments = JSArguments.create(null, function, arguments);
return functionData.getConstructTarget().call(callArguments);
}
public void functionSetName(Object function, String name) {
DynamicObject functionObject = (DynamicObject) function;
JSFunctionData functionData = JSFunction.getFunctionData(functionObject);
functionData.setName(name);
}
public String functionGetName(Object function) {
DynamicObject functionObject = (DynamicObject) function;
JSFunctionData functionData = JSFunction.getFunctionData(functionObject);
return functionData.getName();
}
public Object functionCall(Object function, Object receiver, Object[] arguments) {
Object value = JSRuntime.call(function, receiver, arguments);
Object flatten = valueFlatten(value);
resetSharedBuffer();
asBaseBuffer(sharedBuffer).position(4);
sharedBuffer.putInt(0, valueType(flatten, true));
return flatten;
}
public Object functionCall0(Object function, Object receiver) {
return functionCall(function, receiver, JSArguments.EMPTY_ARGUMENTS_ARRAY);
}
public Object functionCall1(Object function, Object receiver, Object arg0) {
return functionCall(function, receiver, new Object[]{arg0});
}
public Object functionCall2(Object function, Object receiver, Object arg0, Object arg1) {
return functionCall(function, receiver, new Object[]{arg0, arg1});
}
public Object functionCall3(Object function, Object receiver, Object arg0, Object arg1, Object arg2) {
return functionCall(function, receiver, new Object[]{arg0, arg1, arg2});
}
public Object functionCall4(Object function, Object receiver, Object arg0, Object arg1, Object arg2, Object arg3) {
return functionCall(function, receiver, new Object[]{arg0, arg1, arg2, arg3});
}
public Object functionCall5(Object function, Object receiver, Object arg0, Object arg1, Object arg2, Object arg3, Object arg4) {
return functionCall(function, receiver, new Object[]{arg0, arg1, arg2, arg3, arg4});
}
public Object functionCall6(Object function, Object receiver, Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) {
return functionCall(function, receiver, new Object[]{arg0, arg1, arg2, arg3, arg4, arg5});
}
public Object functionCall7(Object function, Object receiver, Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) {
return functionCall(function, receiver, new Object[]{arg0, arg1, arg2, arg3, arg4, arg5, arg6});
}
public Object functionCall8(Object function, Object receiver, Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) {
return functionCall(function, receiver, new Object[]{arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7});
}
public Object functionCall9(Object function, Object receiver, Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8) {
return functionCall(function, receiver, new Object[]{arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8});
}
private static SourceSection functionGetSourceSection(Object function) {
if (JSFunction.isJSFunction(function)) {
CallTarget callTarget = JSFunction.getCallTarget((DynamicObject) function);
if (callTarget instanceof RootCallTarget) {
RootNode rootNode = ((RootCallTarget) callTarget).getRootNode();
return rootNode.getSourceSection();
}
}
return null;
}
public Object functionResourceName(Object function) {
SourceSection sourceSection = functionGetSourceSection(function);
if (sourceSection == null) {
return null;
} else {
Source source = sourceSection.getSource();
return source.getName();
}
}
public int functionGetScriptLineNumber(Object function) {
SourceSection sourceSection = functionGetSourceSection(function);
if (sourceSection == null) {
return -1;
} else {
return sourceSection.getStartLine() - 1;
}
}
public int functionGetScriptColumnNumber(Object function) {
SourceSection sourceSection = functionGetSourceSection(function);
if (sourceSection == null) {
return -1;
} else {
String code = sourceSection.getCharacters().toString();
int idx = code.indexOf('(');
int delta = (idx == -1) ? 0 : idx;
return sourceSection.getStartColumn() + delta - 1;
}
}
public Object exceptionError(Object context, Object object) {
return exceptionCreate((JSRealm) context, JSErrorType.Error, object);
}
public Object exceptionTypeError(Object context, Object object) {
return exceptionCreate((JSRealm) context, JSErrorType.TypeError, object);
}
public Object exceptionSyntaxError(Object context, Object object) {
return exceptionCreate((JSRealm) context, JSErrorType.SyntaxError, object);
}
public Object exceptionRangeError(Object context, Object object) {
return exceptionCreate((JSRealm) context, JSErrorType.RangeError, object);
}
public Object exceptionReferenceError(Object context, Object object) {
return exceptionCreate((JSRealm) context, JSErrorType.ReferenceError, object);
}
private Object exceptionCreate(JSRealm realm, JSErrorType errorType, Object message) {
DynamicObject error = JSError.create(errorType, realm, message);
assert JSError.getException(error) != null;
return error;
}
public Object exceptionCreateMessage(Object exceptionObject) {
return exceptionObjectToException(exceptionObject);
}
private GraalJSException exceptionObjectToException(Object exceptionObject) {
if (JSDynamicObject.isJSDynamicObject(exceptionObject)) {
GraalJSException exception = JSError.getException((DynamicObject) exceptionObject);
if (exception != null) {
return exception;
}
}
return UserScriptException.create(exceptionObject);
}
public void isolateThrowException(Object exceptionObject) {
throw exceptionObjectToException(exceptionObject);
}
public void templateSet(Object templateObj, Object name, Object value, int attributes) {
ObjectTemplate template;
if (templateObj instanceof FunctionTemplate) {
template = ((FunctionTemplate) templateObj).getFunctionObjectTemplate();
} else {
template = (ObjectTemplate) templateObj;
}
template.addValue(new Value(name, value, propertyAttributes(attributes)));
}
public void templateSetAccessorProperty(Object templateObj, Object name, Object getter, Object setter, int attributes) {
templateSet(templateObj, name, new Pair<>(getter, setter), attributes);
}
public Object functionTemplateNew(int id, long pointer, Object additionalData, Object signature, int length, boolean isConstructor, boolean singleFunctionTemplate) {
FunctionTemplate template = new FunctionTemplate(id, pointer, additionalData, (FunctionTemplate) signature, length, isConstructor, singleFunctionTemplate);
template.getInstanceTemplate().setParentFunctionTemplate(template);
return template;
}
public void functionTemplateSetCallHandler(Object templateObj, long funcPointer, Object additionalData) {
FunctionTemplate functionTemplate = (FunctionTemplate) templateObj;
functionTemplate.setFunctionPointer(funcPointer);
functionTemplate.setAdditionalData(additionalData);
}
public void functionTemplateInherit(Object templateObj, Object parent) {
FunctionTemplate functionTemplate = (FunctionTemplate) templateObj;
functionTemplate.setParent((FunctionTemplate) parent);
}
public void functionTemplateSetClassName(Object templateObj, Object name) {
FunctionTemplate functionTemplate = (FunctionTemplate) templateObj;
functionTemplate.setClassName((String) name);
ObjectTemplate instanceTemplate = functionTemplate.getInstanceTemplate();
instanceTemplate.addValue(new Value(Symbol.SYMBOL_TO_STRING_TAG, name, JSAttributes.configurableNotEnumerableNotWritable()));
}
public Object functionTemplateInstanceTemplate(Object templateObj) {
FunctionTemplate functionTemplate = (FunctionTemplate) templateObj;
return functionTemplate.getInstanceTemplate();
}
public Object functionTemplatePrototypeTemplate(Object templateObj) {
FunctionTemplate functionTemplate = (FunctionTemplate) templateObj;
return functionTemplate.getPrototypeTemplate();
}
public Object functionTemplateGetFunction(Object realm, Object templateObj) {
JSRealm jsRealm = (JSRealm) realm;
JSContext jsContext = jsRealm.getContext();
FunctionTemplate template = (FunctionTemplate) templateObj;
if (template.getFunctionObject(jsRealm) == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
DynamicObject obj = functionTemplateCreateCallback(jsContext, jsRealm, template);
objectTemplateInstantiate(jsRealm, template.getFunctionObjectTemplate(), obj);
ObjectTemplate prototypeTemplate = template.getPrototypeTemplate();
if (prototypeTemplate != null) {
DynamicObject proto = JSOrdinary.create(jsContext, jsRealm);
objectTemplateInstantiate(jsRealm, prototypeTemplate, proto);
JSObjectUtil.putConstructorProperty(jsContext, proto, obj);
JSObject.set(obj, JSObject.PROTOTYPE, proto);
FunctionTemplate parentTemplate = template.getParent();
if (parentTemplate != null) {
DynamicObject parentFunction = (DynamicObject) functionTemplateGetFunction(realm, parentTemplate);
DynamicObject parentProto = (DynamicObject) JSObject.get(parentFunction, JSObject.PROTOTYPE);
JSObject.setPrototype(proto, parentProto);
}
}
}
return template.getFunctionObject(jsRealm);
}
private DynamicObject functionTemplateCreateCallback(JSContext context, JSRealm realm, FunctionTemplate template) {
CompilerAsserts.neverPartOfCompilation("do not create function template in compiled code");
JSFunctionData functionData = JSFunctionData.create(context, template.getLength(), template.getClassName(), template.getPrototypeTemplate() != null, false, false, false);
CallTarget callTarget = Truffle.getRuntime().createCallTarget(new ExecuteNativeFunctionNode.NativeFunctionRootNode(this, context, template, false, false));
CallTarget newCallTarget = Truffle.getRuntime().createCallTarget(new ExecuteNativeFunctionNode.NativeFunctionRootNode(this, context, template, true, false));
CallTarget newTargetCallTarget = Truffle.getRuntime().createCallTarget(new ExecuteNativeFunctionNode.NativeFunctionRootNode(this, context, template, true, true));
CallTarget constructTarget = Truffle.getRuntime().createCallTarget(ConstructorRootNode.create(functionData, newCallTarget, false));
CallTarget constructNewTarget = Truffle.getRuntime().createCallTarget(ConstructorRootNode.create(functionData, newTargetCallTarget, true));
functionData.setCallTarget(callTarget);
functionData.setConstructTarget(constructTarget);
functionData.setConstructNewTarget(constructNewTarget);
DynamicObject functionObject = JSFunction.create(realm, functionData);
template.setFunctionObject(realm, functionObject);
JSObjectUtil.putHiddenProperty(functionObject, FUNCTION_TEMPLATE_DATA_KEY, template.getAdditionalData());
return functionObject;
}
public boolean functionTemplateHasInstance(Object functionTemplate, Object instance) {
if (instance instanceof DynamicObject) {
Object constructor = JSObjectUtil.getHiddenProperty((DynamicObject) instance, FunctionTemplate.CONSTRUCTOR);
if (!(constructor instanceof FunctionTemplate)) {
return false;
}
FunctionTemplate instanceTemplate = (FunctionTemplate) constructor;
while (instanceTemplate != null) {
if (instanceTemplate == functionTemplate) {
return true;
} else {
instanceTemplate = instanceTemplate.getParent();
}
}
}
return false;
}
public Object objectTemplateNew() {
return new ObjectTemplate();
}
@CompilerDirectives.TruffleBoundary
public Object objectTemplateNewInstance(Object realm, Object templateObj) {
JSRealm jsRealm = (JSRealm) realm;
JSContext jsContext = jsRealm.getContext();
ObjectTemplate template = (ObjectTemplate) templateObj;
FunctionTemplate functionHandler = template.getFunctionHandler();
DynamicObject instance;
if (functionHandler == null) {
FunctionTemplate parentFunctionTemplate = template.getParentFunctionTemplate();
if (parentFunctionTemplate == null) {
instance = JSOrdinary.create(jsContext, jsRealm);
} else {
DynamicObject function = (DynamicObject) functionTemplateGetFunction(realm, parentFunctionTemplate);
DynamicObject prototype = (DynamicObject) JSObject.get(function, JSObject.PROTOTYPE);
instance = JSOrdinary.createWithPrototype(prototype, jsContext);
JSObjectUtil.putHiddenProperty(instance, FunctionTemplate.CONSTRUCTOR, parentFunctionTemplate);
}
} else {
instance = functionTemplateCreateCallback(jsContext, jsRealm, functionHandler);
}
objectTemplateInstantiate(jsRealm, templateObj, instance);
if (template.hasPropertyHandler()) {
instance = propertyHandlerInstantiate(jsContext, jsRealm, template, instance, false);
}
return instance;
}
@CompilerDirectives.TruffleBoundary
public DynamicObject propertyHandlerInstantiate(JSContext context, JSRealm realm, ObjectTemplate template, DynamicObject target, boolean global) {
DynamicObject handler = JSOrdinary.create(context, realm);
DynamicObject proxy = JSProxy.create(context, target, handler);
DynamicObject getter = functionFromRootNode(context, realm, new ExecuteNativePropertyHandlerNode(
this,
context,
template,
proxy,
ExecuteNativePropertyHandlerNode.Mode.GETTER), proxy);
JSObject.set(handler, JSProxy.GET, getter);
DynamicObject setter = functionFromRootNode(context, realm, new ExecuteNativePropertyHandlerNode(
this,
context,
template,
proxy,
ExecuteNativePropertyHandlerNode.Mode.SETTER), proxy);
JSObject.set(handler, JSProxy.SET, setter);
DynamicObject query = functionFromRootNode(context, realm, new ExecuteNativePropertyHandlerNode(
this,
context,
template,
proxy,
ExecuteNativePropertyHandlerNode.Mode.QUERY), proxy);
JSObject.set(handler, JSProxy.HAS, query);
DynamicObject deleter = functionFromRootNode(context, realm, new ExecuteNativePropertyHandlerNode(
this,
context,
template,
proxy,
ExecuteNativePropertyHandlerNode.Mode.DELETER), proxy);
JSObject.set(handler, JSProxy.DELETE_PROPERTY, deleter);
DynamicObject ownKeys = functionFromRootNode(context, realm, new ExecuteNativePropertyHandlerNode(
this,
context,
template,
proxy,
ExecuteNativePropertyHandlerNode.Mode.OWN_KEYS), proxy);
JSObject.set(handler, JSProxy.OWN_KEYS, ownKeys);
DynamicObject getOwnPropertyDescriptor = functionFromRootNode(context, realm, new ExecuteNativePropertyHandlerNode(
this,
context,
template,
proxy,
ExecuteNativePropertyHandlerNode.Mode.GET_OWN_PROPERTY_DESCRIPTOR), proxy);
JSObject.set(handler, JSProxy.GET_OWN_PROPERTY_DESCRIPTOR, getOwnPropertyDescriptor);
DynamicObject defineProperty = functionFromRootNode(context, realm, new ExecuteNativePropertyHandlerNode(
this,
context,
template,
proxy,
ExecuteNativePropertyHandlerNode.Mode.DEFINE_PROPERTY), proxy);
JSObject.set(handler, JSProxy.DEFINE_PROPERTY, defineProperty);
DynamicObject getPrototypeOf = functionFromRootNode(context, realm, new PropertyHandlerPrototypeNode(global), null);
JSObject.set(handler, JSProxy.GET_PROTOTYPE_OF, getPrototypeOf);
for (Value value : template.getValues()) {
Object name = value.getName();
if (name instanceof HiddenKey) {
JSObjectUtil.putHiddenProperty(proxy, name, value.getValue());
}
}
return proxy;
}
@CompilerDirectives.TruffleBoundary
public void objectTemplateInstantiate(JSRealm realm, Object templateObj, Object targetObject) {
JSContext context = realm.getContext();
ObjectTemplate template = (ObjectTemplate) templateObj;
DynamicObject obj = (DynamicObject) targetObject;
for (Accessor accessor : template.getAccessors()) {
Pair<JSFunctionData, JSFunctionData> accessorFunctions = accessor.getFunctions(context);
DynamicObject getter = functionFromFunctionData(realm, accessorFunctions.getFirst(), obj);
DynamicObject setter = functionFromFunctionData(realm, accessorFunctions.getSecond(), obj);
JSObjectUtil.putAccessorProperty(context, obj, accessor.getName(), getter, setter, accessor.getAttributes());
}
for (Value value : template.getValues()) {
Object name = value.getName();
Object processedValue = value.getValue();
int attributes = value.getAttributes();
if (processedValue instanceof FunctionTemplate) {
FunctionTemplate functionTempl = (FunctionTemplate) processedValue;
processedValue = functionTemplateGetFunction(realm, functionTempl);
}
if (processedValue instanceof Pair) {
Pair<?, ?> pair = (Pair<?, ?>) processedValue;
Object getterTemplate = pair.getFirst();
Object setterTemplate = pair.getSecond();
Object getter = (getterTemplate == null) ? Undefined.instance : functionTemplateGetFunction(realm, getterTemplate);
Object setter = (setterTemplate == null) ? Undefined.instance : functionTemplateGetFunction(realm, setterTemplate);
JSObjectUtil.putAccessorProperty(context, obj, name, (DynamicObject) getter, (DynamicObject) setter, attributes);
} else {
if (name instanceof HiddenKey) {
if (!template.hasPropertyHandler()) {
JSObjectUtil.putHiddenProperty(obj, name, processedValue);
}
} else if (JSObject.hasOwnProperty(obj, name)) {
JSObject.set(obj, name, processedValue);
} else {
JSObjectUtil.putDataProperty(context, obj, name, processedValue, attributes);
}
}
}
}
public void objectTemplateSetAccessor(Object templateObj, Object name, long getterPtr, long setterPtr, Object data, Object signature, int attributes) {
ObjectTemplate template = (ObjectTemplate) templateObj;
template.addAccessor(new Accessor(this, name, getterPtr, setterPtr, data, (FunctionTemplate) signature, propertyAttributes(attributes)));
}
public void objectTemplateSetHandler(Object templateObj, long getter, long setter, long query, long deleter, long enumerator, long definer, long descriptor, Object data, boolean named,
boolean stringKeysOnly) {
ObjectTemplate template = (ObjectTemplate) templateObj;
PropertyHandler handler = new PropertyHandler(getter, setter, query, deleter, enumerator, definer, descriptor, data);
if (named) {
template.setNamedPropertyHandler(handler, stringKeysOnly);
} else {
template.setIndexedPropertyHandler(handler);
}
}
public void objectTemplateSetCallAsFunctionHandler(Object templateObj, int id, long functionPointer, Object additionalData) {
ObjectTemplate template = (ObjectTemplate) templateObj;
FunctionTemplate functionHandler = (FunctionTemplate) functionTemplateNew(id, functionPointer, additionalData, null, 0, true, false);
template.setFunctionHandler(functionHandler);
}
public Object scriptCompilerCompileFunctionInContext(Object context, String sourceName, String body, Object[] arguments, Object[] exts, Object hostDefinedOptions) {
if (VERBOSE) {
System.err.println("FUNCTION IN CONTEXT: " + sourceName);
}
JSRealm realm = (JSRealm) context;
JSContext jsContext = realm.getContext();
Evaluator nodeEvaluator = jsContext.getEvaluator();
Object extraArgument = getExtraArgumentOfInternalScript(sourceName, jsContext);
Object[] extensions;
ByteBuffer snapshot = null;
if (extraArgument == null) {
extensions = exts;
if (USE_SNAPSHOTS && hostDefinedOptions == null) {
assert exts.length == 0 && UnboundScript.isCoreModule(sourceName);
snapshot = getCoreModuleBinarySnapshot(sourceName);
}
} else {
assert exts.length == 0;
DynamicObject graalExtension = JSOrdinary.create(jsContext);
JSObject.set(graalExtension, "graalExtension", extraArgument);
extensions = new Object[]{graalExtension};
}
StringBuilder params = new StringBuilder();
for (int i = 0; i < arguments.length; i++) {
if (i != 0) {
params.append(", ");
}
params.append(arguments[i]);
}
String parameterList = params.toString();
try {
GraalJSParserHelper.checkFunctionSyntax(jsContext, jsContext.getParserOptions(), parameterList, body, false, false, sourceName);
} catch (com.oracle.js.parser.ParserException ex) {
nodeEvaluator.parseFunction(jsContext, parameterList, body, false, false, sourceName);
}
StringBuilder code = new StringBuilder();
boolean anyExtension = extensions.length > 0;
if (anyExtension) {
code.append("(function () {");
for (int i = 0; i < extensions.length; i++) {
code.append("with (arguments[").append(i).append("]) {");
}
code.append("return ");
}
code.append("(function (");
code.append(parameterList);
code.append(") {");
if (body.startsWith("#!")) {
code.append("//");
}
String prefix = code.toString();
code = new StringBuilder();
code.append("\n});");
if (anyExtension) {
for (int i = 0; i < extensions.length; i++) {
code.append("}");
}
code.append(";})");
}
String suffix = code.toString();
Source source = null;
if (hostDefinedOptions == null) {
source = Source.newBuilder(JavaScriptLanguage.ID, body, sourceName).internal(isBootstrapSource(sourceName)).build();
} else {
if (!sourceName.isEmpty()) {
try {
TruffleFile truffleFile = realm.getEnv().getPublicTruffleFile(sourceName);
source = Source.newBuilder(JavaScriptLanguage.ID, truffleFile).content(body).name(sourceName).build();
} catch (InvalidPathException e) {
if (VERBOSE) {
System.err.println("INVALID PATH: " + sourceName);
}
}
}
if (source == null) {
source = Source.newBuilder(JavaScriptLanguage.ID, body, sourceName).build();
}
hostDefinedOptionsMap.put(source, hostDefinedOptions);
}
Object function;
if (snapshot == null) {
ScriptNode scriptNode = nodeEvaluator.parseScript(jsContext, source, prefix, suffix);
DynamicObject fn = (DynamicObject) scriptNode.run(realm);
function = anyExtension ? JSFunction.call(fn, Undefined.instance, extensions) : fn;
} else {
ScriptNode scriptNode = parseScriptFromSnapshot(jsContext, source, prefix, suffix, snapshot);
function = scriptNode.run(realm);
}
assert JSFunction.isJSFunction(function);
NodeScriptOrModule scriptOrModule = new NodeScriptOrModule(jsContext, source);
JSObjectUtil.putHiddenProperty((DynamicObject) function, NodeScriptOrModule.SCRIPT_OR_MODULE, scriptOrModule);
return new Object[]{function, scriptOrModule};
}
private static boolean isBootstrapSource(String sourceName) {
return sourceName.startsWith("internal/per_context") || sourceName.startsWith("internal/bootstrap");
}
public Object scriptCompile(Object context, Object sourceCode, Object fileName, Object hostDefinedOptions) {
UnboundScript unboundScript = (UnboundScript) unboundScriptCompile(sourceCode, fileName, hostDefinedOptions);
return unboundScriptBindToContext(context, unboundScript);
}
@CompilerDirectives.TruffleBoundary
public Object scriptRun(Object script) {
Script boundScript = (Script) script;
ScriptNode scriptNode = boundScript.getScriptNode();
if (VERBOSE) {
Source source = scriptNode.getRootNode().getSourceSection().getSource();
System.err.println("EXECUTING: " + source.getName());
}
JSRealm realm = boundScript.getRealm();
Object[] arguments = scriptNode.argumentsToRun(realm);
Object prev = realm.getTruffleContext().enter(null);
try {
Object result;
if (boundScript.isGraalInternal()) {
result = scriptRunInternal(scriptNode, arguments);
} else {
result = scriptNode.run(arguments);
}
return result;
} finally {
realm.getTruffleContext().leave(null, prev);
}
}
private Object scriptRunInternal(ScriptNode scriptNode, Object[] arguments) {
JSContext context = scriptNode.getContext();
JSRealm realm = context.getRealm();
final DynamicObject moduleFunction = (DynamicObject) scriptNode.run(arguments);
JavaScriptRootNode wrapperNode = new JavaScriptRootNode() {
@Override
public Object execute(VirtualFrame frame) {
Object[] args = frame.getArguments();
DynamicObject thisObject = (DynamicObject) JSArguments.getThisObject(args);
Object result = JSFunction.call(moduleFunction, thisObject, getInternalModuleUserArguments(args, scriptNode));
return result;
}
};
JSFunctionData functionData = JSFunctionData.createCallOnly(context, Truffle.getRuntime().createCallTarget(wrapperNode), 5, "");
return JSFunction.create(realm, functionData);
}
private Object (String moduleName, JSContext context) {
Object extraArgument = null;
if (NIO_BUFFER_MODULE_NAME.equals(moduleName)) {
extraArgument = USE_NIO_BUFFER ? NIOBuffer.createInitFunction(context) : Null.instance;
} else if ("internal/graal/debug.js".equals(moduleName)) {
CallTarget setBreakPointCallTarget = Truffle.getRuntime().createCallTarget(new SetBreakPointNode(this));
JSFunctionData setBreakPointData = JSFunctionData.createCallOnly(context, setBreakPointCallTarget, 3, SetBreakPointNode.NAME);
DynamicObject setBreakPoint = JSFunction.create(context.getRealm(), setBreakPointData);
extraArgument = setBreakPoint;
} else if ("internal/worker/io.js".equals(moduleName) || "internal/main/worker_thread.js".equals(moduleName)) {
extraArgument = SharedMemMessagingBindings.createInitFunction(this, context);
} else if ("inspector.js".equals(moduleName)) {
TruffleObject inspector = lookupInstrument("inspect", TruffleObject.class);
extraArgument = (inspector == null) ? Null.instance : inspector;
}
return extraArgument;
}
@TruffleBoundary
private Object[] getInternalModuleUserArguments(Object[] args, ScriptNode node) {
Object[] userArgs = JSArguments.extractUserArguments(args);
String moduleName = node.getRootNode().getSourceSection().getSource().getName();
Object extraArgument = getExtraArgumentOfInternalScript(moduleName, node.getContext());
if (extraArgument == null) {
return userArgs;
}
Object[] extendedArgs = new Object[userArgs.length + 1];
System.arraycopy(userArgs, 0, extendedArgs, 0, userArgs.length);
extendedArgs[userArgs.length] = extraArgument;
return extendedArgs;
}
public Object scriptGetUnboundScript(Object script) {
return new UnboundScript((Script) script);
}
private static FunctionNode parseSource(Source source, JSContext context) {
ContextData contextData = (ContextData) context.getEmbedderData();
String content = source.getCharacters().toString();
FunctionNode parseResult = contextData.getFunctionNodeCache().get(content);
if (parseResult == null) {
parseResult = GraalJSParserHelper.parseScript(context, source, context.getParserOptions());
contextData.getFunctionNodeCache().put(content, parseResult);
}
return parseResult;
}
public Object unboundScriptCompile(Object sourceCode, Object fileName, Object hostDefinedOptions) {
String sourceCodeStr = (String) sourceCode;
String fileNameStr = (String) fileName;
Source source = UnboundScript.createSource(internSourceCode(sourceCodeStr), fileNameStr);
hostDefinedOptionsMap.put(source, hostDefinedOptions);
if (USE_SNAPSHOTS && fileNameStr != null && UnboundScript.isCoreModule(fileNameStr)) {
ByteBuffer snapshotBinary = getCoreModuleBinarySnapshot(fileNameStr);
if (snapshotBinary != null) {
return new UnboundScript(source, snapshotBinary);
}
}
FunctionNode functionNode = parseSource(source, mainJSContext);
return new UnboundScript(source, functionNode);
}
private static ByteBuffer getCoreModuleBinarySnapshot(String modulePath) {
ByteBuffer snapshotBinary = NativeAccess.getCoreModuleBinarySnapshot(modulePath);
if (VERBOSE) {
if (snapshotBinary == null) {
System.err.printf("no snapshot for %s\n", modulePath);
} else {
System.err.printf("successfully read snapshot for %s\n", modulePath);
}
}
return snapshotBinary;
}
public Object unboundScriptBindToContext(Object context, Object script) {
JSRealm jsRealm = (JSRealm) context;
JSContext jsContext = jsRealm.getContext();
UnboundScript unboundScript = (UnboundScript) script;
Source source = unboundScript.getSource();
Object parseResult = unboundScript.getParseResult();
ScriptNode scriptNode;
if (parseResult instanceof FunctionNode) {
ContextData contextData = (ContextData) jsContext.getEmbedderData();
scriptNode = contextData.getScriptNodeCache().get(source);
if (scriptNode == null) {
JSParserOptions options = jsContext.getParserOptions();
NodeFactory factory = NodeFactory.getInstance(jsContext);
Object prev = jsRealm.getTruffleContext().enter(null);
try {
scriptNode = JavaScriptTranslator.translateFunction(factory, jsContext, null, source, options.isStrict(), (FunctionNode) parseResult);
} finally {
jsRealm.getTruffleContext().leave(null, prev);
}
if (!"repl".equals(source.getName())) {
contextData.getScriptNodeCache().put(source, scriptNode);
}
}
} else {
scriptNode = parseScriptFromSnapshot(jsContext, source, "", "", (ByteBuffer) parseResult);
}
return new Script(scriptNode, parseResult, jsRealm, unboundScript.getId());
}
public String unboundScriptGetContent(Object script) {
return ((UnboundScript) script).getSource().getCharacters().toString();
}
private String internSourceCode(String sourceCode) {
Reference<String> cacheEntry = sourceCodeCache.get(sourceCode);
String entry = null;
if (cacheEntry == null || (entry = cacheEntry.get()) == null) {
sourceCodeCache.put(sourceCode, new WeakReference<>(sourceCode));
return sourceCode;
}
return entry;
}
private ScriptNode parseScriptFromSnapshot(JSContext context, Source source, String prefix, String suffix, ByteBuffer snapshotBinary) {
JSParser parser = (JSParser) context.getEvaluator();
try {
return parser.parseScript(context, source, snapshotBinary);
} catch (IllegalArgumentException e) {
if (VERBOSE) {
String moduleName = source.getName();
System.err.printf("error when parsing binary snapshot for %s: %s\n", moduleName, e);
System.err.printf("falling back to parsing %s at runtime\n", moduleName);
}
return parser.parseScript(context, source, prefix, suffix);
}
}
public int unboundScriptGetId(Object script) {
return ((UnboundScript) script).getId();
}
public Object contextGlobal(Object realm) {
return ((JSRealm) realm).getGlobalObject();
}
private static int propertyAttributes(int attributes) {
int flags = 0;
if ((attributes & 1 ) != 0) {
flags |= JSAttributes.NOT_WRITABLE;
}
if ((attributes & 2 ) != 0) {
flags |= JSAttributes.NOT_ENUMERABLE;
}
if ((attributes & 4 ) != 0) {
flags |= JSAttributes.NOT_CONFIGURABLE;
}
return flags;
}
public static PropertyDescriptor propertyDescriptor(int v8Attributes, Object value) {
boolean writable = ((v8Attributes & 1 ) == 0);
boolean enumerable = ((v8Attributes & 2 ) == 0);
boolean configurable = ((v8Attributes & 4 ) == 0);
return PropertyDescriptor.createData(value, enumerable, writable, configurable);
}
private static DynamicObject functionFromRootNode(JSContext context, JSRealm realm, JavaScriptRootNode rootNode, Object holder) {
return functionFromFunctionData(realm, functionDataFromRootNode(context, rootNode), holder);
}
public static JSFunctionData functionDataFromRootNode(JSContext context, JavaScriptRootNode rootNode) {
CallTarget callbackCallTarget = Truffle.getRuntime().createCallTarget(rootNode);
return JSFunctionData.create(context, callbackCallTarget, callbackCallTarget, 0, "", false, false, false, true);
}
private static DynamicObject functionFromFunctionData(JSRealm realm, JSFunctionData functionData, Object holder) {
if (functionData == null) {
return null;
}
DynamicObject function = JSFunction.create(realm, functionData);
if (holder != null) {
JSObjectUtil.putHiddenProperty(function, HOLDER_KEY, holder);
}
JSObject.preventExtensions(function);
return function;
}
@CompilerDirectives.TruffleBoundary
public Object tryCatchException(Object context, Object exception) {
Throwable throwable = (Throwable) exception;
if (exception instanceof ExitException) {
int exitCode = ((ExitException) exception).getStatus();
exit(exitCode);
} else if (throwable instanceof OutOfMemoryError) {
throwable.printStackTrace();
exit(1);
}
JSRealm jsRealm = (JSRealm) context;
JSContext jsContext = jsRealm.getContext();
if (!(throwable instanceof GraalJSException)) {
isolateInternalErrorCheck(throwable);
throwable = JSException.create(JSErrorType.Error, throwable.getMessage(), throwable, null);
}
GraalJSException truffleException = (GraalJSException) throwable;
Object exceptionObject = truffleException.getErrorObjectEager(jsContext);
if (JSRuntime.isObject(exceptionObject) && JSError.getException((DynamicObject) exceptionObject) == null) {
JSObjectUtil.putHiddenProperty((DynamicObject) exceptionObject, JSError.EXCEPTION_PROPERTY_NAME, truffleException);
}
Matcher matcher = messageSyntaxErrorMatcher(exception);
if (matcher != null) {
String stack = JSRuntime.toString(JSObject.get((DynamicObject) exceptionObject, JSError.STACK_NAME));
if (stack.startsWith(truffleException.getMessage())) {
String message = matcher.group(SYNTAX_ERROR_MESSAGE_GROUP);
stack = "SyntaxError: " + message + stack.substring(truffleException.getMessage().length());
JSObject.set((DynamicObject) exceptionObject, JSError.STACK_NAME, stack);
}
}
return exceptionObject;
}
@SuppressWarnings("deprecation")
public boolean tryCatchHasTerminated(Object exception) {
return (exception instanceof GraalJSKillException) || (exception instanceof com.oracle.truffle.api.TruffleException && ((com.oracle.truffle.api.TruffleException) exception).isCancelled());
}
private static GraalJSException.JSStackTraceElement messageGraalJSExceptionStackFrame(Object exception) {
if (exception instanceof GraalJSException) {
GraalJSException truffleException = (GraalJSException) exception;
GraalJSException.JSStackTraceElement[] stackTrace = truffleException.getJSStackTrace();
GraalJSException.JSStackTraceElement stackFrame;
int index = 0;
do {
if (index == stackTrace.length) {
stackFrame = null;
break;
} else {
stackFrame = stackTrace[index++];
}
} while (JSFunction.BUILTIN_SOURCE_NAME.equals(stackFrame.getFileName()));
return stackFrame;
}
return null;
}
private static final Pattern SYNTAX_ERROR_PATTERN = Pattern.compile("(.+):(\\d+):(\\d+) ([^\r\n]+)\r?\n([^\r\n]+)(?:\r?\n(?:.|(?:\r?\n))*)?");
private static final int SYNTAX_ERROR_RESOURCE_NAME_GROUP = 1;
private static final int SYNTAX_ERROR_LINE_NUMBER_GROUP = 2;
private static final int SYNTAX_ERROR_COLUMN_NUMBER_GROUP = 3;
private static final int SYNTAX_ERROR_MESSAGE_GROUP = 4;
private static final int SYNTAX_ERROR_SOURCE_LINE_GROUP = 5;
private static Matcher messageSyntaxErrorMatcher(Object exception) {
if (exception instanceof JSException) {
JSException jsException = (JSException) exception;
if (jsException.getErrorType() == JSErrorType.SyntaxError) {
String message = jsException.getRawMessage();
Matcher matcher = SYNTAX_ERROR_PATTERN.matcher(message);
if (matcher.matches()) {
return matcher;
}
}
}
return null;
}
private static String messageSyntaxErrorResourceName(Object exception) {
Matcher matcher = messageSyntaxErrorMatcher(exception);
if (matcher != null) {
return matcher.group(SYNTAX_ERROR_RESOURCE_NAME_GROUP);
}
return null;
}
private static int messageSyntaxErrorLineNumber(Object exception) {
Matcher matcher = messageSyntaxErrorMatcher(exception);
if (matcher != null) {
String lineNumber = matcher.group(SYNTAX_ERROR_LINE_NUMBER_GROUP);
return Integer.parseInt(lineNumber);
}
return -1;
}
private static int messageSyntaxErrorColumnNumber(Object exception) {
Matcher matcher = messageSyntaxErrorMatcher(exception);
if (matcher != null) {
String columnNumber = matcher.group(SYNTAX_ERROR_COLUMN_NUMBER_GROUP);
return Integer.parseInt(columnNumber);
}
return -1;
}
private static String messageSyntaxErrorSourceLine(Object exception) {
Matcher matcher = messageSyntaxErrorMatcher(exception);
if (matcher != null) {
return matcher.group(SYNTAX_ERROR_SOURCE_LINE_GROUP);
}
return null;
}
public Object messageGetScriptResourceName(Object exception) {
String resourceName = messageSyntaxErrorResourceName(exception);
if (resourceName != null) {
return resourceName;
}
GraalJSException.JSStackTraceElement stackFrame = messageGraalJSExceptionStackFrame(exception);
if (stackFrame != null) {
return stackFrame.getFileName();
}
return "unknown";
}
public int messageGetLineNumber(Object exception) {
int lineNumber = messageSyntaxErrorLineNumber(exception);
if (lineNumber != -1) {
return lineNumber;
}
GraalJSException.JSStackTraceElement stackFrame = messageGraalJSExceptionStackFrame(exception);
if (stackFrame != null) {
return stackFrame.getLineNumber();
}
return 0;
}
public int messageGetStartColumn(Object exception) {
int columnNumber = messageSyntaxErrorColumnNumber(exception);
if (columnNumber != -1) {
return columnNumber;
}
GraalJSException.JSStackTraceElement stackFrame = messageGraalJSExceptionStackFrame(exception);
if (stackFrame != null) {
return stackFrame.getColumnNumber() - 1;
}
return 0;
}
public Object messageGetSourceLine(Object exception) {
String sourceLine = messageSyntaxErrorSourceLine(exception);
if (sourceLine != null) {
return sourceLine;
}
GraalJSException.JSStackTraceElement stackFrame = messageGraalJSExceptionStackFrame(exception);
if (stackFrame != null) {
return stackFrame.getLine();
}
return "unknown";
}
public Object messageGetStackTrace(Object exception) {
if (exception instanceof GraalJSException) {
GraalJSException truffleException = (GraalJSException) exception;
return truffleException.getJSStackTrace();
}
return new GraalJSException.JSStackTraceElement[0];
}
public Object messageGet(Object exception) {
return "Uncaught " + ((Throwable) exception).getMessage();
}
public Object stackTraceCurrentStackTrace() {
return GraalJSException.getJSStackTrace(null);
}
public int stackFrameGetLineNumber(Object stackFrame) {
GraalJSException.JSStackTraceElement element = (GraalJSException.JSStackTraceElement) stackFrame;
return element.getLineNumber();
}
public int stackFrameGetColumn(Object stackFrame) {
GraalJSException.JSStackTraceElement element = (GraalJSException.JSStackTraceElement) stackFrame;
return element.getColumnNumber();
}
public Object stackFrameGetScriptName(Object stackFrame) {
GraalJSException.JSStackTraceElement element = (GraalJSException.JSStackTraceElement) stackFrame;
return element.getFileName();
}
public Object stackFrameGetFunctionName(Object stackFrame) {
GraalJSException.JSStackTraceElement element = (GraalJSException.JSStackTraceElement) stackFrame;
return element.getFunctionName();
}
public boolean stackFrameIsEval(Object stackFrame) {
GraalJSException.JSStackTraceElement element = (GraalJSException.JSStackTraceElement) stackFrame;
return element.isEval();
}
private static final HiddenKey HIDDEN_WEAK_CALLBACK = new HiddenKey("WeakCallback");
private static final HiddenKey HIDDEN_WEAK_CALLBACK_CONTEXT = new HiddenKey("WeakCallbackContext");
private final ReferenceQueue<Object> weakCallbackQueue = new ReferenceQueue<>();
private final Set<WeakCallback> weakCallbacks = new HashSet<>();
@SuppressWarnings("unchecked")
private WeakCallback updateWeakCallback(Object object, long reference, long data, long callbackPointer, int type) {
Map<Long, WeakCallback> map;
if (object instanceof NodeScriptOrModule) {
map = ((NodeScriptOrModule) object).getWeakCallbackMap();
} else {
DynamicObject target;
HiddenKey key;
if (object instanceof JSRealm) {
target = ((JSRealm) object).getGlobalObject();
key = HIDDEN_WEAK_CALLBACK_CONTEXT;
} else if (object instanceof DynamicObject) {
target = (DynamicObject) object;
key = HIDDEN_WEAK_CALLBACK;
} else {
System.err.println("Weak references not supported for " + object);
return null;
}
map = (Map<Long, WeakCallback>) JSObjectUtil.getHiddenProperty(target, key);
if (map == null) {
map = new HashMap<>();
JSObjectUtil.putHiddenProperty(target, key, map);
}
}
WeakCallback weakCallback = map.get(reference);
if (weakCallback == null) {
weakCallback = new WeakCallback(object, data, callbackPointer, type, weakCallbackQueue);
map.put(reference, weakCallback);
} else {
weakCallback.data = data;
weakCallback.callback = callbackPointer;
weakCallback.type = type;
}
if (callbackPointer == 0) {
weakCallbacks.remove(weakCallback);
} else {
weakCallbacks.add(weakCallback);
}
return weakCallback;
}
private void pollWeakCallbackQueue(boolean canBlock) {
WeakCallback callback;
if (canBlock) {
try {
callback = (WeakCallback) weakCallbackQueue.remove(10);
if (callback != null) {
processWeakCallback(callback);
}
} catch (InterruptedException iex) {
}
}
while ((callback = (WeakCallback) weakCallbackQueue.poll()) != null) {
processWeakCallback(callback);
}
}
private void processWeakCallback(WeakCallback callback) {
weakCallbacks.remove(callback);
if (callback.callback != 0) {
NativeAccess.weakCallback(callback.callback, callback.data, callback.type);
}
}
public void makeWeak(Object object, long reference, long data, long callbackPointer, int type) {
if (object == null) {
System.err.println("null object given to makeWeak!");
return;
}
updateWeakCallback(object, reference, data, callbackPointer, type);
pollWeakCallbackQueue(false);
}
public long clearWeak(Object object, long reference) {
if (object == null) {
return 0;
}
WeakCallback callback = updateWeakCallback(object, reference, 0, 0, 0);
return callback.data;
}
@TruffleBoundary
public <T> T lookupInstrument(String instrumentId, Class<T> instrumentClass) {
TruffleLanguage.Env env = envForInstruments;
InstrumentInfo info = env.getInstruments().get(instrumentId);
return (info == null) ? null : env.lookup(info, instrumentClass);
}
private boolean createChildContext;
public Object contextNew(Object templateObj) {
JSRealm realm;
JSContext context;
if (createChildContext) {
realm = mainJSRealm.createChildRealm();
context = realm.getContext();
assert realm.getAgent() == agent;
} else {
realm = mainJSRealm;
context = mainJSContext;
context.setEmbedderData(new ContextData(context));
createChildContext = true;
}
realm.setEmbedderData(new RealmData());
DynamicObject global = realm.getGlobalObject();
JSObject.delete(global, JSRealm.ARGUMENTS_NAME);
if (exposeGC) {
contextExposeGC(realm);
}
if (templateObj != null) {
ObjectTemplate template = (ObjectTemplate) templateObj;
if (template.hasPropertyHandler()) {
global = propertyHandlerInstantiate(context, realm, template, global, true);
realm.setGlobalObject(global);
} else {
DynamicObject prototype = JSOrdinary.create(context);
objectTemplateInstantiate(realm, template, prototype);
JSObject.setPrototype(global, prototype);
}
}
return realm;
}
public static RealmData getRealmEmbedderData(Object realm) {
return (RealmData) ((JSRealm) realm).getEmbedderData();
}
public static ContextData getContextEmbedderData(JSContext context) {
return (ContextData) context.getEmbedderData();
}
private void contextExposeGC(JSRealm realm) {
DynamicObject global = realm.getGlobalObject();
JavaScriptRootNode rootNode = new JavaScriptRootNode() {
@Override
public Object execute(VirtualFrame vf) {
isolatePerformGC();
return Undefined.instance;
}
};
JSFunctionData functionData = JSFunctionData.createCallOnly(realm.getContext(), Truffle.getRuntime().createCallTarget(rootNode), 0, "gc");
DynamicObject function = JSFunction.create(realm, functionData);
JSObject.set(global, "gc", function);
}
@TruffleBoundary
private void isolatePerformGC() {
NativeAccess.notifyGCCallbacks(true);
pollWeakCallbackQueue(true);
for (int i = 0; i < 3; i++) {
System.gc();
pollWeakCallbackQueue(true);
}
NativeAccess.notifyGCCallbacks(false);
}
public void contextSetSecurityToken(Object context, Object securityToken) {
RealmData contextData = getRealmEmbedderData(context);
contextData.setSecurityToken(securityToken);
}
public Object contextGetSecurityToken(Object context) {
RealmData contextData = getRealmEmbedderData(context);
Object securityToken = contextData.getSecurityToken();
return (securityToken == null) ? Undefined.instance : securityToken;
}
public Object (Object context) {
RealmData contextData = getRealmEmbedderData(context);
DynamicObject extras = contextData.getExtrasBindingObject();
if (extras == null) {
extras = initializeExtrasBindingObject((JSRealm) context);
contextData.setExtrasBindingObject(extras);
}
return extras;
}
private DynamicObject (JSRealm realm) {
DynamicObject extras = JSOrdinary.create(realm.getContext(), realm);
JavaScriptRootNode isEnabledRootNode = new JavaScriptRootNode() {
@Override
public Object execute(VirtualFrame vf) {
return false;
}
};
JSFunctionData isEnabledFunctionData = JSFunctionData.createCallOnly(realm.getContext(), Truffle.getRuntime().createCallTarget(isEnabledRootNode), 0, "isTraceCategoryEnabled");
DynamicObject isEnabledFunction = JSFunction.create(realm, isEnabledFunctionData);
JSObject.set(extras, "isTraceCategoryEnabled", isEnabledFunction);
JavaScriptRootNode traceRootNode = new JavaScriptRootNode() {
@Override
public Object execute(VirtualFrame vf) {
return Undefined.instance;
}
};
JSFunctionData traceFunctionData = JSFunctionData.createCallOnly(realm.getContext(), Truffle.getRuntime().createCallTarget(traceRootNode), 0, "trace");
DynamicObject traceFunction = JSFunction.create(realm, traceFunctionData);
JSObject.set(extras, "trace", traceFunction);
return extras;
}
public void contextSetPointerInEmbedderData(Object context, int index, long pointer) {
contextSetEmbedderData(context, index, pointer);
}
public long contextGetPointerInEmbedderData(Object context, int index) {
Long pointer = (Long) contextGetEmbedderData(context, index);
return (pointer == null) ? 0 : pointer;
}
public void contextSetEmbedderData(Object realm, int index, Object value) {
RealmData data = getRealmEmbedderData(realm);
data.setEmbedderData(index, value);
}
public Object contextGetEmbedderData(Object realm, int index) {
RealmData data = getRealmEmbedderData(realm);
return data.getEmbedderData(index);
}
public void isolateRunMicrotasks() {
pollWeakCallbackQueue(false);
try {
agent.processAllPromises(true);
} catch (Exception ex) {
ex.printStackTrace();
System.exit(1);
}
}
public Object isolateCreateInternalFieldCountKey() {
return INTERNAL_FIELD_COUNT_KEY;
}
public Object isolateCreateInternalFieldKey(int index) {
return (index == 0) ? INTERNAL_FIELD_ZERO_KEY : new HiddenKey("InternalField" + index);
}
public int objectInternalFieldCount(Object target) {
return internalFieldCount((DynamicObject) target);
}
public static int internalFieldCount(DynamicObject target) {
Object ret = JSObjectUtil.getHiddenProperty(target, INTERNAL_FIELD_COUNT_KEY);
if (ret instanceof Integer) {
return (int) ret;
} else if (ret instanceof Double) {
return ((Double) ret).intValue();
} else {
return 0;
}
}
public long objectSlowGetAlignedPointerFromInternalField(Object target) {
Object pointer = JSObjectUtil.getHiddenProperty((DynamicObject) target, INTERNAL_FIELD_ZERO_KEY);
return (pointer == null) ? 0 : ((Number) pointer).longValue();
}
public void objectSetAlignedPointerInInternalField(Object target, long value) {
JSObjectUtil.putHiddenProperty((DynamicObject) target, INTERNAL_FIELD_ZERO_KEY, value);
}
public Object objectPreviewEntries(Object object) {
DynamicObject dynamicObject = (DynamicObject) object;
JSContext context = JSObject.getJSContext(dynamicObject);
JSHashMap.Cursor cursor = (JSHashMap.Cursor) JSObjectUtil.getHiddenProperty(dynamicObject, JSRuntime.ITERATOR_NEXT_INDEX);
if (cursor != null) {
Object kindObject = JSObjectUtil.getHiddenProperty(dynamicObject, JSMap.MAP_ITERATION_KIND_ID);
boolean isSet = (kindObject == null);
if (isSet) {
kindObject = JSObjectUtil.getHiddenProperty(dynamicObject, JSSet.SET_ITERATION_KIND_ID);
}
int kind = ((Number) kindObject).intValue();
cursor = cursor.copy();
List<Object> entries = new ArrayList<>();
while (cursor.advance()) {
Object key = cursor.getKey();
Object value = isSet ? key : cursor.getValue();
if (kind == JSRuntime.ITERATION_KIND_KEY) {
entries.add(key);
} else if (kind == JSRuntime.ITERATION_KIND_VALUE) {
entries.add(value);
} else {
entries.add(key);
entries.add(value);
assert kind == JSRuntime.ITERATION_KIND_KEY_PLUS_VALUE;
}
}
resetSharedBuffer();
sharedBuffer.putInt(kind == JSRuntime.ITERATION_KIND_KEY_PLUS_VALUE ? 1 : 0);
return JSArray.createConstantObjectArray(context, entries.toArray());
}
if (JSWeakMap.isJSWeakMap(object) || JSWeakSet.isJSWeakSet(object)) {
resetSharedBuffer();
sharedBuffer.putInt(0);
return JSArray.createConstantEmptyArray(context);
}
return null;
}
@SuppressWarnings("deprecation")
public void isolateInternalErrorCheck(Object exception) {
boolean internalError = !(exception instanceof com.oracle.truffle.api.TruffleException) && !(exception instanceof StackOverflowError) && !(exception instanceof OutOfMemoryError) &&
!(exception instanceof ControlFlowException) && !(exception instanceof GraalJSKillException);
if (internalError) {
((Throwable) exception).printStackTrace();
exit(1);
}
}
public void isolateThrowStackOverflowError() {
throw Errors.createRangeErrorStackOverflow();
}
public void isolateGetHeapStatistics() {
Runtime runtime = Runtime.getRuntime();
long total = runtime.totalMemory();
long free = runtime.freeMemory();
long max = runtime.maxMemory();
resetSharedBuffer();
sharedBuffer.putLong(total);
sharedBuffer.putLong(max);
sharedBuffer.putLong(total - free);
}
private boolean terminateExecution;
public synchronized void isolateCancelTerminateExecution() {
terminateExecution = false;
if (Thread.currentThread() == agent.getThread()) {
Thread.interrupted();
}
}
public synchronized void isolateTerminateExecution() {
if (terminateExecution) {
return;
}
terminateExecution = true;
Thread thread = agent.getThread();
if (thread != null) {
thread.interrupt();
}
Debugger debugger = lookupInstrument("debugger", Debugger.class);
if (debugger == null) {
System.err.println("Debugger is not available!");
return;
}
debugger.startSession(new SuspendedCallback() {
@Override
public void onSuspend(SuspendedEvent se) {
se.getSession().close();
synchronized (GraalJSAccess.this) {
if (!terminateExecution) {
return;
}
}
throw new GraalJSKillException();
}
}).suspendNextExecution();
}
private static final class GraalJSKillException extends ThreadDeath {
private static final long serialVersionUID = 3930431622452607906L;
}
public Object isolateGetIntPlaceholder() {
return INT_PLACEHOLDER;
}
public Object isolateGetSafeIntPlaceholder() {
return SAFE_INT_PLACEHOLDER;
}
public Object isolateGetDoublePlaceholder() {
return DOUBLE_PLACEHOLDER;
}
public void isolateDispose(boolean exit, int status) {
if (exit) {
exit(status);
}
}
public void isolateEnablePromiseHook(boolean enable) {
PromiseHook hook = enable ? new PromiseHook() {
@Override
public void promiseChanged(int changeType, DynamicObject promise, DynamicObject parentPromise) {
NativeAccess.notifyPromiseHook(changeType, promise, parentPromise);
}
} : null;
mainJSContext.setPromiseHook(hook);
}
public void isolateEnablePromiseRejectCallback(boolean enable) {
PromiseRejectionTracker tracker = enable ? new PromiseRejectionTracker() {
@Override
public void promiseRejected(DynamicObject promise, Object value) {
NativeAccess.notifyPromiseRejectionTracker(
promise,
0,
value);
}
@Override
public void promiseRejectionHandled(DynamicObject promise) {
NativeAccess.notifyPromiseRejectionTracker(
promise,
1,
Undefined.instance);
}
@Override
public void promiseRejectedAfterResolved(DynamicObject promise, Object value) {
NativeAccess.notifyPromiseRejectionTracker(
promise,
2,
value);
}
@Override
public void promiseResolvedAfterResolved(DynamicObject promise, Object value) {
NativeAccess.notifyPromiseRejectionTracker(
promise,
3,
value);
}
} : null;
mainJSContext.setPromiseRejectionTracker(tracker);
}
public void isolateEnableImportMetaInitializer(boolean enable) {
ImportMetaInitializer initializer = enable ? new ImportMetaInitializer() {
@Override
public void initializeImportMeta(DynamicObject importMeta, JSModuleRecord module) {
NativeAccess.notifyImportMetaInitializer(importMeta, module);
}
} : null;
mainJSContext.setImportMetaInitializer(initializer);
}
public void isolateEnableImportModuleDynamically(boolean enable) {
ImportModuleDynamicallyCallback callback = enable ? new ImportModuleDynamicallyCallback() {
@Override
public DynamicObject importModuleDynamically(JSRealm realm, ScriptOrModule referrer, String specifier) {
return (DynamicObject) NativeAccess.executeImportModuleDynamicallyCallback(realm, referrer, specifier);
}
} : null;
mainJSContext.setImportModuleDynamicallyCallback(callback);
}
public void isolateEnablePrepareStackTraceCallback(boolean enable) {
PrepareStackTraceCallback callback = enable ? new PrepareStackTraceCallback() {
@Override
public Object prepareStackTrace(JSRealm realm, DynamicObject error, DynamicObject structuredStackTrace) {
return NativeAccess.executePrepareStackTraceCallback(realm, error, structuredStackTrace);
}
} : null;
mainJSContext.setPrepareStackTraceCallback(callback);
}
private void exit(int status) {
evaluator.close();
System.exit(status);
}
public void isolateEnterPolyglotEngine(long callback, long isolate, long param1, long param2, long args, long execArgs) {
org.graalvm.polyglot.Source source = org.graalvm.polyglot.Source.newBuilder(JavaScriptLanguage.ID, "(function(r) { r.run(); })", "polyglotEngineWrapper").internal(true).buildLiteral();
org.graalvm.polyglot.Value wrapper = evaluator.eval(source);
wrapper.execute(new RunnableInvoker(new Runnable() {
@Override
public void run() {
NativeAccess.polyglotEngineEntered(callback, isolate, param1, param2, args, execArgs);
}
}));
}
private static final ThreadLocal<Deque<Pair<Long, Object>>> isolateStack = new ThreadLocal<>();
public void isolateEnter(long isolate) {
Deque<Pair<Long, Object>> list = isolateStack.get();
if (list == null) {
list = new LinkedList<>();
isolateStack.set(list);
}
Object previous = mainJSRealm.getTruffleContext().enter(null);
if (list.isEmpty()) {
agent.setThread(Thread.currentThread());
}
list.push(new Pair<>(isolate, previous));
}
public long isolateExit(long isolate) {
Deque<Pair<Long, Object>> list = isolateStack.get();
Pair<Long, Object> pair = list.pop();
assert pair.getFirst() == isolate;
mainJSRealm.getTruffleContext().leave(null, pair.getSecond());
if (list.isEmpty()) {
agent.setThread(null);
return 0;
} else {
return list.peekLast().getFirst();
}
}
public void isolateEnqueueMicrotask(Object microtask) {
agent.enqueuePromiseJob((DynamicObject) microtask);
}
public void isolateSchedulePauseOnNextStatement() {
Breakpoint breakpoint = Breakpoint.newBuilder((URI) null).oneShot().build();
Debugger debugger = lookupInstrument("debugger", Debugger.class);
debugger.install(breakpoint);
}
public Object correctReturnValue(Object value) {
if (value == INT_PLACEHOLDER) {
resetSharedBuffer();
return getSharedBuffer().getInt();
} else if (value == SAFE_INT_PLACEHOLDER) {
resetSharedBuffer();
return SafeInteger.valueOf(getSharedBuffer().getLong());
} else if (value == DOUBLE_PLACEHOLDER) {
resetSharedBuffer();
return getSharedBuffer().getDouble();
} else {
return value;
}
}
public void stringExternalResourceCallback(Object object, long data, long callbackPointer) {
WeakCallback weakCallback = new WeakCallback(object, data, callbackPointer, 1, weakCallbackQueue);
weakCallbacks.add(weakCallback);
pollWeakCallbackQueue(false);
}
public Object proxyGetTarget(Object proxy) {
return JSProxy.getTarget((DynamicObject) proxy);
}
public Object proxyGetHandler(Object proxy) {
return JSProxy.getHandler((DynamicObject) proxy);
}
public boolean proxyIsFunction(Object proxy) {
return JSRuntime.isCallableProxy((DynamicObject) proxy);
}
public Object booleanObjectNew(Object context, boolean value) {
return JSBoolean.create(((JSRealm) context).getContext(), value);
}
public boolean booleanObjectValueOf(Object object) {
return JSBoolean.valueOf((DynamicObject) object);
}
public Object stringObjectNew(Object context, Object value) {
return JSString.create(((JSRealm) context).getContext(), (String) value);
}
public String stringObjectValueOf(Object object) {
return JSString.getString((DynamicObject) object);
}
public Object numberObjectNew(Object context, double value) {
return JSNumber.create(((JSRealm) context).getContext(), value);
}
private static String regexpFlagsToString(int flags) {
StringBuilder builder = new StringBuilder();
if ((flags & 1 ) != 0) {
builder.append('g');
} else if ((flags & 2 ) != 0) {
builder.append('i');
} else if ((flags & 4 ) != 0) {
builder.append('m');
} else if ((flags & 8 ) != 0) {
builder.append('y');
} else if ((flags & 16 ) != 0) {
builder.append('u');
} else if ((flags & 32 ) != 0) {
builder.append('s');
}
return builder.toString();
}
public Object regexpNew(Object context, Object pattern, int flags) {
JSContext jsContext = ((JSRealm) context).getContext();
return regexpCreate(jsContext, (String) pattern, flags);
}
public static Object regexpCreate(JSContext context, String pattern, int v8Flags) {
Object compiledRegexp = RegexCompilerInterface.compile(pattern, regexpFlagsToString(v8Flags), context, TRegexUtil.CompileRegexNode.getUncached());
return JSRegExp.create(context, compiledRegexp);
}
@TruffleBoundary
public String regexpGetSource(Object regexp) {
return regexpPattern((DynamicObject) regexp);
}
public static String regexpPattern(DynamicObject regexp) {
assert JSRegExp.isJSRegExp(regexp);
Object compiledRegex = JSRegExp.getCompiledRegex(regexp);
return TRegexUtil.InteropReadStringMemberNode.getUncached().execute(compiledRegex, TRegexUtil.Props.CompiledRegex.PATTERN);
}
@TruffleBoundary
public int regexpGetFlags(Object regexp) {
return regexpV8Flags((DynamicObject) regexp);
}
public static int regexpV8Flags(DynamicObject regexp) {
Object compiledRegex = JSRegExp.getCompiledRegex(regexp);
Object flagsObj = TRegexUtil.InteropReadMemberNode.getUncached().execute(compiledRegex, TRegexUtil.Props.CompiledRegex.FLAGS);
int v8Flags = 0;
if (TRegexUtil.InteropReadBooleanMemberNode.getUncached().execute(flagsObj, TRegexUtil.Props.Flags.GLOBAL)) {
v8Flags |= 1;
}
if (TRegexUtil.InteropReadBooleanMemberNode.getUncached().execute(flagsObj, TRegexUtil.Props.Flags.IGNORE_CASE)) {
v8Flags |= 2;
}
if (TRegexUtil.InteropReadBooleanMemberNode.getUncached().execute(flagsObj, TRegexUtil.Props.Flags.MULTILINE)) {
v8Flags |= 4;
}
if (TRegexUtil.InteropReadBooleanMemberNode.getUncached().execute(flagsObj, TRegexUtil.Props.Flags.STICKY)) {
v8Flags |= 8;
}
if (TRegexUtil.InteropReadBooleanMemberNode.getUncached().execute(flagsObj, TRegexUtil.Props.Flags.UNICODE)) {
v8Flags |= 16;
}
return v8Flags;
}
public Object[] findDynamicObjectFields(Object context) {
if (!JSConfig.SubstrateVM) {
Object arrayBuffer = arrayBufferNew(context, 4);
Object typedArray = uint8ArrayNew(arrayBuffer, 2, 1);
return new Object[]{
findDeclaredField(arrayBuffer.getClass(), "byteBuffer"),
findDeclaredField(typedArray.getClass(), "arrayBuffer"),
};
}
return null;
}
private static Field findDeclaredField(Class<?> bottom, String fieldName) {
for (Class<?> cls = bottom; cls != null && cls != Object.class; cls = cls.getSuperclass()) {
try {
return cls.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
continue;
} catch (SecurityException e) {
break;
}
}
return null;
}
public Object jsonParse(Object context, Object string) {
TruffleJSONParser parser = new TruffleJSONParser(((JSRealm) context).getContext());
return parser.parse((String) string);
}
public String jsonStringify(Object context, Object object, String gap) {
DynamicObject stringify = ((JSRealm) context).lookupFunction(JSONBuiltins.BUILTINS, "stringify");
return (String) JSFunction.call(stringify, Undefined.instance, new Object[]{
object,
Undefined.instance,
(gap == null) ? Undefined.instance : gap
});
}
public Object promiseResult(Object promise) {
return JSObjectUtil.getHiddenProperty((DynamicObject) promise, JSPromise.PROMISE_RESULT);
}
public int promiseState(Object promise) {
return JSPromise.getPromiseState((DynamicObject) promise);
}
public Object promiseResolverNew(Object context) {
DynamicObject resolverFactory = getResolverFactory(context);
return JSFunction.call(JSArguments.create(Undefined.instance, resolverFactory, RESOLVER_RESOLVE, RESOLVER_REJECT));
}
private DynamicObject getResolverFactory(Object realm) {
RealmData data = getRealmEmbedderData(realm);
DynamicObject resolverFactory = data.getResolverFactory();
if (resolverFactory == null) {
resolverFactory = createResolverFactory((JSRealm) realm);
data.setResolverFactory(resolverFactory);
}
return resolverFactory;
}
private DynamicObject createResolverFactory(JSRealm realm) {
JSContext context = realm.getContext();
JSParser parser = (JSParser) context.getEvaluator();
String code = "(function(resolveKey, rejectKey) {\n" +
" var resolve, reject;\n" +
" var promise = new Promise(function() {\n" +
" resolve = arguments[0];\n" +
" reject = arguments[1];\n" +
" });\n" +
" Object.defineProperty(promise, resolveKey, { value : resolve });\n" +
" Object.defineProperty(promise, rejectKey, { value : reject });\n" +
" return promise;\n" +
"})";
ScriptNode scriptNode = parser.parseScript(context, code);
return (DynamicObject) scriptNode.run(realm);
}
public boolean promiseResolverResolve(Object resolver, Object value) {
Object resolve = JSObject.get((DynamicObject) resolver, RESOLVER_RESOLVE);
JSFunction.call(JSArguments.create(Undefined.instance, resolve, value));
return true;
}
public boolean promiseResolverReject(Object resolver, Object value) {
Object reject = JSObject.get((DynamicObject) resolver, RESOLVER_REJECT);
JSFunction.call(JSArguments.create(Undefined.instance, reject, value));
return true;
}
private ESModuleLoader getModuleLoader() {
if (moduleLoader == null) {
moduleLoader = new ESModuleLoader();
}
return moduleLoader;
}
public Object moduleCompile(Object context, Object sourceCode, Object name, Object hostDefinedOptions) {
JSContext jsContext = ((JSRealm) context).getContext();
NodeFactory factory = NodeFactory.getInstance(jsContext);
String moduleName = (String) name;
Source.LiteralBuilder builder = Source.newBuilder(JavaScriptLanguage.ID, (String) sourceCode, moduleName);
try {
builder = builder.uri(new URI(moduleName));
} catch (URISyntaxException usex) {
}
Source source = builder.build();
hostDefinedOptionsMap.put(source, hostDefinedOptions);
return JavaScriptTranslator.translateModule(factory, jsContext, source, getModuleLoader());
}
public void moduleInstantiate(Object context, Object module, long resolveCallback) {
JSRealm jsRealm = (JSRealm) context;
JSContext jsContext = jsRealm.getContext();
ESModuleLoader loader = getModuleLoader();
loader.setResolver(resolveCallback);
try {
jsContext.getEvaluator().moduleInstantiation(jsRealm, (JSModuleRecord) module);
} finally {
loader.setResolver(0);
}
}
public Object moduleEvaluate(Object context, Object module) {
JSRealm jsRealm = (JSRealm) context;
JSContext jsContext = jsRealm.getContext();
JSModuleRecord moduleRecord = (JSModuleRecord) module;
if (moduleRecord.isEvaluated() && moduleRecord.getEvaluationError() == null) {
return Undefined.instance;
}
jsContext.getEvaluator().moduleEvaluation(jsRealm, moduleRecord);
Throwable evaluationError = moduleRecord.getEvaluationError();
if (evaluationError == null) {
return moduleRecord.getExecutionResult();
} else {
throw JSRuntime.rethrow(evaluationError);
}
}
public int moduleGetStatus(Object module) {
JSModuleRecord record = (JSModuleRecord) module;
switch (record.getStatus()) {
case Unlinked:
return 0;
case Linking:
return 1;
case Linked:
return 2;
case Evaluating:
return 3;
case Evaluated:
default:
assert record.getStatus() == JSModuleRecord.Status.Evaluated;
if (record.getEvaluationError() == null) {
return 4;
} else {
return 5;
}
}
}
public Object moduleGetException(Object module) {
JSModuleRecord record = (JSModuleRecord) module;
Throwable evaluationError = record.getEvaluationError();
if (evaluationError instanceof GraalJSException) {
return ((GraalJSException) evaluationError).getErrorObjectEager(record.getContext());
}
return evaluationError;
}
public int moduleGetRequestsLength(Object module) {
JSModuleRecord record = (JSModuleRecord) module;
return ((Module) record.getModule()).getRequestedModules().size();
}
public String moduleGetRequest(Object module, int index) {
JSModuleRecord record = (JSModuleRecord) module;
return ((Module) record.getModule()).getRequestedModules().get(index);
}
public Object moduleGetNamespace(Object module) {
JSModuleRecord record = (JSModuleRecord) module;
GraalJSEvaluator graalEvaluator = (GraalJSEvaluator) record.getContext().getEvaluator();
return graalEvaluator.getModuleNamespace(record);
}
public int moduleGetIdentityHash(Object module) {
return System.identityHashCode(module);
}
public Object moduleCreateSyntheticModule(String moduleName, Object[] exportNames, final long evaluationStepsCallback) {
FrameDescriptor frameDescriptor = new FrameDescriptor(Undefined.instance);
List<Module.ExportEntry> localExportEntries = new ArrayList<>();
for (Object exportName : exportNames) {
frameDescriptor.addFrameSlot(exportName);
localExportEntries.add(Module.ExportEntry.exportSpecifier((String) exportName));
}
Module moduleNode = new Module(Collections.emptyList(), Collections.emptyList(), localExportEntries, Collections.emptyList(), Collections.emptyList(), null, null);
Source source = Source.newBuilder(JavaScriptLanguage.ID, "<unavailable>", moduleName).build();
final JSModuleRecord moduleRecord = new JSModuleRecord(moduleNode, mainJSContext, getModuleLoader(), source);
moduleRecord.setFrameDescriptor(frameDescriptor);
JavaScriptRootNode rootNode = new JavaScriptRootNode(mainJSContext.getLanguage(), source.createUnavailableSection(), frameDescriptor) {
@Override
public Object execute(VirtualFrame frame) {
JSModuleRecord module = (JSModuleRecord) JSArguments.getUserArgument(frame.getArguments(), 0);
if (module.getEnvironment() == null) {
assert module.getStatus() == Status.Linking;
module.setEnvironment(frame.materialize());
return Undefined.instance;
} else {
assert module.getStatus() == Status.Evaluating;
return invokeEvaluationStepsCallback(mainJSContext.getRealm(), module);
}
}
@TruffleBoundary
private Object invokeEvaluationStepsCallback(JSRealm realm, JSModuleRecord module) {
return NativeAccess.syntheticModuleEvaluationSteps(evaluationStepsCallback, realm, module);
}
};
CallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode);
JSFunctionData functionData = JSFunctionData.createCallOnly(mainJSContext, callTarget, 0, moduleName);
moduleRecord.setFunctionData(functionData);
return moduleRecord;
}
public void moduleSetSyntheticModuleExport(Object module, String exportName, Object exportValue) {
JSModuleRecord moduleRecord = (JSModuleRecord) module;
FrameDescriptor frameDescriptor = moduleRecord.getFrameDescriptor();
FrameSlot frameSlot = frameDescriptor.findFrameSlot(exportName);
if (frameSlot == null) {
throw Errors.createReferenceError("Export '" + exportName + "' is not defined in module");
}
MaterializedFrame frame = moduleRecord.getEnvironment();
frame.setObject(frameSlot, exportValue);
}
private static final ByteBuffer DUMMY_UNBOUND_MODULE_PARSE_RESULT = ByteBuffer.allocate(0);
public Object moduleGetUnboundModuleScript(Object module) {
JSModuleRecord moduleRecord = (JSModuleRecord) module;
return new UnboundScript(moduleRecord.getSource(), DUMMY_UNBOUND_MODULE_PARSE_RESULT);
}
public String scriptOrModuleGetResourceName(Object scriptOrModule) {
ScriptOrModule record = (ScriptOrModule) scriptOrModule;
return record.getSource().getName();
}
public Object scriptOrModuleGetHostDefinedOptions(Object scriptOrModule) {
ScriptOrModule record = (ScriptOrModule) scriptOrModule;
Object hostDefinedOptions = hostDefinedOptionsMap.get(record.getSource());
return (hostDefinedOptions == null) ? new Object[0] : hostDefinedOptions;
}
public Object valueSerializerNew(long delegatePointer) {
return new Serializer(mainJSContext, this, delegatePointer);
}
public int valueSerializerSize(Object serializer) {
return ((Serializer) serializer).size();
}
public void valueSerializerRelease(Object serializer, Object targetBuffer) {
((Serializer) serializer).release((ByteBuffer) targetBuffer);
}
public void (Object serializer) {
((Serializer) serializer).writeHeader();
}
public void valueSerializerWriteValue(Object serializer, Object value) {
((Serializer) serializer).writeValue(value);
}
public void valueSerializerWriteUint32(Object serializer, int value) {
((Serializer) serializer).writeVarInt(Integer.toUnsignedLong(value));
}
public void valueSerializerWriteUint64(Object serializer, long value) {
((Serializer) serializer).writeVarInt(value);
}
public void valueSerializerWriteDouble(Object serializer, double value) {
((Serializer) serializer).writeDouble(value);
}
public void valueSerializerWriteRawBytes(Object serializer, Object bytes) {
((Serializer) serializer).writeBytes((ByteBuffer) bytes);
}
public void valueSerializerSetTreatArrayBufferViewsAsHostObjects(Object serializer, boolean treatArrayBufferViewsAsHostObjects) {
((Serializer) serializer).setTreatArrayBufferViewsAsHostObjects(treatArrayBufferViewsAsHostObjects);
}
public void valueSerializerTransferArrayBuffer(Object serializer, int id, Object arrayBuffer) {
((Serializer) serializer).transferArrayBuffer(id, arrayBuffer);
}
public Object valueDeserializerNew(long delegate, Object buffer) {
return new Deserializer(delegate, (ByteBuffer) buffer);
}
public void (Object deserializer) {
((Deserializer) deserializer).readHeader();
}
public Object valueDeserializerReadValue(Object context, Object deserializer) {
return ((Deserializer) deserializer).readValue(((JSRealm) context).getContext());
}
public int valueDeserializerReadUint32(Object deserializer) {
return ((Deserializer) deserializer).readVarInt();
}
public long valueDeserializerReadUint64(Object deserializer) {
return ((Deserializer) deserializer).readVarLong();
}
public double valueDeserializerReadDouble(Object deserializer) {
return ((Deserializer) deserializer).readDouble();
}
public int valueDeserializerReadRawBytes(Object deserializer, int length) {
return ((Deserializer) deserializer).readBytes(length);
}
public void valueDeserializerTransferArrayBuffer(Object deserializer, int id, Object arrayBuffer) {
((Deserializer) deserializer).transferArrayBuffer(id, (DynamicObject) arrayBuffer);
}
public int valueDeserializerGetWireFormatVersion(Object deserializer) {
return ((Deserializer) deserializer).getWireFormatVersion();
}
public Object mapNew(Object context) {
JSContext jsContext = ((JSRealm) context).getContext();
return JSMap.create(jsContext);
}
public void mapSet(Object set, Object key, Object value) {
DynamicObject object = (DynamicObject) set;
JSMap.getInternalMap(object).put(JSSet.normalize(key), value);
}
public Object setNew(Object context) {
JSContext jsContext = ((JSRealm) context).getContext();
return JSSet.create(jsContext);
}
public void setAdd(Object set, Object key) {
DynamicObject object = (DynamicObject) set;
JSSet.getInternalSet(object).put(JSSet.normalize(key), new Object());
}
public long bigIntInt64Value(Object value) {
BigInteger bigInt = ((BigInt) value).bigIntegerValue();
resetSharedBuffer();
sharedBuffer.putInt(bigInt.bitLength() <= 63 ? 1 : 0);
return bigInt.longValue();
}
public long bigIntUint64Value(Object value) {
BigInteger bigInt = ((BigInt) value).bigIntegerValue();
resetSharedBuffer();
sharedBuffer.putInt((bigInt.signum() != -1 && bigInt.bitLength() <= 64) ? 1 : 0);
return bigInt.longValue();
}
public Object bigIntNew(long value) {
return BigInt.valueOf(value);
}
public Object bigIntNewFromUnsigned(long value) {
BigInteger bigInt = BigInteger.valueOf(value & 0x7FFFFFFFFFFFFFFFL);
if (value < 0) {
bigInt = bigInt.setBit(63);
}
return new BigInt(bigInt);
}
public Object bigIntNewFromWords() {
resetSharedBuffer();
int sign = sharedBuffer.getInt();
int count = sharedBuffer.getInt();
BigInteger result = BigInteger.ZERO;
for (int wordIdx = 0; wordIdx < count; wordIdx++) {
long word = sharedBuffer.getLong();
for (int bit = 0; bit < 64; bit++) {
if ((word & (1L << bit)) != 0) {
result = result.setBit(bit + 64 * wordIdx);
}
}
}
if (sign != 0) {
result = result.negate();
}
return new BigInt(result);
}
public int bigIntWordCount(Object value) {
BigInteger bigInt = ((BigInt) value).bigIntegerValue();
return (bigInt.bitLength() + ((bigInt.signum() == -1) ? 1 : 0) + 63) / 64;
}
public void bigIntToWordsArray(Object value) {
BigInteger bigInt = ((BigInt) value).bigIntegerValue();
resetSharedBuffer();
int count = bigIntWordCount(value);
sharedBuffer.putInt(count);
sharedBuffer.putInt(bigInt.signum() == -1 ? 1 : 0);
if (bigInt.signum() == -1) {
bigInt = bigInt.negate();
}
for (int wordIdx = 0; wordIdx < count; wordIdx++) {
long word = 0;
for (int bit = 63; bit >= 0; bit--) {
word <<= 1;
if (bigInt.testBit(bit + 64 * wordIdx)) {
word++;
}
}
sharedBuffer.putLong(word);
}
}
private static class WeakCallback extends WeakReference<Object> {
long data;
long callback;
int type;
WeakCallback(Object object, long data, long callback, int type, ReferenceQueue<Object> queue) {
super(object, queue);
this.data = data;
this.callback = callback;
this.type = type;
}
}
static class PropertyHandlerPrototypeNode extends JavaScriptRootNode {
private final boolean global;
@Child private GetPrototypeNode getPrototypeNode;
PropertyHandlerPrototypeNode(boolean global) {
this.global = global;
if (!global) {
this.getPrototypeNode = GetPrototypeNode.create();
}
}
@Override
public Object execute(VirtualFrame vf) {
Object target = vf.getArguments()[2];
if (global) {
return target;
} else {
return getPrototypeNode.executeJSObject(target);
}
}
}
static class ESModuleLoader implements JSModuleLoader {
private final Map<ScriptOrModule, Map<String, JSModuleRecord>> cache = new HashMap<>();
private long resolver;
void setResolver(long resolver) {
this.resolver = resolver;
}
@Override
public JSModuleRecord resolveImportedModule(ScriptOrModule referrer, String specifier) {
Map<String, JSModuleRecord> referrerCache = cache.get(referrer);
if (referrerCache == null) {
referrerCache = new HashMap<>();
cache.put(referrer, referrerCache);
} else {
JSModuleRecord cached = referrerCache.get(specifier);
if (cached != null) {
return cached;
}
}
if (resolver == 0) {
System.err.println("Cannot resolve module outside module instantiation!");
System.exit(1);
}
JSModuleRecord result = (JSModuleRecord) NativeAccess.executeResolveCallback(resolver, referrer.getContext().getRealm(), specifier, referrer);
referrerCache.put(specifier, result);
return result;
}
@Override
public JSModuleRecord loadModule(Source moduleSource) {
throw new UnsupportedOperationException();
}
}
private JavaMessagePortData currentMessagePortData = null;
public void unsetCurrentMessagePortData() {
currentMessagePortData.encodingEnd();
currentMessagePortData = null;
}
public void setCurrentMessagePortData(JSExternalObject nativeMessagePortData) {
assert nativeMessagePortData != null;
assert currentMessagePortData == null;
currentMessagePortData = SharedMemMessagingManager.getJavaMessagePortDataFor(nativeMessagePortData);
assert currentMessagePortData != null;
currentMessagePortData.encodingBegin();
}
public JavaMessagePortData getCurrentMessagePortData() {
return currentMessagePortData;
}
static class NodeScriptOrModule extends ScriptOrModule {
static final HiddenKey SCRIPT_OR_MODULE = new HiddenKey("scriptOrModule");
private Map<Long, WeakCallback> weakCallbackMap;
NodeScriptOrModule(JSContext context, Source source) {
super(context, source);
}
Map<Long, WeakCallback> getWeakCallbackMap() {
if (weakCallbackMap == null) {
weakCallbackMap = new HashMap<>();
}
return weakCallbackMap;
}
}
}