Skip to content

[GR-64843] Remove JDK 21 Substitutions from Native Image #11162

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 4 commits into from
May 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
import com.oracle.svm.core.jdk.Target_java_lang_Module;
import com.oracle.svm.core.snippets.KnownIntrinsics;

import jdk.graal.compiler.serviceprovider.JavaVersionUtil;
import jdk.internal.foreign.MemorySessionImpl;
import jdk.internal.foreign.Utils;
import jdk.internal.loader.NativeLibrary;
Expand Down Expand Up @@ -139,11 +138,7 @@ static void ensureNativeAccess(Class<?> currentClass, Class<?> owner, String met
*/
Target_java_lang_Module module = SubstrateUtil.cast(currentClass != null ? currentClass.getModule() : ClassLoader.getSystemClassLoader().getUnnamedModule(),
Target_java_lang_Module.class);
if (JavaVersionUtil.JAVA_SPEC <= 21) {
module.ensureNativeAccess(owner, methodName);
} else {
module.ensureNativeAccess(owner, methodName, currentClass, false);
}
module.ensureNativeAccess(owner, methodName, currentClass, false);

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,28 +30,19 @@
import com.oracle.svm.core.annotate.RecomputeFieldValue;
import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.core.config.ConfigurationValues;
import com.oracle.svm.core.jdk.JDK21OrEarlier;
import com.oracle.svm.core.jdk.JDKLatest;
import com.oracle.svm.core.util.VMError;

import jdk.graal.compiler.serviceprovider.JavaVersionUtil;
import jdk.internal.foreign.Utils;
import jdk.vm.ci.meta.JavaKind;

@TargetClass(className = "jdk.internal.foreign.Utils", innerClass = "BaseAndScale", onlyWith = {ForeignAPIPredicates.Enabled.class, JDKLatest.class})
@TargetClass(className = "jdk.internal.foreign.Utils", innerClass = "BaseAndScale", onlyWith = ForeignAPIPredicates.Enabled.class)
final class Target_jdk_internal_foreign_Utils_BaseAndScale {
@Alias //
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = BaseFieldRecomputer.class) //
long base;
}

@TargetClass(className = "jdk.internal.foreign.Utils", innerClass = "BaseAndScale", onlyWith = {ForeignAPIPredicates.Enabled.class, JDK21OrEarlier.class})
final class Target_jdk_internal_foreign_Utils_BaseAndScale_JDK21 {
@Alias //
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = BaseFieldRecomputer.class) //
int base;
}

