Skip to content

Commit 45f45c1

Browse files
Works (without sighandler) on Windows
1 parent f8b9234 commit 45f45c1

File tree

5 files changed

+103
-37
lines changed

5 files changed

+103
-37
lines changed

lib/java/os-environment/src/main/java/org/enso/os/environment/jni/JNIBoot.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package org.enso.os.environment.jni;
22

33
import org.graalvm.nativeimage.c.CContext;
4-
import org.graalvm.nativeimage.c.function.CFunction;
54
import org.graalvm.nativeimage.c.function.CFunctionPointer;
65
import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer;
76
import org.graalvm.nativeimage.c.struct.CField;
@@ -13,10 +12,7 @@
1312
/** Java virtual machine initialization API. */
1413
@CContext(JNIDirectives.class)
1514
final class JNIBoot {
16-
@CFunction
17-
static native int JNI_GetDefaultJavaVMInitArgs(Args vmargs);
18-
19-
public interface JNICreateJavaVMPointer extends CFunctionPointer {
15+
interface JNICreateJavaVMPointer extends CFunctionPointer {
2016
@InvokeCFunctionPointer
2117
int call(JNI.JavaVMPointer jvmptr, JNI.JNIEnvPointer env, Args args);
2218
}
@@ -49,7 +45,7 @@ interface Args extends PointerBase {
4945
}
5046

5147
@CStruct(value = "JavaVMOption")
52-
public interface Option extends PointerBase {
48+
interface Option extends PointerBase {
5349

5450
@CField("optionString")
5551
CCharPointer getOptionString();

lib/java/os-environment/src/main/java/org/enso/os/environment/jni/JNIDirectives.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,13 @@ final class JNIDirectives implements CContext.Directives {
99
@Override
1010
public List<String> getLibraryPaths() {
1111
var javaHome = new File(System.getProperty("java.home"));
12+
var binServer = new File(new File(javaHome, "bin"), "server");
1213
var libServer = new File(new File(javaHome, "lib"), "server");
13-
return List.of(libServer.getPath());
14+
if (binServer.isDirectory()) {
15+
return List.of(binServer.getPath());
16+
} else {
17+
return List.of(libServer.getPath());
18+
}
1419
}
1520

1621
@Override
@@ -28,7 +33,6 @@ public List<String> getOptions() {
2833
for (var subDir : include.listFiles()) {
2934
var md = new File(subDir, "jni_md.h");
3035
if (md.canRead()) {
31-
var q = "\"";
3236
var includes = List.of("-I", jni.getParent(), "-I", md.getParent());
3337
return includes;
3438
}
Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,57 @@
11
package org.enso.os.environment.jni;
22

33
import org.enso.common.Platform;
4+
import org.graalvm.nativeimage.StackValue;
5+
import org.graalvm.word.WordFactory;
46

57
public final class JVM {
6-
private final JNI.JNIEnv env;
8+
private final JNIBoot.JNICreateJavaVMPointer createJvmFn;
9+
private JNI.JNIEnv env = WordFactory.nullPointer();
710

8-
JVM(JNI.JNIEnv env) {
9-
this.env = env;
11+
JVM(JNIBoot.JNICreateJavaVMPointer factory) {
12+
this.createJvmFn = factory;
1013
}
1114

15+
/**
16+
* Create new JVM. Use {@link #env()} to obtain reference to JNI interface and make calls into the
17+
* JVM.
18+
*
19+
* @param javaHome path where the JDK is installed
20+
* @return new instance of the JVM
21+
*/
1222
public static JVM create(String javaHome) {
1323
return switch (Platform.getOperatingSystem()) {
1424
case WINDOWS -> WindowsJVM.createImpl(javaHome);
1525
case LINUX, MACOS -> PosixJVM.createImpl(javaHome);
1626
};
1727
}
1828

19-
public JNI.JNIEnv env() {
29+
/**
30+
* Initialize or just obtain environment associated with this JVM.
31+
*
32+
* @return JNI environment to make calls into the JVM
33+
*/
34+
public final JNI.JNIEnv env() {
35+
if (env.isNull()) {
36+
env = initializeEnv();
37+
}
2038
return env;
2139
}
40+
41+
private synchronized JNI.JNIEnv initializeEnv() {
42+
var jvmArgs = StackValue.get(JNIBoot.Args.class);
43+
jvmArgs.nOptions(0);
44+
var options = StackValue.get(1, JNIBoot.Option.class);
45+
jvmArgs.options(options);
46+
jvmArgs.version(JNI.JNI_VERSION_10());
47+
jvmArgs.nOptions(0);
48+
jvmArgs.ignoreUnrecognized(false);
49+
50+
var jvmPtr = StackValue.get(JNI.JavaVMPointer.class);
51+
var envPtr = StackValue.get(JNI.JNIEnvPointer.class);
52+
53+
int res = createJvmFn.call(jvmPtr, envPtr, jvmArgs);
54+
assert res == 0;
55+
return envPtr.readJNIEnv();
56+
}
2257
}

lib/java/os-environment/src/main/java/org/enso/os/environment/jni/PosixJVM.java

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import java.io.File;
44
import java.util.List;
55
import org.graalvm.nativeimage.Platform;
6-
import org.graalvm.nativeimage.StackValue;
76
import org.graalvm.nativeimage.c.CContext;
87
import org.graalvm.nativeimage.c.constant.CConstant;
98
import org.graalvm.nativeimage.c.function.CFunction;
@@ -15,26 +14,11 @@
1514
final class PosixJVM {
1615

1716
static JVM createImpl(String javaHome) {
18-
var jvmArgs = StackValue.get(JNIBoot.Args.class);
19-
jvmArgs.nOptions(0);
20-
var options = StackValue.get(1, JNIBoot.Option.class);
21-
jvmArgs.options(options);
22-
System.err.println("empty: " + jvmArgs.version());
23-
jvmArgs.version(JNI.JNI_VERSION_1_1());
24-
System.err.println("version is " + jvmArgs.version());
25-
26-
int resInitArgs = JNIBoot.JNI_GetDefaultJavaVMInitArgs(jvmArgs);
27-
if (resInitArgs != 0) {
28-
System.err.println("result: " + resInitArgs);
29-
System.err.println("JVM wants to support version " + jvmArgs.version());
30-
}
31-
32-
jvmArgs.nOptions(0);
33-
jvmArgs.ignoreUnrecognized(false);
34-
35-
var jvmPtr = StackValue.get(JNI.JavaVMPointer.class);
36-
var envPtr = StackValue.get(JNI.JNIEnvPointer.class);
17+
var createJvmFn = findCreateJavaSymbol(javaHome);
18+
return new JVM(createJvmFn);
19+
}
3720

21+
private static JNIBoot.JNICreateJavaVMPointer findCreateJavaSymbol(String javaHome) {
3822
var libJvmPath = findDynamicLibrary(javaHome).getPath();
3923
try (var libPath = CTypeConversion.toCString(libJvmPath);
4024
var createJvm = CTypeConversion.toCString("JNI_CreateJavaVM")) {
@@ -44,10 +28,7 @@ static JVM createImpl(String javaHome) {
4428
+ libJvmPath
4529
+ " error: "
4630
+ CTypeConversion.toJavaString(dlerror());
47-
JNIBoot.JNICreateJavaVMPointer createJvmFn = dlsym(jvmSo, createJvm.get());
48-
int res = createJvmFn.call(jvmPtr, envPtr, jvmArgs);
49-
assert res == 0;
50-
return new JVM(envPtr.readJNIEnv());
31+
return dlsym(jvmSo, createJvm.get());
5132
}
5233
}
5334

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,57 @@
11
package org.enso.os.environment.jni;
22

3+
import static org.graalvm.nativeimage.c.function.CFunction.Transition.NO_TRANSITION;
4+
5+
import java.io.File;
6+
import java.util.List;
7+
import org.enso.os.environment.jni.JNIBoot.JNICreateJavaVMPointer;
8+
import org.graalvm.nativeimage.Platform;
9+
import org.graalvm.nativeimage.Platforms;
10+
import org.graalvm.nativeimage.c.CContext;
11+
import org.graalvm.nativeimage.c.function.CFunction;
12+
import org.graalvm.nativeimage.c.type.CCharPointer;
13+
import org.graalvm.nativeimage.c.type.CTypeConversion;
14+
import org.graalvm.word.PointerBase;
15+
16+
@CContext(WindowsJVM.Direct.class)
317
final class WindowsJVM {
418
static JVM createImpl(String javaHome) {
5-
return null;
19+
var dllPath = findDynamicLibrary(javaHome).getPath();
20+
21+
try (var libPath = CTypeConversion.toCString(dllPath);
22+
var createJvm = CTypeConversion.toCString("JNI_CreateJavaVM")) {
23+
var dll = LoadLibraryA(libPath.get());
24+
assert dll.isNonNull();
25+
JNICreateJavaVMPointer cStringCreateJvm = GetProcAddress(dll, createJvm.get());
26+
27+
return new JVM(cStringCreateJvm);
28+
}
29+
}
30+
31+
private static File findDynamicLibrary(String javaHome) {
32+
return new File(new File(new File(new File(javaHome), "bin"), "server"), "jvm.dll");
33+
}
34+
35+
/** Loads the specified module into the address space of the calling process. */
36+
@CFunction(transition = NO_TRANSITION)
37+
static native HMODULE LoadLibraryA(CCharPointer lpLibFileName);
38+
39+
@CFunction(transition = NO_TRANSITION)
40+
static native <T extends PointerBase> T GetProcAddress(HMODULE hModule, CCharPointer lpProcName);
41+
42+
/** Windows Module Handle type */
43+
interface HMODULE extends PointerBase {}
44+
45+
@Platforms(Platform.WINDOWS.class)
46+
static final class Direct implements CContext.Directives {
47+
@Override
48+
public final boolean isInConfiguration() {
49+
return Platform.includedIn(Platform.WINDOWS.class);
50+
}
51+
52+
@Override
53+
public final List<String> getHeaderFiles() {
54+
return List.of("<windows.h>");
55+
}
656
}
757
}

0 commit comments

Comments
 (0)