package com.oracle.truffle.api.test.polyglot;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.graalvm.options.OptionCategory;
import org.graalvm.options.OptionDescriptors;
import org.graalvm.options.OptionKey;
import org.graalvm.options.OptionValues;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Engine;
import org.graalvm.polyglot.Source;
import org.graalvm.polyglot.Value;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.Option;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.TruffleContext;
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.TruffleLanguage.ContextPolicy;
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
import com.oracle.truffle.api.TruffleLanguage.Env;
import com.oracle.truffle.api.TruffleLanguage.LanguageReference;
import com.oracle.truffle.api.TruffleLanguage.Registration;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.GenerateUncached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.ArityException;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.interop.UnsupportedTypeException;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.test.CompileImmediatelyCheck;
import com.oracle.truffle.api.test.polyglot.ContextPolicyTestFactory.SupplierAccessorNodeGen;
public class ContextPolicyTest {
private static final String EXCLUSIVE0 = "ExclusiveLanguage0";
private static final String REUSE0 = "ReuseLanguage0";
private static final String SHARED0 = "SharedLanguage0";
private static final String EXCLUSIVE1 = "ExclusiveLanguage1";
private static final String REUSE1 = "ReuseLanguage1";
private static final String SHARED1 = "SharedLanguage1";
private static final String RUN_INNER_CONTEXT = "runInInnerContext";
static List<TruffleLanguage<?>> languageInstances = new ArrayList<>();
static List<TruffleLanguage<?>> contextCreate = new ArrayList<>();
static List<TruffleLanguage<?>> contextDispose = new ArrayList<>();
static List<TruffleLanguage<?>> parseRequest = new ArrayList<>();
@After
@Before
public void cleanup() {
languageInstances.clear();
contextCreate.clear();
contextDispose.clear();
parseRequest.clear();
}
@Test
public void testOneLanguageASTParsing() {
Source source0 = Source.create(EXCLUSIVE0, "s0");
Source source1 = Source.create(EXCLUSIVE0, "s1");
Engine engine = Engine.create();
Context context0 = Context.newBuilder().engine(engine).build();
context0.eval(source0);
context0.eval(source1);
assertEquals(2, parseRequest.size());
context0.close();
Context context1 = Context.newBuilder().engine(engine).build();
context1.eval(source0);
context1.eval(source1);
assertEquals(4, parseRequest.size());
engine.close();
}
@Test
public void testManyLanguageASTParsing() {
Source source0 = Source.create(SHARED0, "s0");
Source source1 = Source.create(SHARED0, "s1");
Engine engine = Engine.create();
Context context0 = Context.newBuilder().engine(engine).allowExperimentalOptions(true).option(SHARED0 + ".Dummy", "1").build();
context0.eval(source0);
context0.eval(source1);
assertEquals(2, parseRequest.size());
context0.close();
Context context1 = Context.newBuilder().engine(engine).allowExperimentalOptions(true).option(SHARED0 + ".Dummy", "1").build();
context1.eval(source0);
context1.eval(source1);
assertEquals(2, parseRequest.size());
engine.close();
cleanup();
engine = Engine.create();
context0 = Context.newBuilder().engine(engine).allowExperimentalOptions(true).option(SHARED0 + ".Dummy", "1").build();
context0.eval(source0);
context0.eval(source1);
assertEquals(2, parseRequest.size());
context0.close();
context1 = Context.newBuilder().engine(engine).allowExperimentalOptions(true).option(SHARED0 + ".Dummy", "2").build();
context1.eval(source0);
context1.eval(source1);
assertEquals(4, parseRequest.size());
engine.close();
}
@Test
public void testOneReuseLanguageASTParsing() {
Source source0 = Source.create(REUSE0, "s0");
Source source1 = Source.create(REUSE0, "s1");
Engine engine = Engine.create();
Context context0 = Context.newBuilder().engine(engine).allowExperimentalOptions(true).option(REUSE0 + ".Dummy", "1").build();
context0.eval(source0);
context0.eval(source1);
assertEquals(2, parseRequest.size());
context0.close();
Context context1 = Context.newBuilder().engine(engine).allowExperimentalOptions(true).option(REUSE0 + ".Dummy", "1").build();
context1.eval(source0);
context1.eval(source1);
assertEquals(2, parseRequest.size());
context1.close();
Context context2 = Context.newBuilder().engine(engine).allowExperimentalOptions(true).option(REUSE0 + ".Dummy", "2").build();
context2.eval(source0);
context2.eval(source1);
assertEquals(4, parseRequest.size());
context1.close();
engine.close();
}
@Test
public void testOptionDescriptorContextReuse() {
Engine engine = Engine.create();
assertEquals(0, languageInstances.size());
engine.getLanguages().get(EXCLUSIVE0).getOptions();
assertEquals(1, languageInstances.size());
Context.newBuilder().engine(engine).build().initialize(EXCLUSIVE0);
assertEquals(1, languageInstances.size());
Context.newBuilder().engine(engine).build().initialize(EXCLUSIVE0);
assertEquals(2, languageInstances.size());
engine.close();
cleanup();
engine = Engine.create();
assertEquals(0, languageInstances.size());
engine.getLanguages().get(REUSE0).getOptions();
assertEquals(1, languageInstances.size());
Context context0 = Context.newBuilder().engine(engine).build();
context0.initialize(REUSE0);
assertEquals(1, languageInstances.size());
context0.close();
Context.newBuilder().engine(engine).build().initialize(REUSE0);
assertEquals(1, languageInstances.size());
Context.newBuilder().engine(engine).build().initialize(REUSE0);
assertEquals(2, languageInstances.size());
engine.close();
cleanup();
engine = Engine.create();
assertEquals(0, languageInstances.size());
engine.getLanguages().get(SHARED0).getOptions();
assertEquals(1, languageInstances.size());
Context.newBuilder().engine(engine).build().initialize(SHARED0);
assertEquals(1, languageInstances.size());
Context.newBuilder().engine(engine).build().initialize(SHARED0);
assertEquals(1, languageInstances.size());
engine.close();
}
@Test
public void testOneContext() {
Engine engine = Engine.create();
Source source0 = Source.create(EXCLUSIVE0, "s0");
Source source1 = Source.create(EXCLUSIVE0, "s1");
Context context0 = Context.newBuilder().engine(engine).build();
assertEmpty();
context0.initialize(EXCLUSIVE0);
assertEquals(1, languageInstances.size());
assertEquals(1, contextCreate.size());
assertEquals(0, contextDispose.size());
assertEquals(0, parseRequest.size());
assertSame(languageInstances.get(0), contextCreate.get(0));
Context context1 = Context.newBuilder().engine(engine).build();
context1.initialize(EXCLUSIVE0);
assertEquals(2, languageInstances.size());
assertEquals(2, contextCreate.size());
assertEquals(0, contextDispose.size());
assertEquals(0, parseRequest.size());
assertSame(languageInstances.get(1), contextCreate.get(1));
context0.eval(source0);
assertEquals(1, parseRequest.size());
assertSame(languageInstances.get(0), parseRequest.get(0));
context0.eval(source0);
assertEquals(1, parseRequest.size());
assertSame(languageInstances.get(0), parseRequest.get(0));
context1.eval(source0);
assertEquals(2, parseRequest.size());
assertSame(languageInstances.get(1), parseRequest.get(1));
context1.eval(source0);
assertEquals(2, parseRequest.size());
assertSame(languageInstances.get(1), parseRequest.get(1));
context0.eval(source1);
assertEquals(3, parseRequest.size());
assertSame(languageInstances.get(0), parseRequest.get(2));
context0.eval(source1);
assertEquals(3, parseRequest.size());
assertSame(languageInstances.get(0), parseRequest.get(2));
context1.eval(source1);
assertEquals(4, parseRequest.size());
assertSame(languageInstances.get(1), parseRequest.get(3));
context1.eval(source1);
assertEquals(4, parseRequest.size());
assertSame(languageInstances.get(1), parseRequest.get(3));
assertEquals(0, contextDispose.size());
context0.close();
assertEquals(1, contextDispose.size());
assertSame(languageInstances.get(0), contextDispose.get(0));
context1.close();
assertEquals(2, contextDispose.size());
assertSame(languageInstances.get(1), contextDispose.get(1));
assertEquals(2, languageInstances.size());
assertEquals(2, contextCreate.size());
engine.close();
}
@Test
public void testOneParseCaching() {
}
@Test
public void testOneReuseContext() {
Engine engine = Engine.create();
Source source0 = Source.create(REUSE0, "s0");
Source source1 = Source.create(REUSE0, "s1");
Context context0 = Context.newBuilder().engine(engine).build();
assertEmpty();
context0.initialize(REUSE0);
assertEquals(1, languageInstances.size());
assertEquals(1, contextCreate.size());
assertEquals(0, contextDispose.size());
assertEquals(0, parseRequest.size());
assertSame(languageInstances.get(0), contextCreate.get(0));
Context context1 = Context.newBuilder().engine(engine).build();
context1.initialize(REUSE0);
assertEquals(2, languageInstances.size());
assertEquals(2, contextCreate.size());
assertEquals(0, contextDispose.size());
assertEquals(0, parseRequest.size());
assertSame(languageInstances.get(1), contextCreate.get(1));
context0.eval(source0);
assertEquals(1, parseRequest.size());
assertSame(languageInstances.get(0), parseRequest.get(0));
context0.eval(source0);
assertEquals(1, parseRequest.size());
assertSame(languageInstances.get(0), parseRequest.get(0));
context1.eval(source1);
assertEquals(2, parseRequest.size());
assertSame(languageInstances.get(1), parseRequest.get(1));
context1.eval(source1);
assertEquals(2, parseRequest.size());
assertSame(languageInstances.get(1), parseRequest.get(1));
context1.close();
Context context2 = Context.newBuilder().engine(engine).build();
context2.initialize(REUSE0);
assertEquals(2, languageInstances.size());
assertEquals(3, contextCreate.size());
assertEquals(1, contextDispose.size());
assertEquals(2, parseRequest.size());
context2.eval(source1);
assertEquals(2, parseRequest.size());
context2.eval(source0);
assertEquals(3, parseRequest.size());
assertSame(languageInstances.get(1), parseRequest.get(2));
Context context3 = Context.newBuilder().engine(engine).build();
context0.close();
context3.initialize(REUSE0);
context3.eval(source0);
assertEquals(3, parseRequest.size());
context3.close();
context2.close();
assertEquals(2, languageInstances.size());
assertEquals(4, contextCreate.size());
assertEquals(4, contextDispose.size());
engine.close();
}
@Test
public void testManyContext() {
Engine engine = Engine.create();
Source source0 = Source.create(SHARED0, "s0");
Source source1 = Source.create(SHARED0, "s1");
Context context0 = Context.newBuilder().engine(engine).build();
Context context1 = Context.newBuilder().engine(engine).build();
assertEmpty();
context0.initialize(SHARED0);
assertEquals(1, languageInstances.size());
assertEquals(1, contextCreate.size());
assertEquals(0, contextDispose.size());
assertEquals(0, parseRequest.size());
assertSame(languageInstances.get(0), contextCreate.get(0));
context1.initialize(SHARED0);
assertEquals(1, languageInstances.size());
assertEquals(2, contextCreate.size());
assertEquals(0, contextDispose.size());
assertEquals(0, parseRequest.size());
assertSame(languageInstances.get(0), contextCreate.get(1));
context0.eval(source0);
assertEquals(1, parseRequest.size());
assertSame(languageInstances.get(0), parseRequest.get(0));
context0.eval(source0);
assertEquals(1, parseRequest.size());
context1.eval(source0);
assertEquals(1, parseRequest.size());
context1.eval(source0);
assertEquals(1, parseRequest.size());
context0.eval(source1);
assertEquals(2, parseRequest.size());
assertSame(languageInstances.get(0), parseRequest.get(1));
context0.eval(source1);
assertEquals(2, parseRequest.size());
context1.eval(source1);
assertEquals(2, parseRequest.size());
context1.eval(source1);
assertEquals(2, parseRequest.size());
assertEquals(0, contextDispose.size());
context0.close();
assertEquals(1, contextDispose.size());
assertSame(languageInstances.get(0), contextDispose.get(0));
context1.close();
assertEquals(1, languageInstances.size());
assertEquals(2, contextCreate.size());
assertEquals(2, contextDispose.size());
assertSame(languageInstances.get(0), contextDispose.get(0));
engine.close();
}
private static void assertEmpty() {
assertEquals(0, languageInstances.size());
assertEquals(0, contextCreate.size());
assertEquals(0, contextDispose.size());
assertEquals(0, parseRequest.size());
}
@Test
public void testReferencesWithCodeMixing() {
Assume.assumeFalse(CompileImmediatelyCheck.isCompileImmediately());
testReferenceMixing(EXCLUSIVE0, EXCLUSIVE1);
testReferenceMixing(EXCLUSIVE0, SHARED1);
testReferenceMixing(EXCLUSIVE0, REUSE1);
testReferenceMixing(REUSE0, EXCLUSIVE1);
testReferenceMixing(REUSE0, REUSE1);
testReferenceMixing(REUSE0, SHARED1);
testReferenceMixing(SHARED0, EXCLUSIVE1);
testReferenceMixing(SHARED0, REUSE1);
testReferenceMixing(SHARED0, SHARED1);
}
private static void testReferenceMixing(String language0, String language1) {
testReferenceMixingWithSourcesAndCompatibility(language0, language1, true, true);
testReferenceMixingWithSourcesAndCompatibility(language0, language1, false, true);
testReferenceMixingWithSourcesAndCompatibility(language0, language1, true, false);
testReferenceMixingWithSourcesAndCompatibility(language0, language1, false, false);
}
private static void testReferenceMixingWithSourcesAndCompatibility(String language0, String language1,
boolean language0Compatible,
boolean language1Compatible) {
testReferenceMixingWithSources(
Source.newBuilder(language0, "s0", "").cached(true).buildLiteral(),
Source.newBuilder(language1, "s0", "").cached(true).buildLiteral(),
language0Compatible, language1Compatible);
testReferenceMixingWithSources(
Source.newBuilder(language0, "s1", "").cached(false).buildLiteral(),
Source.newBuilder(language1, "s1", "").cached(true).buildLiteral(),
language0Compatible, language1Compatible);
testReferenceMixingWithSources(
Source.newBuilder(language0, "s2", "").cached(false).buildLiteral(),
Source.newBuilder(language1, "s2", "").cached(false).buildLiteral(),
language0Compatible, language1Compatible);
testReferenceMixingWithSources(
Source.newBuilder(language0, "s0", RUN_INNER_CONTEXT).cached(true).buildLiteral(),
Source.newBuilder(language1, "s0", RUN_INNER_CONTEXT).cached(true).buildLiteral(),
language0Compatible, language1Compatible);
testReferenceMixingWithSources(
Source.newBuilder(language0, "s1", RUN_INNER_CONTEXT).cached(false).buildLiteral(),
Source.newBuilder(language1, "s1", RUN_INNER_CONTEXT).cached(true).buildLiteral(),
language0Compatible, language1Compatible);
testReferenceMixingWithSources(
Source.newBuilder(language0, "s2", RUN_INNER_CONTEXT).cached(false).buildLiteral(),
Source.newBuilder(language1, "s2", RUN_INNER_CONTEXT).cached(false).buildLiteral(),
language0Compatible, language1Compatible);
}
private static void testReferenceMixingWithSources(Source sl0, Source sl1, boolean language0Compatible,
boolean language1Compatible) {
testReferenceMixingWithSourcesBound(sl0, sl1, language0Compatible, language1Compatible, false, false);
testReferenceMixingWithSourcesBound(sl0, sl1, language0Compatible, language1Compatible, true, false);
testReferenceMixingWithSourcesBound(sl0, sl1, language0Compatible, language1Compatible, false, true);
testReferenceMixingWithSourcesBound(sl0, sl1, language0Compatible, language1Compatible, true, true);
}
private static void testReferenceMixingWithSourcesBound(Source sl0, Source sl1, boolean language0Compatible, boolean language1Compatible,
boolean sharedContext1,
boolean sharedContext2) {
try (Engine engine = Engine.create()) {
Context.Builder b0 = Context.newBuilder().allowExperimentalOptions(true);
if (!sharedContext1) {
b0.engine(engine);
}
if (!language0Compatible) {
b0.option(sl0.getLanguage() + ".Dummy", "0");
}
try (Context c0 = b0.build()) {
Value v0l0 = c0.eval(sl0);
Value v0l1 = c0.eval(sl1);
v0l1.execute(v0l1, v0l0, v0l0);
v0l1.execute(v0l0, v0l1, v0l1);
v0l0.execute(v0l1, v0l0);
v0l0.execute(v0l0, v0l1);
}
Context.Builder b1 = Context.newBuilder().allowExperimentalOptions(true);
if (!sharedContext2) {
b1.engine(engine);
}
if (!language1Compatible) {
b1.option(sl1.getLanguage() + ".Dummy", "1");
}
try (Context c1 = b1.build()) {
Value v1l0 = c1.eval(sl0);
Value v1l1 = c1.eval(sl1);
v1l1.execute(v1l1, v1l0, v1l0);
v1l1.execute(v1l0, v1l1, v1l1);
v1l0.execute(v1l1, v1l0);
v1l0.execute(v1l0, v1l1);
}
}
try (Engine engine = Engine.create()) {
Context.Builder b0 = Context.newBuilder().allowExperimentalOptions(true);
if (!sharedContext1) {
b0.engine(engine);
}
if (!language0Compatible) {
b0.option(sl0.getLanguage() + ".Dummy", "0");
}
Context.Builder b1 = Context.newBuilder().allowExperimentalOptions(true);
if (!sharedContext2) {
b1.engine(engine);
}
if (!language1Compatible) {
b1.option(sl1.getLanguage() + ".Dummy", "1");
}
try (Context c0 = b0.build();
Context c1 = b1.build()) {
Value v0l0 = c0.eval(sl0);
Value v0l1 = c0.eval(sl1);
Value v1l0 = c1.eval(sl0);
Value v1l1 = c1.eval(sl1);
v0l1.execute(v0l1, v0l0, v0l0);
v0l1.execute(v0l0, v0l1, v0l1);
v1l1.execute(v1l1, v1l0, v1l0);
v1l1.execute(v1l0, v1l1, v1l1);
v0l0.execute(v0l1, v0l0);
v0l0.execute(v0l0, v0l1);
v1l0.execute(v1l1, v1l0);
v1l0.execute(v1l0, v1l1);
}
}
}
@GenerateUncached
abstract static class SupplierAccessor extends Node {
@SuppressWarnings("rawtypes")
public final <T extends TruffleLanguage> LanguageReference<T> getLanguageReference0(Class<T> languageClass) {
return lookupLanguageReference(languageClass);
}
public final <C, T extends TruffleLanguage<C>> ContextReference<C> getContextReference0(Class<T> languageClass) {
return lookupContextReference(languageClass);
}
public abstract void execute();
@Specialization
void s0() {
}
}
@ExportLibrary(InteropLibrary.class)
static class SharedObject implements TruffleObject {
final TruffleContext context;
final TruffleLanguage<?> expectedLanguage;
final Env expectedEnvironment;
final CallTarget target;
@TruffleBoundary
SharedObject(TruffleContext context, TruffleLanguage<?> language, Env env) {
this.context = context;
this.expectedLanguage = language;
this.expectedEnvironment = env;
this.target = Truffle.getRuntime().createCallTarget(new RootNode(language) {
@Child InteropLibrary library = InteropLibrary.getFactory().createDispatched(5);
@Child SupplierAccessor accessor = SupplierAccessorNodeGen.create();
@CompilationFinal private LanguageReference<? extends Object> cachedLanguageReference;
@CompilationFinal private ContextReference<? extends Object> cachedContextReference;
@SuppressWarnings("unchecked")
@Override
public Object execute(VirtualFrame frame) {
if (cachedLanguageReference == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
cachedLanguageReference = lookupLanguageReference0(accessor);
}
if (cachedContextReference == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
cachedContextReference = lookupContextReference0(accessor);
}
Object[] args = frame.getArguments();
doAssertions(accessor, cachedLanguageReference, cachedContextReference);
if (args.length > 0) {
try {
return library.execute(args[0], Arrays.copyOfRange(args, 1, args.length));
} catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) {
CompilerDirectives.transferToInterpreter();
throw new AssertionError();
}
} else {
return "done";
}
}
});
}
@ExportMessage
boolean accepts(@Cached(value = "this.expectedLanguage.getClass()", allowUncached = true) Class<?> cachedLanguageclass) {
return expectedLanguage.getClass() == cachedLanguageclass;
}
@ExportMessage
boolean isExecutable() {
return true;
}
@SuppressWarnings("unchecked")
@ExportMessage
Object execute(Object[] args,
@CachedLibrary(limit = "5") InteropLibrary library,
@Cached SupplierAccessor accessor,
@Cached(value = "this.lookupLanguageReference0(accessor)", allowUncached = true) LanguageReference<? extends Object> cachedLanguageSupplier,
@Cached(value = "this.lookupContextReference0(accessor)", allowUncached = true) ContextReference<? extends Object> cachedContextSupplier,
@Cached(value = "this.getContextReference()", allowUncached = true) ContextReference<Env> contextReference)
throws UnsupportedTypeException, ArityException, UnsupportedMessageException {
Object prev = enterInner();
try {
doAssertions(accessor, cachedLanguageSupplier, cachedContextSupplier, contextReference);
target.call(args);
if (args.length > 0) {
return library.execute(args[0], Arrays.copyOfRange(args, 1, args.length));
} else {
return "done";
}
} finally {
leaveInner(prev);
}
}
@TruffleBoundary
private void doAssertions(SupplierAccessor accessor, LanguageReference<? extends Object> cachedLanguageSupplier, ContextReference<? extends Object> cachedContextSupplier,
ContextReference<Env> contextReference) {
doAssertions(accessor, cachedLanguageSupplier, cachedContextSupplier);
assertSame(expectedEnvironment, contextReference.get());
}
@TruffleBoundary
private void doAssertions(SupplierAccessor accessor, LanguageReference<? extends Object> cachedLanguageSupplier, ContextReference<? extends Object> cachedContextSupplier) {
assertSame(expectedLanguage, lookupLanguageReference0(accessor).get());
assertSame(expectedEnvironment, lookupContextReference0(accessor).get());
assertSame(expectedLanguage, cachedLanguageSupplier.get());
assertSame(expectedEnvironment, cachedContextSupplier.get());
assertSame(cachedLanguageSupplier, lookupLanguageReference0(accessor));
assertSame(cachedContextSupplier, lookupContextReference0(accessor));
}
@TruffleBoundary
private void leaveInner(Object prev) {
if (context != null) {
context.leave(null, prev);
}
}
@TruffleBoundary
@SuppressWarnings("unchecked")
private Object enterInner() {
Object prev = null;
if (context != null) {
prev = context.enter(null);
assertSame(expectedLanguage, ExclusiveLanguage0.getCurrentLanguage(expectedLanguage.getClass()));
assertSame(expectedEnvironment, ExclusiveLanguage0.getCurrentContext(expectedLanguage.getClass()));
}
return prev;
}
@TruffleBoundary
private void doAssertions(LanguageReference<?> languageSupplier) {
assertSame(expectedLanguage, ExclusiveLanguage0.getCurrentLanguage(expectedLanguage.getClass()));
assertSame(languageSupplier.get(), expectedLanguage);
}
@SuppressWarnings("rawtypes")
LanguageReference<? extends Object> lookupLanguageReference0(SupplierAccessor node) {
Object prev = enterInner();
try {
LanguageReference<?> o = node.getLanguageReference0(expectedLanguage.getClass());
doAssertions(o);
return o;
} finally {
leaveInner(prev);
}
}
@SuppressWarnings({"rawtypes", "unchecked", "deprecation"})
ContextReference<Env> getContextReference() {
Object prev = enterInner();
try {
return ExclusiveLanguage0.getCurrentLanguage(expectedLanguage.getClass()).getContextReference();
} finally {
leaveInner(prev);
}
}
@SuppressWarnings("unchecked")
ContextReference<? extends Object> lookupContextReference0(SupplierAccessor node) {
Object prev = enterInner();
try {
return node.getContextReference0(expectedLanguage.getClass());
} finally {
leaveInner(prev);
}
}
}
static class LanguageRootNode extends RootNode {
private final Class<? extends TruffleLanguage<Env>> languageClass;
private final boolean innerContext;
@SuppressWarnings("unchecked")
protected LanguageRootNode(TruffleLanguage<?> language, boolean innerContext) {
super(language);
this.languageClass = (Class<? extends TruffleLanguage<Env>>) language.getClass();
this.innerContext = innerContext;
}
@Override
public Object execute(VirtualFrame frame) {
Env env = ExclusiveLanguage0.getCurrentContext(languageClass);
TruffleContext context = null;
if (innerContext) {
context = env.newContextBuilder().build();
}
Object prev = null;
if (context != null) {
prev = context.enter(this);
}
try {
SharedObject obj = new SharedObject(
context,
ExclusiveLanguage0.getCurrentLanguage(languageClass),
ExclusiveLanguage0.getCurrentContext(languageClass));
return obj;
} finally {
if (context != null) {
context.leave(this, prev);
}
}
}
}
@Registration(id = EXCLUSIVE0, name = EXCLUSIVE0, contextPolicy = ContextPolicy.EXCLUSIVE)
public static class ExclusiveLanguage0 extends TruffleLanguage<Env> {
public ExclusiveLanguage0() {
languageInstances.add(this);
}
@Option(help = "", category = OptionCategory.INTERNAL)
static final OptionKey<Integer> Dummy = new OptionKey<>(0);
@Override
protected OptionDescriptors getOptionDescriptors() {
return new ExclusiveLanguage0OptionDescriptors();
}
@Override
protected CallTarget parse(ParsingRequest request) throws Exception {
parseRequest.add(this);
boolean innerContext = request.getSource().getName().equals(RUN_INNER_CONTEXT);
return Truffle.getRuntime().createCallTarget(new LanguageRootNode(this, innerContext));
}
@Override
protected Env createContext(Env env) {
contextCreate.add(this);
return env;
}
@Override
protected void disposeContext(Env context) {
contextDispose.add(this);
}
@TruffleBoundary
public static <T extends TruffleLanguage<?>> T getCurrentLanguage(Class<T> languageClass) {
return TruffleLanguage.getCurrentLanguage(languageClass);
}
@TruffleBoundary
public static <C, T extends TruffleLanguage<C>> C getCurrentContext(Class<T> languageClass) {
return TruffleLanguage.getCurrentContext(languageClass);
}
}
@Registration(id = EXCLUSIVE1, name = EXCLUSIVE1, contextPolicy = ContextPolicy.EXCLUSIVE)
public static class ExclusiveLanguage1 extends ExclusiveLanguage0 {
@Option(help = "", category = OptionCategory.INTERNAL)
static final OptionKey<Integer> Dummy = new OptionKey<>(0);
@Override
protected boolean areOptionsCompatible(OptionValues firstOptions, OptionValues newOptions) {
return firstOptions.get(Dummy).equals(newOptions.get(Dummy));
}
@Override
protected OptionDescriptors getOptionDescriptors() {
return new ExclusiveLanguage1OptionDescriptors();
}
}
@Registration(id = REUSE0, name = REUSE0, contextPolicy = ContextPolicy.REUSE)
public static class ReuseLanguage0 extends ExclusiveLanguage0 {
@Option(help = "", category = OptionCategory.INTERNAL)
static final OptionKey<Integer> Dummy = new OptionKey<>(0);
@Override
protected boolean areOptionsCompatible(OptionValues firstOptions, OptionValues newOptions) {
return firstOptions.get(Dummy).equals(newOptions.get(Dummy));
}
@Override
protected OptionDescriptors getOptionDescriptors() {
return new ReuseLanguage0OptionDescriptors();
}
}
@Registration(id = REUSE1, name = REUSE1, contextPolicy = ContextPolicy.REUSE)
public static class ReuseLanguage1 extends ExclusiveLanguage0 {
@Option(help = "", category = OptionCategory.INTERNAL)
static final OptionKey<Integer> Dummy = new OptionKey<>(0);
@Override
protected boolean areOptionsCompatible(OptionValues firstOptions, OptionValues newOptions) {
return firstOptions.get(Dummy).equals(newOptions.get(Dummy));
}
@Override
protected OptionDescriptors getOptionDescriptors() {
return new ReuseLanguage1OptionDescriptors();
}
}
@Registration(id = SHARED0, name = SHARED0, contextPolicy = ContextPolicy.SHARED)
public static class SharedLanguage0 extends ExclusiveLanguage0 {
@Option(help = "", category = OptionCategory.INTERNAL)
static final OptionKey<Integer> Dummy = new OptionKey<>(0);
@Override
protected boolean areOptionsCompatible(OptionValues firstOptions, OptionValues newOptions) {
return firstOptions.get(Dummy).equals(newOptions.get(Dummy));
}
@Override
protected OptionDescriptors getOptionDescriptors() {
return new SharedLanguage0OptionDescriptors();
}
}
@Registration(id = SHARED1, name = SHARED1, contextPolicy = ContextPolicy.SHARED)
public static class SharedLanguage1 extends ExclusiveLanguage0 {
@Option(help = "", category = OptionCategory.INTERNAL)
static final OptionKey<Integer> Dummy = new OptionKey<>(0);
@Override
protected boolean areOptionsCompatible(OptionValues firstOptions, OptionValues newOptions) {
return firstOptions.get(Dummy).equals(newOptions.get(Dummy));
}
@Override
protected OptionDescriptors getOptionDescriptors() {
return new SharedLanguage1OptionDescriptors();
}
}
}