Skip to content

Commit

Permalink
Add Polyglot Support in Runtime Tests (#4016)
Browse files Browse the repository at this point in the history
`runtime-with-instruments` project sets `-Dgraalvm.locatorDisabled=true` that disables the discovery of available polyglot languages (installed with `gu`). On the other hand, enabling locator makes polyglot languages available, but also makes the program classes and the test classes loaded with different classloaders. This way we're unable to use `EnsoContext` in tests to observe internal context state (there is an exception when you try to cast to `EnsoContext`).

The solution is to move tests with enabled polyglot support, but disabled `EnsoContext` introspection to a separate project.
  • Loading branch information
4e6 authored Jan 3, 2023
1 parent 1e5e232 commit 9df6448
Show file tree
Hide file tree
Showing 13 changed files with 104 additions and 128 deletions.
49 changes: 49 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ lazy val enso = (project in file("."))
`runtime-instrument-repl-debugger`,
`runtime-instrument-runtime-server`,
`runtime-with-instruments`,
`runtime-with-polyglot`,
`runtime-version-manager`,
`runtime-version-manager-test`,
editions,
Expand Down Expand Up @@ -1143,6 +1144,7 @@ lazy val `polyglot-api` = project
},
libraryDependencies ++= Seq(
"org.graalvm.sdk" % "polyglot-tck" % graalVersion % "provided",
"org.graalvm.truffle" % "truffle-api" % graalVersion % "provided",
"com.google.flatbuffers" % "flatbuffers-java" % flatbuffersVersion,
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
"org.scalacheck" %% "scalacheck" % scalacheckVersion % Test
Expand Down Expand Up @@ -1569,6 +1571,53 @@ lazy val `runtime-with-instruments` =
.dependsOn(`runtime-instrument-repl-debugger`)
.dependsOn(`runtime-instrument-runtime-server`)

/* runtime-with-polyglot
* ~~~~~~~~~~~~~~~~~~~~~
* A project that allows loading polyglot languages by not disabling
* the GraalVM locator explicitly with `-Dgraalvm.locatorDisabled=true` like the
* `runtime-with-instruments` project does. It means that the test classes and
* runtime classes are loaded using different classloaders, and the test code
* cannot access the `EnsoContext`.
*/

lazy val `runtime-with-polyglot` =
(project in file("engine/runtime-with-polyglot"))
.configs(Benchmark)
.settings(
frgaalJavaCompilerSetting,
inConfig(Compile)(truffleRunOptionsSettings),
inConfig(Benchmark)(Defaults.testSettings),
commands += WithDebugCommand.withDebug,
Benchmark / javacOptions --= Seq(
"-source",
frgaalSourceLevel,
"--enable-preview"
),
Test / javaOptions ++= {
// Note [Classpath Separation]
val runtimeClasspath =
(LocalProject("runtime") / Compile / fullClasspath).value
val runtimeInstrumentsClasspath =
(LocalProject("runtime-with-instruments") / Compile / fullClasspath).value
val appendClasspath =
(runtimeClasspath ++ runtimeInstrumentsClasspath)
.map(_.data)
.mkString(File.pathSeparator)
Seq(
s"-Dtruffle.class.path.append=$appendClasspath"
)
},
Test / fork := true,
Test / envVars ++= distributionEnvironmentOverrides ++ Map(
"ENSO_TEST_DISABLE_IR_CACHE" -> "false"
),
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % scalatestVersion % Test
)
)
.dependsOn(runtime % "compile->compile;test->test;runtime->runtime")
.dependsOn(`runtime-with-instruments`)