final class BaseFieldRecomputer implements FieldValueTransformer {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@
import com.oracle.svm.core.ArenaIntrinsics;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.core.annotate.TargetElement;
import com.oracle.svm.core.jdk.JDK21OrEarlier;
import com.oracle.svm.core.jdk.JDKLatest;
import com.oracle.svm.core.nodes.foreign.MemoryArenaValidInScopeNode;
import com.oracle.svm.core.util.BasedOnJDKFile;

Expand Down Expand Up @@ -99,7 +96,6 @@ static void registerNatives() {
@SuppressWarnings("static-method")
@Substitute
@Target_jdk_internal_misc_ScopedMemoryAccess_Scoped
@TargetElement(onlyWith = JDKLatest.class)
@AlwaysInline("Safepoints must be visible in caller")
public void loadInternal(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, long address, boolean isSync, long size) {
SubstrateForeignUtil.checkIdentity(mappedUtils, Target_java_nio_MappedMemoryUtils.PROXY);
Expand All @@ -120,7 +116,6 @@ public void loadInternal(MemorySessionImpl session, MappedMemoryUtilsProxy mappe
@SuppressWarnings("static-method")
@Substitute
@Target_jdk_internal_misc_ScopedMemoryAccess_Scoped
@TargetElement(onlyWith = JDKLatest.class)
@AlwaysInline("Safepoints must be visible in caller")
public boolean isLoadedInternal(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, long address, boolean isSync, long size) {
SubstrateForeignUtil.checkIdentity(mappedUtils, Target_java_nio_MappedMemoryUtils.PROXY);
Expand All @@ -142,7 +137,6 @@ public boolean isLoadedInternal(MemorySessionImpl session, MappedMemoryUtilsProx
@SuppressWarnings("static-method")
@Substitute
@Target_jdk_internal_misc_ScopedMemoryAccess_Scoped
@TargetElement(onlyWith = JDKLatest.class)
@AlwaysInline("Safepoints must be visible in caller")
public void unloadInternal(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, long address, boolean isSync, long size) {
SubstrateForeignUtil.checkIdentity(mappedUtils, Target_java_nio_MappedMemoryUtils.PROXY);
Expand All @@ -165,7 +159,6 @@ public void unloadInternal(MemorySessionImpl session, MappedMemoryUtilsProxy map
@SuppressWarnings("static-method")
@Substitute
@Target_jdk_internal_misc_ScopedMemoryAccess_Scoped
@TargetElement(onlyWith = JDKLatest.class)
@AlwaysInline("Safepoints must be visible in caller")
public void forceInternal(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, FileDescriptor fd, long address, boolean isSync, long index, long length) {
SubstrateForeignUtil.checkIdentity(mappedUtils, Target_java_nio_MappedMemoryUtils.PROXY);
Expand Down Expand Up @@ -202,22 +195,13 @@ public void forceInternal(MemorySessionImpl session, MappedMemoryUtilsProxy mapp
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+20/src/hotspot/share/prims/scopedMemoryAccess.cpp#L215-L218")
@SuppressWarnings("static-method")
@Substitute
@TargetElement(onlyWith = JDKLatest.class)
void closeScope0(Target_jdk_internal_foreign_MemorySessionImpl session, @SuppressWarnings("unused") Target_jdk_internal_misc_ScopedMemoryAccess_ScopedAccessError error) {
new SyncCloseScopeOperation(session).enqueue();
}

@SuppressWarnings("static-method")
@Substitute
@TargetElement(onlyWith = JDK21OrEarlier.class)
boolean closeScope0(Target_jdk_internal_foreign_MemorySessionImpl session) {
new SyncCloseScopeOperation(session).enqueue();
return true;
}
}

@Retention(RetentionPolicy.RUNTIME)
@TargetClass(className = "jdk.internal.misc.ScopedMemoryAccess$Scoped", onlyWith = {JDKLatest.class, ForeignAPIPredicates.Enabled.class})
@TargetClass(className = "jdk.internal.misc.ScopedMemoryAccess$Scoped", onlyWith = ForeignAPIPredicates.Enabled.class)
@interface Target_jdk_internal_misc_ScopedMemoryAccess_Scoped {

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@
import com.oracle.svm.core.jfr.Target_jdk_jfr_internal_dcmd_AbstractDCmd;
import com.oracle.svm.core.util.VMError;

import jdk.graal.compiler.serviceprovider.JavaVersionUtil;

/**
* Base class for JFR-related diagnostic commands. Note that the JDK already implements those
* diagnostic commands, so we wrap and reuse the JDK implementations.
Expand Down Expand Up @@ -57,16 +55,9 @@ protected String execute(DCmdArguments args) throws Throwable {
@Override
protected String getSyntaxAndExamples() {
Target_jdk_jfr_internal_dcmd_AbstractDCmd cmd = createDCmd();
String[] lines = getHelp(cmd);
String[] lines = cmd.getHelp();
return String.join(System.lineSeparator(), lines);
}

private static String[] getHelp(Target_jdk_jfr_internal_dcmd_AbstractDCmd cmd) {
if (JavaVersionUtil.JAVA_SPEC <= 21) {
return cmd.printHelp();
}
return cmd.getHelp();
}

protected abstract Target_jdk_jfr_internal_dcmd_AbstractDCmd createDCmd();
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;

import jdk.graal.compiler.serviceprovider.JavaVersionUtil;
import org.graalvm.word.Pointer;

import com.oracle.svm.core.NeverInline;
Expand Down Expand Up @@ -162,8 +161,7 @@ public static <T> void setNextDiscovered(Reference<T> instance, Reference<?> new
}

public static boolean hasQueue(Reference<?> instance) {
return cast(instance).queue != (JavaVersionUtil.JAVA_SPEC > 21 ? Target_java_lang_ref_ReferenceQueue.NULL_QUEUE
: Target_java_lang_ref_ReferenceQueue.NULL);
return cast(instance).queue != Target_java_lang_ref_ReferenceQueue.NULL_QUEUE;
}

/*
Expand Down Expand Up @@ -231,8 +229,7 @@ public static void processPendingReferences() {
} else {
@SuppressWarnings("unchecked")
Target_java_lang_ref_ReferenceQueue<? super Object> queue = SubstrateUtil.cast(ref.queue, Target_java_lang_ref_ReferenceQueue.class);
if (queue != (JavaVersionUtil.JAVA_SPEC > 21 ? Target_java_lang_ref_ReferenceQueue.NULL_QUEUE
: Target_java_lang_ref_ReferenceQueue.NULL)) {
if (queue != Target_java_lang_ref_ReferenceQueue.NULL_QUEUE) {
// Enqueues, avoiding the potentially overridden Reference.enqueue().
queue.enqueue(ref);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.core.annotate.TargetElement;
import com.oracle.svm.core.jdk.JDKLatest;

@TargetClass(PhantomReference.class)
public final class Target_java_lang_ref_PhantomReference<T> {
Expand All @@ -40,7 +38,6 @@ boolean refersTo0(Object obj) {
}

@Substitute
@TargetElement(onlyWith = JDKLatest.class)
private void clear0() {
ReferenceInternals.clear(SubstrateUtil.cast(this, PhantomReference.class));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import java.lang.reflect.Field;
import java.util.function.BooleanSupplier;

import jdk.graal.compiler.serviceprovider.JavaVersionUtil;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.nativeimage.hosted.FieldValueTransformer;
Expand All @@ -44,8 +43,6 @@
import com.oracle.svm.core.annotate.RecomputeFieldValue;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.core.annotate.TargetElement;
import com.oracle.svm.core.jdk.JDKLatest;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.util.ReflectionUtil;

Expand Down Expand Up @@ -120,8 +117,7 @@ public final class Target_java_lang_ref_Reference<T> {
@Uninterruptible(reason = "The initialization of the fields must be atomic with respect to collection.")
Target_java_lang_ref_Reference(T referent, Target_java_lang_ref_ReferenceQueue<? super T> queue) {
this.referent = referent;
this.queue = (queue == null) ? (JavaVersionUtil.JAVA_SPEC > 21 ? Target_java_lang_ref_ReferenceQueue.NULL_QUEUE
: Target_java_lang_ref_ReferenceQueue.NULL) : queue;
this.queue = (queue == null) ? Target_java_lang_ref_ReferenceQueue.NULL_QUEUE : queue;
}

@KeepOriginal
Expand All @@ -135,7 +131,6 @@ private void clear0() {
ReferenceInternals.clear(SubstrateUtil.cast(this, Reference.class));
}

@TargetElement(onlyWith = JDKLatest.class)
@KeepOriginal
native void clearImpl();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,14 @@
import com.oracle.svm.core.annotate.Alias;
import com.oracle.svm.core.annotate.RecomputeFieldValue;
import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.core.annotate.TargetElement;
import com.oracle.svm.core.jdk.JDK21OrEarlier;
import com.oracle.svm.core.jdk.JDKLatest;

@TargetClass(ReferenceQueue.class)
final class Target_java_lang_ref_ReferenceQueue<T> {
// Checkstyle: stop
@Alias //
@TargetElement(onlyWith = JDKLatest.class) //
static Target_java_lang_ref_ReferenceQueue<Object> NULL_QUEUE;
// CheckStyle: resume

@Alias //
@TargetElement(onlyWith = JDK21OrEarlier.class) //
static Target_java_lang_ref_ReferenceQueue<Object> NULL;

@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) //
volatile Reference<? extends T> head;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import java.lang.ref.Cleaner;
import java.lang.ref.ReferenceQueue;

import jdk.graal.compiler.serviceprovider.JavaVersionUtil;
import org.graalvm.nativeimage.hosted.FieldValueTransformer;

import com.oracle.svm.core.NeverInline;
Expand All @@ -37,11 +36,10 @@
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.core.annotate.TargetElement;
import com.oracle.svm.core.jdk.JDK21OrEarlier;
import com.oracle.svm.core.jdk.JDKLatest;
import com.oracle.svm.core.thread.VMThreads;
import com.oracle.svm.util.ReflectionUtil;

import jdk.graal.compiler.serviceprovider.JavaVersionUtil;
import jdk.internal.misc.InnocuousThread;

@TargetClass(className = "jdk.internal.ref.Cleaner")
Expand Down Expand Up @@ -79,45 +77,13 @@ final class Target_java_lang_ref_Cleaner_Cleanable {
@TargetClass(className = "jdk.internal.ref.CleanerImpl")
final class Target_jdk_internal_ref_CleanerImpl {

@TargetElement(onlyWith = JDK21OrEarlier.class)//
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.NewInstance, declClassName = "jdk.internal.ref.CleanerImpl$PhantomCleanableRef")//
Target_jdk_internal_ref_PhantomCleanable_JDK21 phantomCleanableList;

@TargetElement(onlyWith = JDKLatest.class)//
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.NewInstance, declClassName = "jdk.internal.ref.CleanerImpl$CleanableList")//
Target_jdk_internal_ref_CleanerImpl_CleanableList activeList;

@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.NewInstance, declClassName = "java.lang.ref.ReferenceQueue")//
public ReferenceQueue<Object> queue;

/**
* This loop executes in a daemon thread and waits until there are no more cleanables (including
* the {@code Cleaner} itself), ignoring {@link InterruptedException}. This blocks VM tear-down,
* so we add a check if the VM is tearing down here.
*/
@TargetElement(name = "run", onlyWith = JDK21OrEarlier.class)
@Substitute
public void runJDK21() {
Thread t = Thread.currentThread();
InnocuousThread mlThread = (t instanceof InnocuousThread) ? (InnocuousThread) t : null;
while (!phantomCleanableList.isListEmpty()) {
if (mlThread != null) {
mlThread.eraseThreadLocals();
}
try {
Cleaner.Cleanable ref = (Cleaner.Cleanable) queue.remove(60 * 1000L);
if (ref != null) {
ref.clean();
}
} catch (Throwable e) {
if (VMThreads.isTearingDown()) {
return;
}
}
}
}

@TargetElement(name = "run", onlyWith = JDKLatest.class)
@TargetElement(name = "run")
@Substitute
public void run() {
Thread t = Thread.currentThread();
Expand All @@ -140,28 +106,7 @@ public void run() {
}
}

@TargetClass(className = "jdk.internal.ref.PhantomCleanable", onlyWith = JDK21OrEarlier.class)
final class Target_jdk_internal_ref_PhantomCleanable_JDK21 {
/*
* Unlink from the list for the image heap so that we cannot reach Cleanables irrelevant for the
* image heap which could fail the image build; we reset the list head anyway.
*/
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = HolderObjectFieldTransformer.class) //
Target_jdk_internal_ref_PhantomCleanable_JDK21 prev;
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = HolderObjectFieldTransformer.class) //
Target_jdk_internal_ref_PhantomCleanable_JDK21 next;
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = HolderObjectFieldTransformer.class) //
Target_jdk_internal_ref_PhantomCleanable_JDK21 list;

@Alias
native boolean isListEmpty();

@AnnotateOriginal
@NeverInline("Ensure that every exception can be caught, including implicit exceptions.")
/* final */ native void clean();
}

@TargetClass(className = "jdk.internal.ref.PhantomCleanable", onlyWith = JDKLatest.class)
@TargetClass(className = "jdk.internal.ref.PhantomCleanable")
final class Target_jdk_internal_ref_PhantomCleanable {
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = GetCleanableListSingletonTransformer.class) //
Target_jdk_internal_ref_CleanerImpl_CleanableList list;
Expand All @@ -175,7 +120,7 @@ final class Target_jdk_internal_ref_PhantomCleanable {
/* final */ native void clean();
}

@TargetClass(className = "jdk.internal.ref.CleanerImpl$CleanableList", onlyWith = JDKLatest.class)
@TargetClass(className = "jdk.internal.ref.CleanerImpl$CleanableList")
final class Target_jdk_internal_ref_CleanerImpl_CleanableList {

@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.NewInstance, declClassName = "jdk.internal.ref.CleanerImpl$CleanableList$Node") //
Expand All @@ -189,7 +134,7 @@ final class Target_jdk_internal_ref_CleanerImpl_CleanableList {

}

@TargetClass(className = "jdk.internal.ref.CleanerImpl$CleanableList$Node", onlyWith = JDKLatest.class)
@TargetClass(className = "jdk.internal.ref.CleanerImpl$CleanableList$Node")
final class Target_jdk_internal_ref_CleanerImpl_CleanableList_Node {
}

Expand Down
Loading