Skip to content

Commit

Permalink
Create new module org.enso.interpreter.test
Browse files Browse the repository at this point in the history
This module will contain all the truffle instruments required for testing
  • Loading branch information
Akirathan committed Dec 8, 2023
1 parent 0dd0056 commit 4a9c962
Show file tree
Hide file tree
Showing 21 changed files with 168 additions and 32 deletions.
77 changes: 65 additions & 12 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,10 @@ lazy val modulePathTestOptions =
val runtimeMod = (LocalProject(
"runtime-fat-jar"
) / Compile / productDirectories).value
val runtimeTestInstrModName =
(`runtime-test-instruments` / moduleInfos).value.head.moduleName
val runtimeTestInstrMod =
(`runtime-test-instruments` / Compile / productDirectories).value
val graalMods = graalModulesPaths.value
val graalLangMods = JPMSUtils.filterModulesFromUpdate(
updateReport,
Expand Down Expand Up @@ -605,9 +609,14 @@ lazy val modulePathTestOptions =
.mkString(File.pathSeparator)
val allModulesPaths: Seq[String] =
runtimeMod.map(_.getAbsolutePath) ++
runtimeTestInstrMod.map(_.getAbsolutePath) ++
graalMods.map(_.data.getAbsolutePath) ++
graalLangMods.map(_.getAbsolutePath) ++
loggingMods.map(_.getAbsolutePath)
val modulesToAdd = Seq(
runtimeModName,
runtimeTestInstrModName
)
// We can't use org.enso.logger.TestLogProvider (or anything from our own logging framework here) because it is not
// in a module, and it cannot be simple wrapped inside a module.
// So we use plain ch.qos.logback with its configuration.
Expand All @@ -620,11 +629,11 @@ lazy val modulePathTestOptions =
"--module-path",
allModulesPaths.mkString(File.pathSeparator),
"--add-modules",
runtimeModName,
modulesToAdd.mkString(","),
"--patch-module",
s"$runtimeModName=$patchStr",
"--add-reads",
s"$runtimeModName=ALL-UNNAMED"
s"$runtimeModName=ALL-UNNAMED,$runtimeTestInstrModName"
)
}

Expand Down Expand Up @@ -1503,6 +1512,40 @@ lazy val `runtime-language-epb` =
)
.dependsOn(`polyglot-api`)

/** This project contains only Truffle instruments that are used in various tests in `runtime-*`
* projects.
*/
lazy val `runtime-test-instruments` =
(project in file("engine/runtime-test-instruments"))
.settings(
inConfig(Compile)(truffleRunOptionsSettings),
instrumentationSettings,
// Needed to compile module-info.java
compileOrder := xsbti.compile.CompileOrder.JavaThenScala,
moduleInfos := Seq(
JpmsModule("org.enso.runtime.test.instrument")
),
libraryDependencies ++= {
GraalVM.modules.map(_.withConfigurations(Some(Compile.name)))
},
Compile / javacOptions ++= {
val updateReport = (Compile / update).value
val graalVmMods = JPMSUtils.filterModulesFromUpdate(
updateReport,
GraalVM.modules,
streams.value.log,
shouldContainAll = true
)
//val runtimeMod = (`runtime-fat-jar` / Compile / exportedProducts).value.head.data
//val allRequiredMods = graalVmMods ++ Seq(runtimeMod)
val allRequiredMods = graalVmMods
Seq(
"--module-path",
allRequiredMods.map(_.getAbsolutePath).mkString(File.pathSeparator)
)
}
)

