package com.oracle.truffle.js.builtins;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.js.builtins.RealmFunctionBuiltinsFactory.RealmCreateNodeGen;
import com.oracle.truffle.js.builtins.RealmFunctionBuiltinsFactory.RealmCurrentNodeGen;
import com.oracle.truffle.js.builtins.RealmFunctionBuiltinsFactory.RealmDisposeNodeGen;
import com.oracle.truffle.js.builtins.RealmFunctionBuiltinsFactory.RealmEvalNodeGen;
import com.oracle.truffle.js.builtins.RealmFunctionBuiltinsFactory.RealmGlobalNodeGen;
import com.oracle.truffle.js.lang.JavaScriptLanguage;
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.Evaluator;
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.builtins.BuiltinEnum;
import com.oracle.truffle.js.runtime.objects.Undefined;
public final class RealmFunctionBuiltins extends JSBuiltinsContainer.SwitchEnum<RealmFunctionBuiltins.RealmFunction> {
public static final JSBuiltinsContainer BUILTINS = new RealmFunctionBuiltins();
protected RealmFunctionBuiltins() {
super(JSRealm.REALM_BUILTIN_CLASS_NAME, RealmFunction.class);
}
public enum RealmFunction implements BuiltinEnum<RealmFunction> {
create(0),
createAllowCrossRealmAccess(0),
global(1),
dispose(1),
current(0),
eval(2);
private final int length;
RealmFunction(int length) {
this.length = length;
}
@Override
public int getLength() {
return length;
}
}
@Override
protected Object createNode(JSContext context, JSBuiltin builtin, boolean construct, boolean newTarget, RealmFunction builtinEnum) {
switch (builtinEnum) {
case create:
case createAllowCrossRealmAccess:
return RealmCreateNodeGen.create(context, builtin, args().fixedArgs(0).createArgumentNodes(context));
case global:
return RealmGlobalNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case dispose:
return RealmDisposeNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context));
case current:
return RealmCurrentNodeGen.create(context, builtin, args().fixedArgs(0).createArgumentNodes(context));
case eval:
return RealmEvalNodeGen.create(context, builtin, args().fixedArgs(2).createArgumentNodes(context));
}
return null;
}
protected static JSRealm topLevelRealm(JSContext context) {
JSRealm realm = context.getRealm();
while (realm.getParent() != null) {
realm = realm.getParent();
}
return realm;
}
protected static int toRealmIndexOrThrow(JSRealm topLevelRealm, Object index) {
int realmIdx = JSRuntime.intValue(JSRuntime.toNumber(index));
if (realmIdx < 0) {
throw Errors.createTypeError("Invalid realm index");
}
JSRealm jsrealm = topLevelRealm.getFromRealmList(realmIdx);
if (jsrealm == null) {
throw Errors.createTypeError("Invalid realm index");
}
return realmIdx;
}
public abstract static class RealmCreateNode extends JSBuiltinNode {
public RealmCreateNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@TruffleBoundary
@Specialization
protected Object createRealm() {
JSRealm newRealm = getContext().getRealm().createChildRealm();
return topLevelRealm(getContext()).getIndexFromRealmList(newRealm);
}
}
public abstract static class RealmDisposeNode extends JSBuiltinNode {
public RealmDisposeNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@TruffleBoundary
@Specialization
protected Object dispose(Object index) {
JSRealm topLevelRealm = topLevelRealm(getContext());
int realmIndex = toRealmIndexOrThrow(topLevelRealm, index);
topLevelRealm.removeFromRealmList(realmIndex);
return Undefined.instance;
}
}
public abstract static class RealmGlobalNode extends JSBuiltinNode {
public RealmGlobalNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@TruffleBoundary
@Specialization
protected Object global(Object index) {
JSRealm topLevelRealm = topLevelRealm(getContext());
int realmIndex = toRealmIndexOrThrow(topLevelRealm, index);
JSRealm jsrealm = topLevelRealm.getFromRealmList(realmIndex);
return jsrealm.getGlobalObject();
}
}
public abstract static class RealmCurrentNode extends JSBuiltinNode {
public RealmCurrentNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@TruffleBoundary
@Specialization
protected Object current() {
JSRealm topLevelRealm = topLevelRealm(getContext());
return topLevelRealm.getIndexFromRealmList(topLevelRealm.getCurrentV8Realm());
}
}
public abstract static class RealmEvalNode extends JSBuiltinNode {
public RealmEvalNode(JSContext context, JSBuiltin builtin) {
super(context, builtin);
}
@TruffleBoundary
@Specialization
protected Object eval(Object index, Object code) {
JSRealm topLevelRealm = topLevelRealm(getContext());
int realmIndex = toRealmIndexOrThrow(topLevelRealm, index);
JSRealm jsrealm = topLevelRealm.getFromRealmList(realmIndex);
String sourceText = JSRuntime.toString(code);
Source source = Source.newBuilder(JavaScriptLanguage.ID, sourceText, Evaluator.EVAL_SOURCE_NAME).build();
JSRealm currentV8Realm = topLevelRealm.getCurrentV8Realm();
try {
topLevelRealm.setCurrentV8Realm(jsrealm);
return jsrealm.getContext().getEvaluator().evaluate(jsrealm, this, source);
} finally {
topLevelRealm.setCurrentV8Realm(currentV8Realm);
}
}
}
}