Skip to content

Handle --jvm flag in process with JNI instantiated JVM #12843

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 65 commits into from
May 9, 2025
Merged
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
b2a04ed
Removing obsoleted DesktopEnvironment
JaroslavTulach Apr 14, 2025
0c4d7e9
Load a class via JNI
JaroslavTulach Apr 14, 2025
b3f5894
Invoke Short.parseShort method
JaroslavTulach Apr 14, 2025
f8b9234
Enabling dynamic linking on Linux
JaroslavTulach Apr 14, 2025
45f45c1
Works (without sighandler) on Windows
JaroslavTulach Apr 14, 2025
14aabfa
Need to disable segfault handler on Windows
JaroslavTulach Apr 14, 2025
ed2ce35
Create JVM with options
JaroslavTulach Apr 14, 2025
ebb49cb
Invoke Main.main via JVM and its JNI
JaroslavTulach Apr 14, 2025
1efcc8f
Verify behavior of JVM.executeMain method
JaroslavTulach Apr 15, 2025
d3faacf
Compute factorial in NI and JVM and compare the results
JaroslavTulach Apr 15, 2025
41c19f6
Repeat the test just five times
JaroslavTulach Apr 22, 2025
369912b
Derive Java home from java executable File
JaroslavTulach Apr 22, 2025
d29b6ae
Handle JAVA_OPTS in JVM class
JaroslavTulach Apr 22, 2025
94565c5
Don't pass (wrong) JAVA_OPTS to test-os-env subprocess
JaroslavTulach Apr 23, 2025
764cbc8
Merge remote-tracking branch 'origin/develop' into wip/jtulach/Jni12842
JaroslavTulach Apr 24, 2025
179307b
Specifying --module-path rather than class path
JaroslavTulach Apr 29, 2025
17b1691
Merge remote-tracking branch 'origin/develop' into wip/jtulach/Jni12842
JaroslavTulach Apr 29, 2025
ee85301
Avoiding dependency on java.desktop unlocks --jvm via JNI support on …
JaroslavTulach Apr 30, 2025
0105b73
Copy of DataFormatter from org.apache.poi:poi-ooxml:5.2.3
JaroslavTulach Apr 30, 2025
f29e549
Commented out support for locale changes in DataFormatter
JaroslavTulach Apr 30, 2025
7dbd359
Original copies from org.apache.poi:poi-ooxml:5.2.3
JaroslavTulach Apr 30, 2025
2c72c14
Avoiding java.awt dependencies
JaroslavTulach Apr 30, 2025
f0a4e02
javafmtAll
JaroslavTulach Apr 30, 2025
060453a
Merge remote-tracking branch 'origin/develop' into wip/jtulach/Jni12842
JaroslavTulach Apr 30, 2025
197ad8b
Merge tag '2025.2.1-nightly.2025.5.1' into wip/jtulach/Jni12842
JaroslavTulach May 2, 2025
12e99ea
Copy of Native from JNA 5.14.0
JaroslavTulach May 2, 2025
e2ce862
Use jna-wrapper instead of direct JNA dependency
JaroslavTulach May 2, 2025
6bb1f4f
Copy of JNA's Native as of version 5.14.0 with commented out java.awt…
JaroslavTulach May 2, 2025
8246fbc
scalafmtSbt & javafmtAll
JaroslavTulach May 2, 2025
9127982
Using JNA version in the JAR name
JaroslavTulach May 2, 2025
de80776
Merge remote-tracking branch 'origin/develop' into wip/jtulach/Jni12842
JaroslavTulach May 2, 2025
7290275
Prevent JNA from referencing java.awt.Window & co
JaroslavTulach May 2, 2025
87697fa
Merging with introduction of slf4jApi
JaroslavTulach May 3, 2025
8c79504
Merging with recent jna-wrapper adjustments
JaroslavTulach May 3, 2025
da2db93
Avoid direct dependency on io.methvin as it brings in JNA
JaroslavTulach May 3, 2025
f566b24
Tableau no longer has copy of JNA libs
JaroslavTulach May 3, 2025
1878125
The only direct reference to JNA goes via language-server now
JaroslavTulach May 3, 2025
b46f8cf
filewatcher/test on Mac needs JNA
JaroslavTulach May 3, 2025
db9bd23
Licenses adjusted as Tableau shares JNA with engine
JaroslavTulach May 3, 2025
da5ae0a
Continue to extract JNA wrapper
JaroslavTulach May 4, 2025
3b87db9
Merge branch 'wip/jtulach/UseJnaWrapperOnly12203' of enso:enso-org/en…
JaroslavTulach May 4, 2025
3d17f1d
jnidispatch library is back in Tableau
JaroslavTulach May 4, 2025
b4b4647
Merging with already well functioning #13021
JaroslavTulach May 4, 2025
2f65e50
Removing unnecessary ++ Seq()
JaroslavTulach May 5, 2025
c7e356b
Removing unnecessary dependency
JaroslavTulach May 5, 2025
5f2c2a7
Native is a copy from JNA 5.14.0 note
JaroslavTulach May 5, 2025
abc2684
Merge remote-tracking branch 'origin/develop' into wip/jtulach/UseJna…
JaroslavTulach May 5, 2025
702d63f
workingDirectory parameter is no longer used
JaroslavTulach May 5, 2025
30f04d9
JNA appears in Tableau as it is inherited from jna-wrapper
JaroslavTulach May 5, 2025
318c14e
Merging with most recent changes in #13021
JaroslavTulach May 6, 2025
6f3d119
Avoid JNA on language-server class path
JaroslavTulach May 6, 2025
dbf1407
Merge remote-tracking branch 'origin/develop' into wip/jtulach/Jni12842
JaroslavTulach May 6, 2025
e0722f7
Merge remote-tracking branch 'origin/develop' into wip/jtulach/Jni12842
JaroslavTulach May 7, 2025
dd11276
Merge remote-tracking branch 'origin/develop' into wip/jtulach/Jni12842
JaroslavTulach May 8, 2025
51c86dd
Adjusting licenses as we are using JNI implementation of jline-termin…
JaroslavTulach May 8, 2025
95b2920
Dual mode for --jvm - support both JNI and process execution
JaroslavTulach May 8, 2025
7a0846a
No need for loading in jvm.dll
JaroslavTulach May 8, 2025
da05d8d
Handling --jvm flag via JNI works (locally) on Windows
JaroslavTulach May 9, 2025
0ab5f22
Disable segfault handler when running os-environment/test
JaroslavTulach May 9, 2025
967e2ce
Attempt to define poi-wrapper (like to be) uber JAR with patches
JaroslavTulach May 9, 2025
179aff3
std-table polyglot directory contains only poi-wrapper-assembly fat j…
Akirathan May 9, 2025
923f4ec
Use Platform.getOperatingSystem() to check for a platform
JaroslavTulach May 9, 2025
2191b84
Removing outdated comments & co.
JaroslavTulach May 9, 2025
71410be
Merge branch 'wip/jtulach/Jni12842' of enso:enso-org/enso into wip/jt…
JaroslavTulach May 9, 2025
e24a687
Let's use JNI all the time
JaroslavTulach May 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ val bouncyCastle = Seq(
val jlineVersion = "3.26.3"
val jline = Seq(
"org.jline" % "jline-terminal" % jlineVersion,
"org.jline" % "jline-terminal-jna" % jlineVersion,
"org.jline" % "jline-terminal-jni" % jlineVersion, // The terminal provider jna has been deprecated, check your configuration.
"org.jline" % "jline-reader" % jlineVersion,
"org.jline" % "jline-native" % jlineVersion
)
Expand Down Expand Up @@ -1435,6 +1435,7 @@ lazy val `directory-watcher-wrapper` = project
)
}
)
.dependsOn(`jna-wrapper` % "provided")

