diff --git a/CHANGELOG.md b/CHANGELOG.md index c0215c818501..a0a5fcff4542 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -923,6 +923,7 @@ - [Warning.get_all returns only unique warnings][6372] - [Reimplement `enso_project` as a proper builtin][6352] - [Limit number of reported warnings per value][6577] +- [Experimental support for Espresso Java interpreter][6966] - [Suggestions are updated only when the type of the expression changes][6755] - [Add project creation time to project metadata][6780] - [Upgrade GraalVM to 22.3.1 JDK17][6750] @@ -1064,6 +1065,7 @@ [6372]: https://github.com/enso-org/enso/pull/6372 [6352]: https://github.com/enso-org/enso/pull/6352 [6577]: https://github.com/enso-org/enso/pull/6577 +[6966]: https://github.com/enso-org/enso/pull/6966 [6750]: https://github.com/enso-org/enso/pull/6750 [6755]: https://github.com/enso-org/enso/pull/6755 [6780]: https://github.com/enso-org/enso/pull/6780 diff --git a/docs/infrastructure/native-image.md b/docs/infrastructure/native-image.md index 8ae0c49a5a8b..2ea348475dde 100644 --- a/docs/infrastructure/native-image.md +++ b/docs/infrastructure/native-image.md @@ -201,9 +201,7 @@ safely. ### Engine runner Configuration The Native Image generation for the Engine Runner is currently in a preview -state. Limitations are currently mostly due to -[Java interop](https://www.pivotaltracker.com/story/show/183260380) and loading -of stdlib components. To generate the Native Image for runner simply execute +state. To generate the Native Image for runner simply execute ``` sbt> engine-runner/buildNativeImage @@ -217,4 +215,27 @@ and execute the binary on a sample factorial test program The task that generates the Native Image, along with all the necessary configuration, reside in a separate project due to a bug in the currently used -GraalVM version. +GraalVM version. As September 2023 it can execute all Enso code, but cannot invoke `IO.println` +or other library functions that require [polyglot java import](../../docs/polyglot/java.md), +but read on... + +### Engine with Espresso + +Since [PR-6966](https://github.com/enso-org/enso/pull/6966) there is an experimental +support for including [Espresso Java interpreter](https://www.graalvm.org/jdk17/reference-manual/java-on-truffle/) +to allow use of some library functions (like `IO.println`) in the _Native Image_ built +runner. + +The support can be enabled by setting environment variable `ENSO_JAVA=espresso` and +making sure Espresso is installed in GraalVM executing the Enso engine - e.g. by +running `graalvm/bin/gu install espresso`. Then execute: + +```bash +$ cat >hello.enso +import Standard.Base.IO + +main = IO.println <| "Hello World!" +$ ENSO_JAVA=espresso ./enso-x.y.z-dev/bin/enso --run hello.enso +``` +Unless you see a warning containing _"No language for id java found."_ your code +has just successfully been executed by [Espresso](https://www.graalvm.org/jdk17/reference-manual/java-on-truffle/)! diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoContext.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoContext.java index a73912da1af2..957c1ba7beb6 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoContext.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoContext.java @@ -1,17 +1,5 @@ package org.enso.interpreter.runtime; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.TruffleFile; -import com.oracle.truffle.api.TruffleLanguage; -import com.oracle.truffle.api.TruffleLanguage.Env; -import com.oracle.truffle.api.TruffleLogger; -import com.oracle.truffle.api.interop.InteropLibrary; -import com.oracle.truffle.api.interop.UnknownIdentifierException; -import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.object.Shape; -import com.oracle.truffle.api.source.Source; import java.io.BufferedReader; import java.io.File; import java.io.InputStream; @@ -26,7 +14,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; -import java.util.stream.StreamSupport; + import org.enso.compiler.Compiler; import org.enso.compiler.PackageRepository; import org.enso.compiler.PackageRepositoryUtils; @@ -66,6 +54,7 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.Shape; +import com.oracle.truffle.api.source.Source; import scala.jdk.javaapi.OptionConverters; @@ -405,14 +394,6 @@ public Optional findModuleByExpressionId(UUID expressionId) { */ @TruffleBoundary public Object lookupJavaClass(String className) { - var isHosted = "hosted".equals(System.getenv("ENSO_JAVA")); - Object java; - if (!isHosted) { - var src = Source.newBuilder("java", "", "getbindings.java").build(); - java = environment.parsePublic(src).call(); - } else { - java = null; - } List items = Arrays.asList(className.split("\\.")); for (int i = items.size() - 1; i >= 0; i--) { String pkgName = String.join(".", items.subList(0, i)); @@ -421,10 +402,10 @@ public Object lookupJavaClass(String className) { i < items.size() - 1 ? items.subList(i + 1, items.size()) : List.of(); try { Object hostSymbol; - if (isHosted) { + if (findGuestJava() == null) { hostSymbol = environment.lookupHostSymbol(pkgName + "." + curClassName); } else { - hostSymbol = InteropLibrary.getUncached().readMember(java, pkgName + "." + curClassName); + hostSymbol = InteropLibrary.getUncached().readMember(findGuestJava(), pkgName + "." + curClassName); } if (nestedClassPart.isEmpty()) { return hostSymbol; @@ -438,6 +419,34 @@ public Object lookupJavaClass(String className) { return null; } + private Object guestJava = this; + + @TruffleBoundary + private Object findGuestJava() throws IllegalStateException { + if (guestJava != this) { + return guestJava; + } + guestJava = null; + var envJava = System.getenv("ENSO_JAVA"); + if ("espresso".equals(envJava)) { + var src = Source.newBuilder("java", "", "getbindings.java").build(); + try { + guestJava = environment.parsePublic(src).call(); + } catch (Exception ex) { + if (ex.getMessage().contains("No language for id java found.")) { + logger.log(Level.SEVERE, "Environment variable ENSO_JAVA=" + envJava + ", but " + ex.getMessage()); + logger.log(Level.SEVERE, "Use " + System.getProperty("java.home") + "/bin/gu install espresso"); + logger.log(Level.SEVERE, "Continuing in regular Java mode"); + } else { + var ise = new IllegalStateException(ex.getMessage()); + ise.setStackTrace(ex.getStackTrace()); + throw ise; + } + } + } + return guestJava; + } + /** * Finds the package the provided module belongs to. * diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java index 7f1e47b50ab8..570007eeb9bb 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/scope/DebugLocalScope.java @@ -6,25 +6,22 @@ import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.UnknownIdentifierException; import com.oracle.truffle.api.interop.UnsupportedMessageException; +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.source.SourceSection; - import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.stream.Collectors; - import org.enso.interpreter.EnsoLanguage; import org.enso.interpreter.node.EnsoRootNode; import org.enso.interpreter.runtime.callable.function.Function; import org.enso.interpreter.runtime.data.EnsoObject; import org.enso.interpreter.runtime.error.DataflowError; -import com.oracle.truffle.api.library.CachedLibrary; - /** * This class serves as a basic support for debugging with Chrome inspector. Currently, only * function scopes are supported.