Skip to content

Commit

Permalink
Use ENSO_JAVA=espresso to turn on Espresso support
Browse files Browse the repository at this point in the history
  • Loading branch information
JaroslavTulach committed Sep 16, 2023
1 parent 89458ec commit 64029ef
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 31 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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
Expand Down
29 changes: 25 additions & 4 deletions docs/infrastructure/native-image.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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/)!
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -405,14 +394,6 @@ public Optional<Module> 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", "<Bindings>", "getbindings.java").build();
java = environment.parsePublic(src).call();
} else {
java = null;
}
List<String> items = Arrays.asList(className.split("\\."));
for (int i = items.size() - 1; i >= 0; i--) {
String pkgName = String.join(".", items.subList(0, i));
Expand All @@ -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;
Expand All @@ -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", "<Bindings>", "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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 64029ef

Please sign in to comment.