Skip to content

Commit

Permalink
[GR-37469] Backport: Espresso fails to run with Java 8 home.
Browse files Browse the repository at this point in the history
PullRequest: graal/11601
  • Loading branch information
gilles-duboscq committed Apr 12, 2022
2 parents 18ca9de + 9aeae5b commit c2a589c
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 43 deletions.
1 change: 1 addition & 0 deletions espresso/mx.espresso/native-image.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ Requires = language:nfi
Args = -H:MaxRuntimeCompileMethods=7000 \
-H:ReflectionConfigurationFiles=${.}/reflectconfig.json \
-H:+TruffleCheckBlockListMethods \
--initialize-at-build-time=com.oracle.truffle.espresso \
--features=com.oracle.truffle.espresso.ref.FinalizationFeature
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,13 @@
*/
package com.oracle.truffle.espresso;

import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;

import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.espresso.meta.EspressoError;
import com.oracle.truffle.espresso.runtime.JavaVersion;
import org.graalvm.home.Version;
import org.graalvm.options.OptionDescriptors;

Expand Down Expand Up @@ -95,15 +99,17 @@ public final class EspressoLanguage extends TruffleLanguage<EspressoContext> {
private static final StaticProperty ARRAY_PROPERTY = new DefaultStaticProperty("array");
// This field should be static final, but until we move the static object model we cannot have a
// SubstrateVM feature which will allow us to set the right field offsets at image build time.
@CompilerDirectives.CompilationFinal //
@CompilationFinal //
private static StaticShape<StaticObjectFactory> arrayShape;

private static final StaticProperty FOREIGN_PROPERTY = new DefaultStaticProperty("foreignObject");
// This field should be static final, but until we move the static object model we cannot have a
// SubstrateVM feature which will allow us to set the right field offsets at image build time.
@CompilerDirectives.CompilationFinal //
@CompilationFinal //
private static StaticShape<StaticObjectFactory> foreignShape;

@CompilationFinal private JavaVersion javaVersion;

private final ContextThreadLocal<EspressoThreadLocalState> threadLocalState = createContextThreadLocal((context, thread) -> new EspressoThreadLocalState(context));

public EspressoLanguage() {
Expand Down Expand Up @@ -289,4 +295,21 @@ private StaticShape<StaticObjectFactory> initializeForeignShape() {
public static EspressoLanguage get(Node node) {
return REFERENCE.get(node);
}

public JavaVersion getJavaVersion() {
return javaVersion;
}

public void tryInitializeJavaVersion(JavaVersion version) {
JavaVersion ref = this.javaVersion;
if (ref == null) {
synchronized (this) {
ref = this.javaVersion;
if (ref == null) {
this.javaVersion = ref = Objects.requireNonNull(version);
}
}
}
EspressoError.guarantee(version.equals(ref), "incompatible Java versions");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -501,8 +501,12 @@ private void spawnVM() {

// Spawn JNI first, then the VM.
try (DebugCloseable vmInit = VM_INIT.scope(timers)) {
this.vm = VM.create(getJNI()); // Mokapot is loaded
this.jniEnv = JniEnv.create(this); // libnespresso
this.vm = VM.create(this.jniEnv); // libjvm
vm.attachThread(Thread.currentThread());
// The Java version is extracted from libjava and is available after this line.
vm.loadAndInitializeJavaLibrary(vmProperties.bootLibraryPath()); // libjava
EspressoError.guarantee(getJavaVersion() != null, "Java version");
}

if (getJavaVersion().modulesEnabled()) {
Expand Down Expand Up @@ -735,7 +739,7 @@ public JImageHelper createJImageHelper(String jimagePath) {
}

public JavaVersion getJavaVersion() {
return vm.getJavaVersion();
return getLanguage().getJavaVersion();
}

public boolean advancedRedefinitionEnabled() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,24 @@
*
* Makes it harder to access the raw int version: please add new predicates instead.
*/
public final class JavaVersion {
public enum JavaVersion {

JAVA_4(4),
JAVA_5(5),
JAVA_6(6),
JAVA_7(7),
JAVA_8(8),
JAVA_9(9),
JAVA_10(10),
JAVA_11(11),
JAVA_12(12),
JAVA_13(13),
JAVA_14(14),
JAVA_15(15),
JAVA_16(16),
JAVA_17(17),
JAVA_18(18);

public static final class VersionRange {
public static final VersionRange VERSION_8_OR_LOWER = lower(8);
public static final VersionRange VERSION_9_TO_11 = new VersionRange(9, 11);
Expand Down Expand Up @@ -68,10 +85,19 @@ public boolean contains(JavaVersion version) {

private final int version;

public JavaVersion(int version) {
JavaVersion(int version) {
this.version = version;
}

public static JavaVersion forVersion(int version) {
int lowest = values()[0].version;
return values()[version - lowest];
}

public static JavaVersion latestSupported() {
return forVersion(LATEST_SUPPORTED);
}

public boolean java8OrEarlier() {
return version <= 8;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,18 +184,14 @@ public final class VM extends NativeEnv implements ContextAccess {
private final long rtldDefaultValue;
private final long processHandleValue;

private final JavaVersion javaVersion;

private final Structs structs;

private final JniEnv jniEnv;
private final Management management;
private final JVMTI jvmti;

private @Pointer TruffleObject mokapotEnvPtr;

// libjava must be loaded after mokapot.
private final @Pointer TruffleObject javaLibrary;
private @Pointer TruffleObject javaLibrary;

private static String stringify(List<Path> paths) {
StringJoiner joiner = new StringJoiner(File.pathSeparator);
Expand Down Expand Up @@ -225,6 +221,10 @@ public Management getManagement() {
return management;
}

public @Pointer TruffleObject getJavaLibrary() {
return javaLibrary;
}

public static final class GlobalFrameIDs {
private static final AtomicLong id = new AtomicLong();

Expand All @@ -233,15 +233,6 @@ public static long getID() {
}
}

@Override
public JavaVersion getJavaVersion() {
return javaVersion;
}

public @Pointer TruffleObject getJavaLibrary() {
return javaLibrary;
}

private @Pointer TruffleObject loadJavaLibrary(List<Path> bootLibraryPath) {
// Comment from HotSpot:
// Try to load verify dll first. In 1.3 java dll depends on it and is not
Expand All @@ -252,14 +243,15 @@ public JavaVersion getJavaVersion() {
return getNativeAccess().loadLibrary(bootLibraryPath, "java", true);
}

private void libJavaOnLoad(TruffleObject libJava) {
private void initializeJavaLibrary(TruffleObject libJava) {
// HotSpot calls libjava's JNI_OnLoad only on 8.
if (getJavaVersion().java8OrEarlier()) {
// The JNI_OnLoad handling is normally done by method load in
// java.lang.ClassLoader$NativeLibrary, but the VM loads the base library
// explicitly so we have to check for JNI_OnLoad as well
// libjava is initialized after libjvm (Espresso VM native context).

// TODO(peterssen): Use JVM_FindLibraryEntry.
/*
* The JNI_OnLoad handling is normally done by method load in
* java.lang.ClassLoader$NativeLibrary, but the VM loads the base library explicitly so
* we have to check for JNI_OnLoad as well.
*/
EspressoError.guarantee(getVM() != null, "The VM must be initialized before libjava's JNI_OnLoad");
TruffleObject jniOnLoad = getNativeAccess().lookupAndBindSymbol(libJava, "JNI_OnLoad", NativeSignature.create(NativeType.INT, NativeType.POINTER, NativeType.POINTER));
if (jniOnLoad != null) {
try {
Expand Down Expand Up @@ -288,17 +280,25 @@ private JavaVersion findJavaVersion(TruffleObject libJava) {
if (major == 1) {
// Version 1.X
int minor = (versionInfo & 0x00FF0000) >> 16;
return new JavaVersion(minor);
return JavaVersion.forVersion(minor);
} else {
// Version X.Y
return new JavaVersion(major);
return JavaVersion.forVersion(major);
}
} else {
// JDK 14+
return new JavaVersion(JavaVersion.LATEST_SUPPORTED);
return JavaVersion.latestSupported();
}
}

public void loadAndInitializeJavaLibrary(List<Path> searchPaths) {
assert javaLibrary == null : "java library already initialized";
this.javaLibrary = loadJavaLibrary(searchPaths);
JavaVersion javaVersion = findJavaVersion(this.javaLibrary);
getEspressoLanguage().tryInitializeJavaVersion(javaVersion);
initializeJavaLibrary(this.javaLibrary);
}

private VM(JniEnv jniEnv) {
this.jniEnv = jniEnv;
try {
Expand Down Expand Up @@ -359,19 +359,9 @@ private VM(JniEnv jniEnv) {
getLogger().finest(() -> String.format("Got RTLD_DEFAULT=0x%016x and ProcessHandle=0x%016x", rtldDefaultValue, processHandleValue));
assert getUncached().isPointer(this.mokapotEnvPtr);
assert !getUncached().isNull(this.mokapotEnvPtr);

javaLibrary = loadJavaLibrary(props.bootLibraryPath());
javaVersion = findJavaVersion(javaLibrary);
libJavaOnLoad(javaLibrary);

} catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) {
throw EspressoError.shouldNotReachHere(e);
}
if (getJavaVersion().java9OrLater()) {
stackWalk = new StackWalk();
} else {
stackWalk = null;
}
}

@Override
Expand Down Expand Up @@ -3606,7 +3596,21 @@ public static long JVM_MaxObjectInspectionAge() {

// region stackwalk

private final StackWalk stackWalk;
private volatile StackWalk stackWalk;

private StackWalk getStackWalk() {
StackWalk ref = stackWalk;
if (ref == null) {
EspressoError.guarantee(getJavaVersion().java9OrLater(), "Stack-Walking API requires Java 9+");
synchronized (this) {
ref = stackWalk;
if (ref == null) {
stackWalk = ref = new StackWalk();
}
}
}
return ref;
}

@VmImpl(isJni = true)
@SuppressWarnings("unused")
Expand Down Expand Up @@ -3708,7 +3712,7 @@ private void checkStackWalkArguments(int batchSize, int startIndex, @JavaType(Ob
int batchSize, int startIndex,
@JavaType(Object[].class) StaticObject frames) {
checkStackWalkArguments(batchSize, startIndex, frames);
return stackWalk.fetchFirstBatch(stackStream, mode, skipframes, batchSize, startIndex, frames, getMeta());
return getStackWalk().fetchFirstBatch(stackStream, mode, skipframes, batchSize, startIndex, frames, getMeta());
}

@VmImpl(isJni = true)
Expand All @@ -3718,7 +3722,7 @@ public int JVM_MoreStackWalk(
int batchSize, int startIndex,
@JavaType(Object[].class) StaticObject frames) {
checkStackWalkArguments(batchSize, startIndex, frames);
return stackWalk.fetchNextBatch(stackStream, mode, anchor, batchSize, startIndex, frames, getMeta());
return getStackWalk().fetchNextBatch(stackStream, mode, anchor, batchSize, startIndex, frames, getMeta());
}

// endregion stackwalk
Expand Down

0 comments on commit c2a589c

Please sign in to comment.