package com.oracle.truffle.js.builtins;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.instrumentation.Tag;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugClassNameNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugClassNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugContinueInInterpreterNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugStringCompareNodeGen;
import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugTypedArrayDetachBufferNodeGen;
import com.oracle.truffle.js.builtins.TestV8BuiltinsFactory.TestV8ConstructDoubleNodeGen;
import com.oracle.truffle.js.builtins.TestV8BuiltinsFactory.TestV8CreateAsyncFromSyncIteratorNodeGen;
import com.oracle.truffle.js.builtins.TestV8BuiltinsFactory.TestV8DoublePartNodeGen;
import com.oracle.truffle.js.builtins.TestV8BuiltinsFactory.TestV8EnqueueJobNodeGen;
import com.oracle.truffle.js.builtins.TestV8BuiltinsFactory.TestV8ReferenceEqualNodeGen;
import com.oracle.truffle.js.builtins.TestV8BuiltinsFactory.TestV8RunMicrotasksNodeGen;
import com.oracle.truffle.js.builtins.TestV8BuiltinsFactory.TestV8SetTimeoutNodeGen;
import com.oracle.truffle.js.builtins.TestV8BuiltinsFactory.TestV8ToLengthNodeGen;
import com.oracle.truffle.js.builtins.TestV8BuiltinsFactory.TestV8ToNameNodeGen;
import com.oracle.truffle.js.builtins.TestV8BuiltinsFactory.TestV8ToNumberNodeGen;
import com.oracle.truffle.js.builtins.TestV8BuiltinsFactory.TestV8ToPrimitiveNodeGen;
import com.oracle.truffle.js.builtins.TestV8BuiltinsFactory.TestV8ToStringNodeGen;
import com.oracle.truffle.js.builtins.helper.GCNodeGen;
import com.oracle.truffle.js.nodes.JavaScriptNode;
import com.oracle.truffle.js.nodes.access.PropertyGetNode;
import com.oracle.truffle.js.nodes.access.PropertySetNode;
import com.oracle.truffle.js.nodes.cast.JSToLengthNode;
import com.oracle.truffle.js.nodes.cast.JSToNumberNode;
import com.oracle.truffle.js.nodes.cast.JSToPrimitiveNode;
import com.oracle.truffle.js.nodes.cast.JSToStringNode;
import com.oracle.truffle.js.nodes.function.JSBuiltin;
import com.oracle.truffle.js.nodes.function.JSBuiltinNode;
import com.oracle.truffle.js.runtime.Errors;
import com.oracle.truffle.js.runtime.JSContext;
import com.oracle.truffle.js.runtime.JSRealm;
import com.oracle.truffle.js.runtime.JSRuntime;
import com.oracle.truffle.js.runtime.Symbol;
import com.oracle.truffle.js.runtime.builtins.BuiltinEnum;
import com.oracle.truffle.js.runtime.builtins.JSFunction;
import com.oracle.truffle.js.runtime.builtins.JSTestV8;
import com.oracle.truffle.js.runtime.builtins.JSOrdinary;
import com.oracle.truffle.js.runtime.objects.IteratorRecord;
import com.oracle.truffle.js.runtime.objects.Undefined;
public final class TestV8Builtins extends JSBuiltinsContainer.SwitchEnum<TestV8Builtins.TestV8> {
public static final JSBuiltinsContainer BUILTINS = new TestV8Builtins();
protected TestV8Builtins() {
super(JSTestV8.CLASS_NAME, TestV8.class);
}
public enum TestV8 implements BuiltinEnum<TestV8> {
class_(1),
className(1),
createAsyncFromSyncIterator(1),
runMicrotasks(0),
enqueueJob(1),
setTimeout(1),
stringCompare(2),
typedArrayDetachBuffer(1),
constructDouble(2),
doubleHi(1),
doubleLo(1),
deoptimize(0),
gc(0),
referenceEqual(2),
toLength(1),
toStringConv(1),
toName(1),
toNumber(1),
toPrimitive(1),
toPrimitiveString(1),
toPrimitiveNumber(1);
private final int length;
TestV8(int length) {
this.length = length;
}
@Override
public int getLength() {
return length;
}
}
@Override
protected Object createNode(JSContext context, JSBuiltin builtin, boolean construct, boolean newTarget, TestV8 builtinEnum) {
switch (builtinEnum) {
case class_:
return DebugClassNodeGen.create(context, builtin, true, args().fixedArgs(1).createArgumentNodes(context));
case className:
return DebugClassNameNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case createAsyncFromSyncIterator:
return TestV8CreateAsyncFromSyncIteratorNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case runMicrotasks:
return TestV8RunMicrotasksNodeGen.create(context, builtin, args().createArgumentNodes(context));
case enqueueJob:
return TestV8EnqueueJobNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case setTimeout:
return TestV8SetTimeoutNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case stringCompare:
return DebugStringCompareNodeGen.create(context, builtin, args().fixedArgs(2).createArgumentNodes(context));
case typedArrayDetachBuffer:
return DebugTypedArrayDetachBufferNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case constructDouble:
return TestV8ConstructDoubleNodeGen.create(context, builtin, args().fixedArgs(2).createArgumentNodes(context));
case doubleHi:
return TestV8DoublePartNodeGen.create(context, builtin, true, args().fixedArgs(1).createArgumentNodes(context));
case doubleLo:
return TestV8DoublePartNodeGen.create(context, builtin, false, args().fixedArgs(1).createArgumentNodes(context));
case deoptimize:
return DebugContinueInInterpreterNodeGen.create(context, builtin, true, args().createArgumentNodes(context));
case gc:
return GCNodeGen.create(context, builtin, args().createArgumentNodes(context));
case referenceEqual:
return TestV8ReferenceEqualNodeGen.create(context, builtin, args().fixedArgs(2).createArgumentNodes(context));
case toStringConv:
return TestV8ToStringNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case toName:
return TestV8ToNameNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case toPrimitive:
return TestV8ToPrimitiveNodeGen.create(context, builtin, JSToPrimitiveNode.Hint.None, args().fixedArgs(1).createArgumentNodes(context));
case toPrimitiveString:
return TestV8ToPrimitiveNodeGen.create(context, builtin, JSToPrimitiveNode.Hint.String, args().fixedArgs(1).createArgumentNodes(context));
case toPrimitiveNumber:
return TestV8ToPrimitiveNodeGen.create(context, builtin, JSToPrimitiveNode.Hint.Number, args().fixedArgs(1).createArgumentNodes(context));
case toNumber:
return TestV8ToNumberNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case toLength:
return TestV8ToLengthNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
}
return null;
}
public abstract static class TestV8ConstructDoubleNode extends JSBuiltinNode {
public TestV8ConstructDoubleNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@TruffleBoundary
@Specialization
protected double constructDouble(Object hiObj, Object loObj) {
long hi = JSRuntime.toUInt32(hiObj);
long lo = JSRuntime.toUInt32(loObj);
return Double.longBitsToDouble((hi << 32) | lo);
}
}
public abstract static class TestV8DoublePartNode extends JSBuiltinNode {
private final boolean upper;
public TestV8DoublePartNode(JSContext context, JSBuiltin builtin, boolean upper) {
super(context, builtin);
this.upper = upper;
}
@Specialization
protected int doublePart(Object value) {
long bits = Double.doubleToRawLongBits((double) value);
return upper ? (int) (bits >>> 32L) : (int) (bits & 0xFFFF_FFFFL);
}
}
public abstract static class TestV8ToStringNode extends JSBuiltinNode {
@Child private JSToStringNode toStringNode;
public TestV8ToStringNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
toStringNode = JSToStringNode.create();
}
@Specialization
protected String toStringConv(Object obj) {
return toStringNode.executeString(obj);
}
}
public abstract static class TestV8ToNumberNode extends JSBuiltinNode {
@Child private JSToNumberNode toNumberNode;
public TestV8ToNumberNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
toNumberNode = JSToNumberNode.create();
}
@Specialization
protected Number toNumberOp(Object obj) {
return toNumberNode.executeNumber(obj);
}
}
public abstract static class TestV8ToPrimitiveNode extends JSBuiltinNode {
@Child private JSToPrimitiveNode toPrimitiveNode;
public TestV8ToPrimitiveNode(JSContext context, JSBuiltin builtin, JSToPrimitiveNode.Hint hint) {
super(context, builtin);
toPrimitiveNode = JSToPrimitiveNode.create(hint);
}
@Specialization
protected Object toPrimitive(Object obj) {
return toPrimitiveNode.execute(obj);
}
}
public abstract static class TestV8ToNameNode extends JSBuiltinNode {
@Child private JSToStringNode toStringNode;
public TestV8ToNameNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
toStringNode = JSToStringNode.create();
}
@Specialization
protected Object toName(Object obj) {
if (obj instanceof Symbol) {
return obj;
} else {
return toStringNode.executeString(obj);
}
}
}
public abstract static class TestV8RunMicrotasksNode extends JSBuiltinNode {
public TestV8RunMicrotasksNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@Specialization
protected Object runMicrotasks() {
JSContext context = getContext();
context.processAllPendingPromiseJobs(context.getRealm());
return Undefined.instance;
}
}
public abstract static class TestV8EnqueueJobNode extends JSBuiltinNode {
public TestV8EnqueueJobNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@Specialization
protected Object enqueueJob(Object function) {
if (JSFunction.isJSFunction(function)) {
getContext().promiseEnqueueJob(getContext().getRealm(), (DynamicObject) function);
}
return 0;
}
}
public abstract static class TestV8CreateAsyncFromSyncIterator extends JSBuiltinNode {
@Child private PropertySetNode setState;
@Child private PropertyGetNode getNextMethodNode;
public TestV8CreateAsyncFromSyncIterator(JSContext context, JSBuiltin builtin) {
super(context, builtin);
this.setState = PropertySetNode.createSetHidden(JSFunction.ASYNC_FROM_SYNC_ITERATOR_KEY, context);
this.getNextMethodNode = PropertyGetNode.create(JSRuntime.NEXT, context);
}
@Specialization(guards = "isJSObject(syncIterator)")
protected Object createAsyncFromSyncIterator(DynamicObject syncIterator) {
JSContext context = getContext();
DynamicObject obj = JSOrdinary.create(context, context.getAsyncFromSyncIteratorFactory());
IteratorRecord syncIteratorRecord = IteratorRecord.create(syncIterator, getNextMethodNode.getValue(syncIterator), false);
setState.setValue(obj, syncIteratorRecord);
return obj;
}
@Specialization(guards = "!isJSObject(syncIterator)")
protected Object notObject(Object syncIterator) {
throw Errors.createTypeErrorNotAnObject(syncIterator, this);
}
}
public abstract static class TestV8ToLengthNode extends JSBuiltinNode {
@Child private JSToLengthNode toLengthNode;
public TestV8ToLengthNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
toLengthNode = JSToLengthNode.create();
}
@Specialization
protected Object toLengthOp(Object obj) {
long value = toLengthNode.executeLong(obj);
double d = value;
if (JSRuntime.doubleIsRepresentableAsInt(d)) {
return (int) d;
} else {
return d;
}
}
@Override
protected JavaScriptNode copyUninitialized(Set<Class<? extends Tag>> materializedTags) {
return TestV8ToLengthNodeGen.create(getContext(), getBuiltin(), cloneUninitialized(getArguments(), materializedTags));
}
}
public abstract static class TestV8ReferenceEqualNode extends JSBuiltinNode {
public TestV8ReferenceEqualNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@Specialization
protected boolean referenceEqual(Object arg1, Object arg2) {
return arg1 == arg2;
}
}
public abstract static class TestV8SetTimeoutNode extends JSBuiltinNode {
public TestV8SetTimeoutNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@Specialization
@TruffleBoundary
@SuppressWarnings("unchecked")
protected Object setTimeout(Object callback) {
assert JSRuntime.isCallable(callback);
JSRealm realm = getContext().getRealm();
List<Object> embedderData = (List<Object>) realm.getEmbedderData();
if (embedderData == null) {
embedderData = new ArrayList<>();
realm.setEmbedderData(embedderData);
}
embedderData.add(callback);
return Undefined.instance;
}
}
}