lazy val runtime = (project in file("engine/runtime"))
.configs(Benchmark)
.settings(
Expand Down Expand Up @@ -1555,7 +1598,17 @@ lazy val runtime = (project in file("engine/runtime"))
GraalVM.toolsPkgs.map(_.withConfigurations(Some(Runtime.name)))
necessaryModules ++ langs ++ tools
},
Test / javaOptions := modulePathTestOptions.value,
Test / javaOptions := {
val prevOpts = modulePathTestOptions.value
// Append the `test-classes` directory of the current project to the `--patch-module` option.
// Otherwise, the test frameworks would be unable to load some testing classes as they are
// in the same package as some implementation classes (split packages).
val patchIdx = prevOpts.indexOf("--patch-module") + 1
val testClassesDir = (Test / productDirectories).value.head
val newPatchOpt =
prevOpts(patchIdx) + File.pathSeparator + testClassesDir.getAbsolutePath
prevOpts.updated(patchIdx, newPatchOpt)
},
Test / compile := (Test / compile)
.dependsOn(LocalProject("runtime-fat-jar") / Compile / compileModuleInfo)
.value,
Expand Down Expand Up @@ -1639,6 +1692,7 @@ lazy val runtime = (project in file("engine/runtime"))
.dependsOn(`connected-lock-manager`)
.dependsOn(testkit % Test)
.dependsOn(`logging-service-logback` % "test->test")
.dependsOn(`runtime-test-instruments` % "test->compile")