lazy val `fansi-wrapper` = project
.in(file("lib/java/fansi-wrapper"))
Expand Down Expand Up @@ -1495,14 +1496,16 @@ lazy val `akka-wrapper` = project
"com.google.protobuf" % "protobuf-java" % googleProtobufVersion,
"io.github.java-diff-utils" % "java-diff-utils" % javaDiffVersion,
"org.reactivestreams" % "reactive-streams" % reactiveStreamsVersion,
"net.java.dev.jna" % "jna" % jnaVersion,
"io.spray" %% "spray-json" % sprayJsonVersion
),
javaModuleName := "org.enso.akka.wrapper",
Compile / moduleDependencies ++= slf4jApi ++ Seq(
"com.google.protobuf" % "protobuf-java" % googleProtobufVersion,
"org.reactivestreams" % "reactive-streams" % reactiveStreamsVersion
),
Compile / internalModuleDependencies := Seq(
(`jna-wrapper` / Compile / exportedModule).value
),
assembly / assemblyExcludedJars := {
val excludedJars = JPMSUtils.filterModulesFromUpdate(
update.value,
Expand All @@ -1511,8 +1514,7 @@ lazy val `akka-wrapper` = project
"com.typesafe" % "config" % typesafeConfigVersion,
"io.github.java-diff-utils" % "java-diff-utils" % javaDiffVersion,
"com.google.protobuf" % "protobuf-java" % googleProtobufVersion,
"org.reactivestreams" % "reactive-streams" % reactiveStreamsVersion,
"net.java.dev.jna" % "jna" % jnaVersion
"org.reactivestreams" % "reactive-streams" % reactiveStreamsVersion
),
streams.value.log,
moduleName.value,
Expand Down Expand Up @@ -1549,6 +1551,7 @@ lazy val `akka-wrapper` = project
)
}
)
.dependsOn(`jna-wrapper` % "provided")