/* Note [Unmanaged Classpath]
* ~~~~~~~~~~~~~~~~~~~~~~~~~~
* As the definition of the core primitives in `core_definition` is achieved
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package org.enso.polyglot;

import java.util.Arrays;
import java.util.logging.Level;
import org.graalvm.options.OptionDescriptor;
import org.graalvm.options.OptionDescriptors;
import org.graalvm.options.OptionKey;

import org.graalvm.options.*;
import com.oracle.truffle.api.Option;

/** Class representing runtime options supported by the Enso engine. */
public class RuntimeOptions {
Expand Down Expand Up @@ -91,6 +90,16 @@ public class RuntimeOptions {
OptionDescriptor.newBuilder(USE_GLOBAL_IR_CACHE_LOCATION_KEY, USE_GLOBAL_IR_CACHE_LOCATION)
.build();

public static final String ENABLE_EXECUTION_TIMER = optionName("enableExecutionTimer");

@Option(
help = "Enables timer that counts down the execution time of expressions.",
category = OptionCategory.INTERNAL)
public static final OptionKey<Boolean> ENABLE_EXECUTION_TIMER_KEY = new OptionKey<>(true);

private static final OptionDescriptor ENABLE_EXECUTION_TIMER_DESCRIPTOR =
OptionDescriptor.newBuilder(ENABLE_EXECUTION_TIMER_KEY, ENABLE_EXECUTION_TIMER).build();

public static final OptionDescriptors OPTION_DESCRIPTORS =
OptionDescriptors.create(
Arrays.asList(
Expand All @@ -107,7 +116,8 @@ public class RuntimeOptions {
INTERPRETER_SEQUENTIAL_COMMAND_EXECUTION_DESCRIPTOR,
DISABLE_IR_CACHES_DESCRIPTOR,
WAIT_FOR_PENDING_SERIALIZATION_JOBS_DESCRIPTOR,
USE_GLOBAL_IR_CACHE_LOCATION_DESCRIPTOR));
USE_GLOBAL_IR_CACHE_LOCATION_DESCRIPTOR,
ENABLE_EXECUTION_TIMER_DESCRIPTOR));

/**
* Canonicalizes the option name by prefixing it with the language name.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
id = IdExecutionService.INSTRUMENT_ID,
services = IdExecutionService.class)
public class IdExecutionInstrument extends TruffleInstrument implements IdExecutionService {
private Timer timer;

private Env env;

/**
Expand All @@ -48,20 +48,9 @@ public class IdExecutionInstrument extends TruffleInstrument implements IdExecut
@Override
protected void onCreate(Env env) {
env.registerService(this);
this.timer = new Timer.Nanosecond();
this.env = env;
}

/**
* Override the default nanosecond timer with the specified {@code timer}.
*
* @param timer the timer to override with
*/
@Override
public void overrideTimer(Timer timer) {
this.timer = timer;
}

/** The listener class used by this instrument. */
private static class IdExecutionEventListener implements ExecutionEventListener {
private final CallTarget entryCallTarget;
Expand Down Expand Up @@ -305,6 +294,7 @@ private UUID getNodeId(Node node) {
* @param cache the precomputed expression values.
* @param methodCallsCache the storage tracking the executed method calls.
* @param syncState the synchronization state of runtime updates.
* @param timer the execution timer.
* @param nextExecutionItem the next item scheduled for execution.
* @param functionCallCallback the consumer of function call events.
* @param onComputedCallback the consumer of the computed value events.
Expand All @@ -319,6 +309,7 @@ public EventBinding<ExecutionEventListener> bind(
RuntimeCache cache,
MethodCallsCache methodCallsCache,
UpdatesSynchronizationState syncState,
Timer timer,
UUID nextExecutionItem,
Consumer<IdExecutionInstrument.ExpressionCall> functionCallCallback,
Consumer<IdExecutionInstrument.ExpressionValue> onComputedCallback,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package org.enso.interpreter.test.instrument

import org.enso.distribution.FileSystem
import org.enso.distribution.locking.ThreadSafeFileLockManager
import org.enso.interpreter.instrument.execution.Timer
import org.enso.interpreter.runtime.`type`.ConstantsGen
import org.enso.interpreter.runtime.EnsoContext
import org.enso.interpreter.test.Metadata
import org.enso.pkg.{Package, PackageManager}
import org.enso.polyglot._
Expand All @@ -24,12 +22,6 @@ class BuiltinTypesTest
with Matchers
with BeforeAndAfterEach {

// === Test Timer ===========================================================

class TestTimer extends Timer {
override def getTime(): Long = 0
}

// === Test Utilities =======================================================

var context: TestContext = _
Expand All @@ -56,6 +48,7 @@ class BuiltinTypesTest
.option(RuntimeOptions.INTERPRETER_SEQUENTIAL_COMMAND_EXECUTION, "true")
.option(RuntimeOptions.ENABLE_PROJECT_SUGGESTIONS, "false")
.option(RuntimeOptions.ENABLE_GLOBAL_SUGGESTIONS, "false")
.option(RuntimeOptions.ENABLE_EXECUTION_TIMER, "false")
.option(
RuntimeOptions.DISABLE_IR_CACHES,
InstrumentTestContext.DISABLE_IR_CACHE
Expand All @@ -77,14 +70,6 @@ class BuiltinTypesTest
)
executionContext.context.initialize(LanguageInfo.ID)

val languageContext = executionContext.context
.getBindings(LanguageInfo.ID)
.invokeMember(MethodNames.TopScope.LEAK_CONTEXT)
.asHostObject[EnsoContext]
languageContext.getLanguage.getIdExecutionService.ifPresent(
_.overrideTimer(new TestTimer)
);

def writeMain(contents: String): File =
Files.write(pkg.mainFile.toPath, contents.getBytes).toFile

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package org.enso.interpreter.test.instrument

import org.enso.distribution.FileSystem
import org.enso.distribution.locking.ThreadSafeFileLockManager
import org.enso.interpreter.instrument.execution.Timer
import org.enso.interpreter.test.Metadata
import org.enso.pkg.{Package, PackageManager}
import org.enso.polyglot._
Expand All @@ -23,12 +22,6 @@ class RuntimeAsyncCommandsTest
with Matchers
with BeforeAndAfterEach {

// === Test Timer ===========================================================

class TestTimer extends Timer {
override def getTime(): Long = 0
}

// === Test Utilities =======================================================

var context: TestContext = _
Expand Down Expand Up @@ -56,6 +49,7 @@ class RuntimeAsyncCommandsTest
)
.option(RuntimeOptions.ENABLE_PROJECT_SUGGESTIONS, "false")
.option(RuntimeOptions.ENABLE_GLOBAL_SUGGESTIONS, "false")
.option(RuntimeOptions.ENABLE_EXECUTION_TIMER, "false")
.option(
RuntimeOptions.DISABLE_IR_CACHES,
InstrumentTestContext.DISABLE_IR_CACHE
Expand All @@ -76,14 +70,6 @@ class RuntimeAsyncCommandsTest
)
executionContext.context.initialize(LanguageInfo.ID)

val languageContext = executionContext.context
.getBindings(LanguageInfo.ID)
.invokeMember(MethodNames.TopScope.LEAK_CONTEXT)
.asHostObject[org.enso.interpreter.runtime.EnsoContext]
languageContext.getLanguage.getIdExecutionService.ifPresent(
_.overrideTimer(new TestTimer)
)

def writeMain(contents: String): File =
Files.write(pkg.mainFile.toPath, contents.getBytes).toFile

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package org.enso.interpreter.test.instrument

import org.enso.distribution.FileSystem
import org.enso.distribution.locking.ThreadSafeFileLockManager
import org.enso.interpreter.instrument.execution.Timer
import org.enso.interpreter.runtime.`type`.ConstantsGen
import org.enso.interpreter.test.Metadata
import org.enso.pkg.{Package, PackageManager}
Expand All @@ -26,12 +25,6 @@ class RuntimeErrorsTest
with Matchers
with BeforeAndAfterEach {

// === Test Timer ===========================================================

class TestTimer extends Timer {
override def getTime(): Long = 0
}

// === Test Utilities =======================================================

var context: TestContext = _
Expand Down Expand Up @@ -61,6 +54,7 @@ class RuntimeErrorsTest
.option(RuntimeOptions.INTERPRETER_SEQUENTIAL_COMMAND_EXECUTION, "true")
.option(RuntimeOptions.ENABLE_PROJECT_SUGGESTIONS, "false")
.option(RuntimeOptions.ENABLE_GLOBAL_SUGGESTIONS, "false")
.option(RuntimeOptions.ENABLE_EXECUTION_TIMER, "false")
.option(
RuntimeOptions.DISABLE_IR_CACHES,
InstrumentTestContext.DISABLE_IR_CACHE
Expand All @@ -81,14 +75,6 @@ class RuntimeErrorsTest
)
executionContext.context.initialize(LanguageInfo.ID)

val languageContext = executionContext.context
.getBindings(LanguageInfo.ID)
.invokeMember(MethodNames.TopScope.LEAK_CONTEXT)
.asHostObject[org.enso.interpreter.runtime.EnsoContext]
languageContext.getLanguage.getIdExecutionService.ifPresent(
_.overrideTimer(new TestTimer)
)

def writeMain(contents: String): File =
Files.write(pkg.mainFile.toPath, contents.getBytes).toFile

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package org.enso.interpreter.test.instrument

import org.enso.distribution.FileSystem
import org.enso.distribution.locking.ThreadSafeFileLockManager
import org.enso.interpreter.instrument.execution.Timer
import org.enso.interpreter.runtime.`type`.{Constants, ConstantsGen}
import org.enso.interpreter.test.Metadata
import org.enso.pkg.{Package, PackageManager}
Expand All @@ -24,12 +23,6 @@ class RuntimeInstrumentTest
with Matchers
with BeforeAndAfterEach {

// === Test Timer ===========================================================

class TestTimer extends Timer {
override def getTime(): Long = 0
}

// === Test Utilities =======================================================

var context: TestContext = _
Expand All @@ -54,6 +47,7 @@ class RuntimeInstrumentTest
.option(RuntimeOptions.INTERPRETER_SEQUENTIAL_COMMAND_EXECUTION, "true")
.option(RuntimeOptions.ENABLE_PROJECT_SUGGESTIONS, "false")
.option(RuntimeOptions.ENABLE_GLOBAL_SUGGESTIONS, "false")
.option(RuntimeOptions.ENABLE_EXECUTION_TIMER, "false")
.option(
RuntimeOptions.DISABLE_IR_CACHES,
InstrumentTestContext.DISABLE_IR_CACHE
Expand All @@ -74,14 +68,6 @@ class RuntimeInstrumentTest
)
executionContext.context.initialize(LanguageInfo.ID)

val languageContext = executionContext.context
.getBindings(LanguageInfo.ID)
.invokeMember(MethodNames.TopScope.LEAK_CONTEXT)
.asHostObject[org.enso.interpreter.runtime.EnsoContext]
languageContext.getLanguage.getIdExecutionService.ifPresent(
_.overrideTimer(new TestTimer)
);

def writeMain(contents: String): File =
Files.write(pkg.mainFile.toPath, contents.getBytes).toFile

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package org.enso.interpreter.test.instrument

import org.enso.distribution.FileSystem
import org.enso.distribution.locking.ThreadSafeFileLockManager
import org.enso.interpreter.instrument.execution.Timer
import org.enso.interpreter.runtime.`type`.{ConstantsGen, Types}
import org.enso.interpreter.runtime.EnsoContext
import org.enso.interpreter.test.Metadata
Expand All @@ -27,12 +26,6 @@ class RuntimeServerTest
with Matchers
with BeforeAndAfterEach {

// === Test Timer ===========================================================

class TestTimer extends Timer {
override def getTime(): Long = 0
}

// === Test Utilities =======================================================

var context: TestContext = _
Expand All @@ -59,6 +52,7 @@ class RuntimeServerTest
.option(RuntimeOptions.INTERPRETER_SEQUENTIAL_COMMAND_EXECUTION, "true")
.option(RuntimeOptions.ENABLE_PROJECT_SUGGESTIONS, "false")
.option(RuntimeOptions.ENABLE_GLOBAL_SUGGESTIONS, "false")
.option(RuntimeOptions.ENABLE_EXECUTION_TIMER, "false")
.option(
RuntimeOptions.DISABLE_IR_CACHES,
InstrumentTestContext.DISABLE_IR_CACHE
Expand All @@ -84,11 +78,6 @@ class RuntimeServerTest
.getBindings(LanguageInfo.ID)
.invokeMember(MethodNames.TopScope.LEAK_CONTEXT)
.asHostObject[EnsoContext]
val info =
languageContext.getEnvironment.getPublicLanguages.get(LanguageInfo.ID)
languageContext.getLanguage.getIdExecutionService.ifPresent(
_.overrideTimer(new TestTimer)
)

def writeMain(contents: String): File =
Files.write(pkg.mainFile.toPath, contents.getBytes).toFile
Expand Down
Loading

0 comments on commit 9df6448

Please sign in to comment.