lazy val `runtime-parser` =
(project in file("engine/runtime-parser"))
Expand Down Expand Up @@ -1767,24 +1821,23 @@ lazy val `runtime-fat-jar` =
moduleInfos := Seq(
JpmsModule("org.enso.runtime")
),
compileOrder := CompileOrder.JavaThenScala,
compileOrder := CompileOrder.JavaThenScala
)
/**
* The following libraryDependencies are provided in Runtime scope.
* Later, we will collect them into --module-path option.
* We don't collect them in Compile scope as it does not even make sense
* to run `compile` task in this project.
*/
/** The following libraryDependencies are provided in Runtime scope.
* Later, we will collect them into --module-path option.
* We don't collect them in Compile scope as it does not even make sense
* to run `compile` task in this project.
*/
.settings(
libraryDependencies ++= {
val graalMods =
GraalVM.modules.map(_.withConfigurations(Some(Runtime.name)))
val langMods =
GraalVM.langsPkgs.map(_.withConfigurations(Some(Runtime.name)))
val logbackMods =
logbackPkg.map(_.withConfigurations(Some(Runtime.name)) )
logbackPkg.map(_.withConfigurations(Some(Runtime.name)))
graalMods ++ langMods ++ logbackMods
},
}
)
/** Assembling Uber Jar */
.settings(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module org.enso.runtime.test.instrument {
requires org.graalvm.truffle;
exports org.enso.interpreter.test.instrument;
provides com.oracle.truffle.api.instrumentation.provider.TruffleInstrumentProvider with
org.enso.interpreter.test.instrument.CodeLocationsTestInstrumentProvider,
org.enso.interpreter.test.instrument.CodeIdsTestInstrumentProvider;
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package org.enso.interpreter.test;
package org.enso.interpreter.test.instrument;

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.instrumentation.*;
import com.oracle.truffle.api.nodes.Node;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;
import org.enso.interpreter.node.ExpressionNode;
import org.enso.interpreter.runtime.control.TailCallException;

import java.util.UUID;

Expand Down Expand Up @@ -82,11 +82,34 @@ public ExecutionEventNode create(EventContext context) {
return node;
}

/**
* Uses reflection to get access to {@link org.enso.interpreter.node.ExpressionNode} and
* {@link org.enso.interpreter.runtime.control.TailCallException} classes. We need this because
* this instrument is not a part of the {@code org.enso.runtime} module, and thus cannot import these classes.
* It is part of {@code org.enso.runtime.test.instrument} module, which just provides few instruments
* for testing of the {@code org.enso.runtime} module.
*
* This is a hack to make the unit testing work and to remove the compile-time dependency on the
* {@code org.enso.runtime} module.
*/
private final class IdEventNode extends ExecutionEventNode {
private final EventContext context;
private final Class<?> expressionNodeClass;
private final Method expressionNodeGetIdMethod;
private final Class<?> tailCallExceptionClass;

IdEventNode(EventContext context) {
this.context = context;
try {
// Are there two ExpressionNode classes at this point? One loaded here and one loaded inside
// the runtime module?
this.expressionNodeClass = Class.forName("org.enso.interpreter.node.ExpressionNode");
this.tailCallExceptionClass =
Class.forName("org.enso.interpreter.runtime.control.TailCallException");
this.expressionNodeGetIdMethod = expressionNodeClass.getDeclaredMethod("getId");
} catch (ClassNotFoundException | NoSuchMethodException e) {
throw new AssertionError(e);
}
}

@Override
Expand All @@ -95,7 +118,6 @@ public void onEnter(VirtualFrame frame) {}
/**
* Checks if the node to be executed is the node this listener was created to observe.
*
* @param context current execution context
* @param frame current execution frame
* @param result the result of executing the node
*/
Expand All @@ -105,11 +127,11 @@ public void onReturnValue(VirtualFrame frame, Object result) {
return;
}
Node node = context.getInstrumentedNode();
if (!(node instanceof ExpressionNode)) {
if (!expressionNodeClass.isAssignableFrom(node.getClass())) {
return;
}
nodes.put(this, result);
UUID id = ((ExpressionNode) node).getId();
UUID id = getIdFromExpressionNode(node);
if (id == null || !id.equals(expectedId)) {
return;
}
Expand All @@ -118,22 +140,32 @@ public void onReturnValue(VirtualFrame frame, Object result) {
}
}

private UUID getIdFromExpressionNode(Node expressionNode) {
assert expressionNodeClass.isAssignableFrom(expressionNode.getClass());
Object res = null;
try {
res = expressionNodeGetIdMethod.invoke(expressionNode);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new AssertionError(e);
}
return (UUID) res;
}

/**
* Checks if the specified was called, if its execution triggered TCO.
*
* @param context current execution context.
* @param frame current execution frame.
* @param exception the exception thrown from this node's execution.
*/
@Override
public void onReturnExceptional(VirtualFrame frame, Throwable exception) {
if (!(exception instanceof TailCallException)) {
if (!(exception.getClass().equals(tailCallExceptionClass))) {
return;
}
if (!(context.getInstrumentedNode() instanceof ExpressionNode)) {
if (!(expressionNodeClass.isAssignableFrom(context.getInstrumentedNode().getClass()))) {
return;
}
UUID id = ((ExpressionNode) context.getInstrumentedNode()).getId();
UUID id = getIdFromExpressionNode(context.getInstrumentedNode());
if (expectedResult == null) {
successful = true;
}
Expand All @@ -143,8 +175,9 @@ public void onReturnExceptional(VirtualFrame frame, Throwable exception) {
public String toString() {
var sb = new StringBuilder();
sb.append(context.getInstrumentedNode().getClass().getSimpleName());
if (context.getInstrumentedNode() instanceof ExpressionNode expr) {
sb.append("@").append(expr.getId());
if (expressionNodeClass.isAssignableFrom(context.getInstrumentedNode().getClass())) {
UUID id = getIdFromExpressionNode(context.getInstrumentedNode());
sb.append("@").append(id);
}
sb.append(" ");
sb.append(context.getInstrumentedSourceSection());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.enso.interpreter.test;
package org.enso.interpreter.test.instrument;

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.instrumentation.EventBinding;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package org.enso.interpreter.test.instrument

import org.enso.interpreter.runtime.`type`.ConstantsGen
import org.enso.interpreter.test.Metadata
import org.enso.interpreter.test.instruments.{
InstrumentTestContext,
TestMessages
}
import org.enso.polyglot._
import org.enso.polyglot.runtime.Runtime.Api
import org.graalvm.polyglot.Context
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.enso.interpreter.test.instrument

import org.enso.interpreter.test.Metadata
import org.enso.interpreter.test.instruments.InstrumentTestContext
import org.enso.polyglot._
import org.enso.polyglot.runtime.Runtime.Api
import org.enso.text.{ContentVersion, Sha3_224VersionCalculator}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package org.enso.interpreter.test.instrument
import org.enso.editions.LibraryName
import org.enso.interpreter.runtime
import org.enso.interpreter.test.Metadata
import org.enso.interpreter.test.instruments.{
InstrumentTestContext,
TestEdition
}
import org.enso.pkg.{
ComponentGroup,
ComponentGroups,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package org.enso.interpreter.test.instrument

import org.enso.interpreter.runtime.`type`.ConstantsGen
import org.enso.interpreter.test.Metadata
import org.enso.interpreter.test.instruments.{
InstrumentTestContext,
TestMessages
}
import org.enso.polyglot._
import org.enso.polyglot.runtime.Runtime.Api
import org.enso.text.editing.model
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ package org.enso.interpreter.test.instrument
import org.enso.interpreter.runtime.EnsoContext
import org.enso.interpreter.runtime.`type`.ConstantsGen
import org.enso.interpreter.test.Metadata
import org.enso.interpreter.test.instruments.{
InstrumentTestContext,
TestEdition,
TestMessages
}
import org.enso.pkg.{Package, PackageManager}
import org.enso.polyglot._
import org.enso.polyglot.runtime.Runtime.Api
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package org.enso.interpreter.test.instrument

import org.enso.interpreter.runtime.`type`.{Constants, ConstantsGen}
import org.enso.interpreter.test.Metadata
import org.enso.interpreter.test.instruments.{
InstrumentTestContext,
TestMessages
}
import org.enso.polyglot._
import org.enso.polyglot.runtime.Runtime.Api
import org.enso.text.{ContentVersion, Sha3_224VersionCalculator}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package org.enso.interpreter.test.instrument
import org.apache.commons.io.output.TeeOutputStream
import org.enso.interpreter.runtime.`type`.ConstantsGen
import org.enso.interpreter.test.Metadata
import org.enso.interpreter.test.instruments.{
InstrumentTestContext,
TestMessages
}
import org.enso.polyglot._
import org.enso.polyglot.runtime.Runtime.Api
import org.enso.text.{ContentBasedVersioning, Sha3_224VersionCalculator}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ import java.io.{ByteArrayOutputStream, File}
import java.nio.file.{Files, Paths}
import java.util.UUID
import org.apache.commons.io.output.TeeOutputStream
import org.enso.interpreter.test.instruments.{
InstrumentTestContext,
TestMessages
}

@scala.annotation.nowarn("msg=multiarg infix syntax")
class RuntimeServerTest
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package org.enso.interpreter.test.instrument

import org.enso.interpreter.test.Metadata
import org.enso.interpreter.test.instruments.{
InstrumentTestContext,
TestEdition
}
import org.enso.pkg.{Package, PackageManager, QualifiedName}
import org.enso.polyglot._
import org.enso.polyglot.runtime.Runtime.Api
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.enso.interpreter.test.instrument

import org.enso.interpreter.runtime.`type`.ConstantsGen
import org.enso.interpreter.test.instruments.InstrumentTestContext
import org.enso.polyglot._
import org.enso.polyglot.data.Tree
import org.enso.polyglot.runtime.Runtime.Api
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package org.enso.interpreter.test.instrument

import org.enso.interpreter.runtime.`type`.ConstantsGen
import org.enso.interpreter.test.Metadata
import org.enso.interpreter.test.instruments.{
InstrumentTestContext,
TestMessages
}
import org.enso.pkg.QualifiedName
import org.enso.polyglot._
import org.enso.polyglot.runtime.Runtime.Api
Expand Down
Loading

0 comments on commit 4a9c962

Please sign in to comment.