lazy val `zio-wrapper` = project
.in(file("lib/java/zio-wrapper"))
Expand Down Expand Up @@ -3902,7 +3905,7 @@ lazy val `engine-runner` = project
val NI_MODULES =
"org.graalvm.nativeimage,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.base,org.graalvm.nativeimage.driver,org.graalvm.nativeimage.librarysupport,org.graalvm.nativeimage.objectfile,org.graalvm.nativeimage.pointsto,com.oracle.graal.graal_enterprise,com.oracle.svm.svm_enterprise"
val JDK_MODULES =
"java.desktop,java.naming,java.net.http,jdk.charsets,jdk.crypto.ec,jdk.localedata,jdk.httpserver,java.rmi"
"java.naming,java.net.http,jdk.charsets,jdk.crypto.ec,jdk.localedata,jdk.httpserver,java.rmi"
val DEBUG_MODULES = "jdk.jdwp.agent"
val PYTHON_MODULES = "jdk.security.auth,java.naming"

Expand Down Expand Up @@ -4285,7 +4288,7 @@ lazy val `os-environment` =
val targetDir = (Test / target).value
NativeImage.buildNativeImage(
"test-os-env",
staticOnLinux = true,
staticOnLinux = false,
targetDir = targetDir,
mainClass = Some("org.enso.os.environment.TestRunner"),
additionalOptions = Seq(
Expand All @@ -4301,7 +4304,7 @@ lazy val `os-environment` =
val exeFile =
(Test / target).value / ("test-os-env" + exeSuffix)
val binPath = exeFile.getAbsolutePath
val res = binPath ! logger
val res = Process(Seq(binPath), None, "JAVA_OPTS" -> "") ! logger
if (res != 0) {
logger.error("Some test in os-environment failed")
throw new TestsFailedException()
Expand Down Expand Up @@ -5515,7 +5518,6 @@ lazy val `std-tableau` = project
unmanagedClasspath = unmanagedClasspath,
previousRun = prev
)

StdBits
.extractNativeLibsFromTableau(
`std-tableau-polyglot-root`,
Expand Down
9 changes: 2 additions & 7 deletions distribution/engine/THIRD-PARTY/NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -361,11 +361,6 @@ The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `jakarta.inject.jakarta.inject-api-2.0.1`.


'jna', licensed under the Apache-2.0, is distributed with the engine.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `net.java.dev.jna.jna-5.14.0`.


'commons-compress', licensed under the Apache-2.0, is distributed with the engine.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `org.apache.commons.commons-compress-1.23.0`.
Expand Down Expand Up @@ -531,9 +526,9 @@ The license file can be found at `licenses/BSD-3-Clause`.
Copyright notices related to this dependency can be found in the directory `org.jline.jline-terminal-3.26.3`.


'jline-terminal-jna', licensed under the The BSD License, is distributed with the engine.
'jline-terminal-jni', licensed under the The BSD License, is distributed with the engine.
The license file can be found at `licenses/BSD-3-Clause`.
Copyright notices related to this dependency can be found in the directory `org.jline.jline-terminal-jna-3.26.3`.
Copyright notices related to this dependency can be found in the directory `org.jline.jline-terminal-jni-3.26.3`.


'org-netbeans-modules-sampler', licensed under the The Apache Software License, Version 2.0, is distributed with the engine.
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Copyright (C) 2022 the original author(s).

Copyright (c) 2002-2017, the original author(s).

Copyright (c) 2002-2020, the original author or authors.

Copyright (c) 2002-2020, the original author(s).

Copyright (c) 2009-2018, the original author(s).
21 changes: 11 additions & 10 deletions engine/runner/src/main/java/org/enso/runner/JavaFinder.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.enso.runner;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Comparator;
Expand Down Expand Up @@ -27,10 +28,10 @@ private JavaFinder() {}
* @return null if cannot be found. Otherwise, returns the absolute path to the executable, or
* simply {@code java} if it is on the {@code PATH}.
*/
static String findJavaExecutable() {
static File findJavaExecutable() {
var javaInRuntime = findJavaExecutableInDistributionRuntimes();
if (javaInRuntime != null) {
return javaInRuntime.toAbsolutePath().toString();
return javaInRuntime.toAbsolutePath().toFile();
}
logger.warn("No appropriate JDK found in the distribution runtimes. Trying system-wide JDK.");
var javaHome = System.getenv("JAVA_HOME");
Expand All @@ -44,7 +45,7 @@ static String findJavaExecutable() {
}
if (javaExe.toFile().exists()) {
logger.info("Found JDK in JAVA_HOME: {}", javaHome);
return javaExe.toAbsolutePath().toString();
return javaExe.toAbsolutePath().toFile();
} else {
logger.warn(
"No JDK found in JAVA_HOME (missing Java executable at {}). Trying java on PATH.",
Expand All @@ -54,10 +55,9 @@ static String findJavaExecutable() {
logger.warn("JAVA_HOME is not set. Trying java on PATH.");
}

if (isJavaOnPath()) {
var javaExe = isOnWindows() ? "java.exe" : "java";
logger.warn("Falling back to java on PATH: {}", javaExe);
return javaExe;
if (findJavaOnPath() instanceof File javaExecutable) {
logger.warn("Falling back to java on PATH: {}", javaExecutable);
return javaExecutable;
}
logger.warn("No JDK found on PATH. Cannot start the runtime.");
return null;
Expand Down Expand Up @@ -107,7 +107,7 @@ private static Path findJavaExecutableInDistributionRuntimes() {
return null;
}

private static boolean isJavaOnPath() {
private static File findJavaOnPath() {
try {
ProcessBuilder processBuilder;
if (isOnWindows()) {
Expand All @@ -116,10 +116,11 @@ private static boolean isJavaOnPath() {
processBuilder = new ProcessBuilder("java", "-h");
}
Process process = processBuilder.start();
var pathOpt = process.info().command();
boolean exitSucc = process.waitFor(5L, TimeUnit.SECONDS);
return exitSucc;
return exitSucc && pathOpt.isPresent() ? new File(pathOpt.get()) : null;
} catch (IOException | InterruptedException e) {
return false;
return null;
}
}
}
66 changes: 43 additions & 23 deletions engine/runner/src/main/java/org/enso/runner/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.enso.distribution.Environment;
import org.enso.editions.DefaultEdition;
import org.enso.libraryupload.LibraryUploader.UploadFailedError;
import org.enso.os.environment.jni.JVM;
import org.enso.pkg.Contact;
import org.enso.pkg.PackageManager;
import org.enso.pkg.PackageManager$;
Expand Down Expand Up @@ -1437,17 +1438,20 @@ private boolean isJvmModeEnabled(CommandLine line) {
}

private void launchJvm(
CommandLine line, Map<String, String> props, File component, String javaPath)
CommandLine line, Map<String, String> props, File component, File javaExecutable)
throws IOException, InterruptedException {
var useJNI = JVM.isSupported();
var commandAndArgs = new ArrayList<String>();
commandAndArgs.add(javaPath);
var jvmOptions = System.getenv("JAVA_OPTS");
if (jvmOptions != null) {
for (var op : jvmOptions.split(" ")) {
if (op.isEmpty()) {
continue;
if (!useJNI) {
commandAndArgs.add(javaExecutable.getPath());
var jvmOptions = System.getenv("JAVA_OPTS");
if (jvmOptions != null) {
for (var op : jvmOptions.split(" ")) {
if (op.isEmpty()) {
continue;
}
commandAndArgs.add(op);
}
commandAndArgs.add(op);
}
}
var assertsOn = false;
Expand All @@ -1463,13 +1467,23 @@ private void launchJvm(
commandAndArgs.add("--sun-misc-unsafe-memory-access=allow");
commandAndArgs.add("--enable-native-access=org.graalvm.truffle");
commandAndArgs.add("--add-opens=java.base/java.nio=ALL-UNNAMED");
commandAndArgs.add("--module-path");
if (!component.isDirectory()) {
throw new IOException("Cannot find " + component + " directory");
}
commandAndArgs.add(component.getPath());
commandAndArgs.add("-m");
commandAndArgs.add("org.enso.runner/org.enso.runner.Main");
JVM jvm;
if (useJNI) {
commandAndArgs.add("--module-path=" + component.getPath());
commandAndArgs.add("-Djdk.module.main=org.enso.runner");
var javaHome = javaExecutable.getParentFile().getParentFile();
jvm = JVM.create(javaHome, commandAndArgs.toArray(new String[0]));
commandAndArgs.clear();
} else {
commandAndArgs.add("--module-path");
commandAndArgs.add(component.getPath());
commandAndArgs.add("-m");
commandAndArgs.add("org.enso.runner/org.enso.runner.Main");
jvm = null;
}
var it = line.iterator();
while (it.hasNext()) {
var op = it.next();
Expand All @@ -1491,11 +1505,18 @@ private void launchJvm(
}
}
commandAndArgs.addAll(line.getArgList());
var pb = new ProcessBuilder();
pb.inheritIO();
pb.command(commandAndArgs);
var p = pb.start();
var exitCode = p.waitFor();
int exitCode;
if (useJNI) {
jvm.executeMain("org/enso/runner/Main", commandAndArgs.toArray(new String[0]));
// the above call should never return
exitCode = 1;
} else {
var pb = new ProcessBuilder();
pb.inheritIO();
pb.command(commandAndArgs);
var p = pb.start();
exitCode = p.waitFor();
}
if (exitCode == 0) {
throw exitSuccess();
} else {
Expand Down Expand Up @@ -1541,16 +1562,15 @@ private void launch(String[] args) throws IOException, InterruptedException, URI
var javaExe = JavaFinder.findJavaExecutable();
if (javaExe == null) {
// Try your best if `jvm` mode enabled in a project
if (!jvmInProjectEnforced) throw exitFail("Cannot find java executable");
if (!jvmInProjectEnforced) {
throw exitFail("Cannot find java executable");
}
} else {
launchJvm(line, props, component, javaExe);
}
} else {
launchJvm(
line,
props,
component,
new File(new File(new File(jvm), "bin"), "java").getAbsolutePath());
var javaExecutable = new File(new File(new File(jvm), "bin"), "java").getAbsoluteFile();
launchJvm(line, props, component, javaExecutable);
}
}
}
Expand Down
1 change: 1 addition & 0 deletions lib/java/os-environment/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
requires org.apache.commons.io;

exports org.enso.os.environment;
exports org.enso.os.environment.jni;
exports org.enso.os.environment.chdir;
exports org.enso.os.environment.trash;
exports org.enso.os.environment.directories;
Expand Down

This file was deleted.

Loading
Loading