Skip to content
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
3 changes: 1 addition & 2 deletions substratevm/mx.substratevm/mx_substratevm_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -936,8 +936,7 @@ def _empty_file():
# 2. Native-image picks a different service provider than the JVM for javax.xml.transform.TransformerFactory.
# We can simply remove the jar containing that provider as it is not required for the benchmark to run.
'fop': [f"-Djava.util.logging.config.file={_empty_file()}",
'--initialize-at-run-time=org.apache.fop.render.rtf.rtflib.rtfdoc.RtfList',
'-H:+ForeignAPISupport'],
'--initialize-at-run-time=org.apache.fop.render.rtf.rtflib.rtfdoc.RtfList'],
'batik': []
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ public enum Extracted {
CaptureBufferAddress
}

@Platforms(Platform.HOSTED_ONLY.class)
public static class Result {
@Platforms(Platform.HOSTED_ONLY.class)
public record FullNativeAdaptation(
Map<Extracted, ValueNode> extractedArguments,
List<ValueNode> arguments,
Expand All @@ -131,10 +133,12 @@ public ValueNode getArgument(Extracted id) {
}
}

@Platforms(Platform.HOSTED_ONLY.class)
public record TypeAdaptation(List<AssignedLocation> parametersAssignment, MethodType callType) {
}
}

@Platforms(Platform.HOSTED_ONLY.class)
public static Result.FullNativeAdaptation adaptToNative(AbiUtils self, List<Adaptation> adaptations, List<ValueNode> originalArguments, NativeEntryPointInfo nep) {
List<ValueNode> originalUnmodifiableArguments = Collections.unmodifiableList(originalArguments);

Expand Down Expand Up @@ -175,6 +179,7 @@ public static Result.FullNativeAdaptation adaptToNative(AbiUtils self, List<Adap
MethodType.methodType(nep.methodType().returnType(), argumentTypes), nodesToAppendToGraph);
}

@Platforms(Platform.HOSTED_ONLY.class)
public static Result.TypeAdaptation adaptFromNative(AbiUtils self, List<Adaptation> adaptations, JavaEntryPointInfo jep) {
AssignedLocation[] originalAssignment = self.toMemoryAssignment(jep.parametersAssignment(), false);

Expand Down Expand Up @@ -622,6 +627,7 @@ protected List<Adapter.Adaptation> generateAdaptations(NativeEntryPointInfo nep)
}

@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+27/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/CallArranger.java#L280-L290")
@Platforms(Platform.HOSTED_ONLY.class)
private static void handleCriticalWithHeapAccess(NativeEntryPointInfo nep, int i, List<Adaptation> adaptations, Adaptation adaptation) {
VMError.guarantee(nep.allowHeapAccess(), "A storage may only be null when the Linker.Option.critical(true) option is passed.");
VMError.guarantee(
Expand Down Expand Up @@ -709,6 +715,7 @@ public AssignedLocation[] toMemoryAssignment(VMStorage[] moves, boolean forRetur
}

@Override
@Platforms(Platform.HOSTED_ONLY.class)
protected List<Adapter.Adaptation> generateAdaptations(NativeEntryPointInfo nep) {
return fail();
}
Expand Down Expand Up @@ -1017,6 +1024,7 @@ protected CallingSequence makeCallingSequence(MethodType type, FunctionDescripto
}

@Override
@Platforms(Platform.HOSTED_ONLY.class)
protected List<Adapter.Adaptation> generateAdaptations(NativeEntryPointInfo nep) {
var adaptations = super.generateAdaptations(nep);
var assignments = nep.parametersAssignment();
Expand Down Expand Up @@ -1088,6 +1096,7 @@ protected CallingSequence makeCallingSequence(MethodType type, FunctionDescripto
* assignments of float/double parameters to a cpu register.
*/
@Override
@Platforms(Platform.HOSTED_ONLY.class)
protected List<Adapter.Adaptation> generateAdaptations(NativeEntryPointInfo nep) {
List<Adapter.Adaptation> adaptations = super.generateAdaptations(nep);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@

import java.util.function.BooleanSupplier;

import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;

import com.oracle.svm.core.SubstrateOptions;
import com.oracle.svm.core.option.SubstrateOptionsParser;
import com.oracle.svm.core.util.VMError;

/**
* Set of predicates used to control activation of substitutions (depending on method
Expand All @@ -39,21 +44,51 @@ public final class ForeignAPIPredicates {
public static final class Enabled implements BooleanSupplier {
@Override
public boolean getAsBoolean() {
return SubstrateOptions.ForeignAPISupport.getValue();
return SubstrateOptions.isForeignAPIEnabled();
}
}

public static final class FunctionCallsSupported implements BooleanSupplier {
@Override
public boolean getAsBoolean() {
return SubstrateOptions.ForeignAPISupport.getValue() && ForeignFunctionsRuntime.areFunctionCallsSupported();
return SubstrateOptions.isForeignAPIEnabled() && ForeignFunctionsRuntime.areFunctionCallsSupported();
}
}

public static final class FunctionCallsUnsupported implements BooleanSupplier {
@Override
public boolean getAsBoolean() {
return SubstrateOptions.ForeignAPISupport.getValue() && !ForeignFunctionsRuntime.areFunctionCallsSupported();
return SubstrateOptions.isForeignAPIEnabled() && !ForeignFunctionsRuntime.areFunctionCallsSupported();
}
}

@Platforms(Platform.HOSTED_ONLY.class)
public static final class SharedArenasEnabled implements BooleanSupplier {
public static boolean getValue() {
return SubstrateOptions.isForeignAPIEnabled() && SubstrateOptions.SharedArenaSupport.getValue();
}

@Override
public boolean getAsBoolean() {
return SharedArenasEnabled.getValue();
}
}

public static final class SharedArenasDisabled implements BooleanSupplier {
private static final String SHARED_ARENA_SUPPORT_OPTION_NAME = SubstrateOptionsParser.commandArgument(SubstrateOptions.SharedArenaSupport, "+");

@Platforms(Platform.HOSTED_ONLY.class)
SharedArenasDisabled() {
}

@Override
public boolean getAsBoolean() {
return !SharedArenasEnabled.getValue();
}

public static RuntimeException fail() {
assert !SharedArenasEnabled.getValue();
throw VMError.unsupportedFeature("Support for Arena.ofShared is not active: enable with " + SHARED_ARENA_SUPPORT_OPTION_NAME);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public static boolean areFunctionCallsSupported() {
}

public static RuntimeException functionCallsUnsupported() {
assert SubstrateOptions.ForeignAPISupport.getValue();
assert SubstrateOptions.isForeignAPIEnabled();
throw VMError.unsupportedFeature("Calling foreign functions is currently not supported on platform: " +
(OS.getCurrent().className + "-" + SubstrateUtil.getArchitectureName()).toLowerCase(Locale.ROOT));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,15 @@
import java.util.Optional;
import java.util.function.Function;

import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platform.DARWIN;
import org.graalvm.nativeimage.Platform.WINDOWS;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.nativeimage.c.function.CFunction;
import org.graalvm.nativeimage.c.function.CFunction.Transition;
import org.graalvm.nativeimage.c.function.CLibrary;
import org.graalvm.word.Pointer;

import com.oracle.svm.core.OS;
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.util.BasedOnJDKClass;

Expand All @@ -56,7 +57,7 @@ public final class RuntimeSystemLookup {
static final SymbolLookup INSTANCE = makeSystemLookup();

public static SymbolLookup makeSystemLookup() {
if (OS.WINDOWS.isCurrent()) {
if (Platform.includedIn(WINDOWS.class)) {
/*
* Windows support has some subtleties: one would ideally load ucrtbase.dll, but some
* old installs might not have it, in which case msvcrt.dll should be loaded instead. If
Expand Down Expand Up @@ -93,7 +94,7 @@ public static SymbolLookup makeSystemLookup() {
}

return lookup;
} else if (OS.DARWIN.isCurrent()) {
} else if (Platform.includedIn(DARWIN.class)) {
return Util_java_lang_foreign_SymbolLookup.libraryLookup(LookupNativeLibraries::loadLibraryPlatformSpecific, List.of("/usr/lib/libSystem.B.dylib"));
} else {
/*
Expand All @@ -114,6 +115,7 @@ public static SymbolLookup makeSystemLookup() {
@CFunction(value = "__svm_get_syslookup_func", transition = Transition.NO_TRANSITION)
public static native Pointer getSyslookupFunc(int i, int nExpected);

@Platforms(WINDOWS.class)
private static Pointer getWindowsFallbackSymbol(String name) {
try {
assert Target_jdk_internal_foreign_SystemLookup_WindowsFallbackSymbols.class.isEnum();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@
package com.oracle.svm.core.foreign;

import java.lang.foreign.MemorySegment;
import java.lang.foreign.SymbolLookup;
import java.util.Optional;

import com.oracle.svm.core.annotate.Alias;
import com.oracle.svm.core.annotate.RecomputeFieldValue;
import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;

Expand All @@ -37,11 +41,22 @@
*/
@TargetClass(className = "jdk.internal.foreign.SystemLookup", onlyWith = ForeignAPIPredicates.Enabled.class)
public final class Target_jdk_internal_foreign_SystemLookup {
// Checkstyle: stop

/*
* This field must be cleared because on Windows, it references a closure which contains a
* native memory segment.
*/
@Alias //
@RecomputeFieldValue(isFinal = true, kind = Kind.Reset) //
static SymbolLookup SYSTEM_LOOKUP;

@SuppressWarnings("static-method")
@Substitute
public Optional<MemorySegment> find(String name) {
return RuntimeSystemLookup.INSTANCE.find(name);
}
// Checkstyle: resume
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
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.foreign.ForeignAPIPredicates.SharedArenasDisabled;
import com.oracle.svm.core.foreign.ForeignAPIPredicates.SharedArenasEnabled;
import com.oracle.svm.core.nodes.foreign.MemoryArenaValidInScopeNode;
import com.oracle.svm.core.util.BasedOnJDKFile;

Expand Down Expand Up @@ -96,7 +99,8 @@ static void registerNatives() {
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+20/src/java.base/share/classes/java/nio/MappedMemoryUtils.java#L50-L77")
@SuppressWarnings("static-method")
@Substitute
@Target_jdk_internal_misc_ScopedMemoryAccess_Scoped
@TargetElement(onlyWith = SharedArenasEnabled.class)
@SVMScoped
@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 @@ -116,7 +120,8 @@ public void loadInternal(MemorySessionImpl session, MappedMemoryUtilsProxy mappe
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+14/src/java.base/share/classes/java/nio/MappedMemoryUtils.java#L182-L185")
@SuppressWarnings("static-method")
@Substitute
@Target_jdk_internal_misc_ScopedMemoryAccess_Scoped
@TargetElement(onlyWith = SharedArenasEnabled.class)
@SVMScoped
@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 @@ -137,7 +142,8 @@ public boolean isLoadedInternal(MemorySessionImpl session, MappedMemoryUtilsProx
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+14/src/java.base/share/classes/java/nio/MappedMemoryUtils.java#L192-L195")
@SuppressWarnings("static-method")
@Substitute
@Target_jdk_internal_misc_ScopedMemoryAccess_Scoped
@TargetElement(onlyWith = SharedArenasEnabled.class)
@SVMScoped
@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 @@ -159,7 +165,8 @@ public void unloadInternal(MemorySessionImpl session, MappedMemoryUtilsProxy map
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+14/src/java.base/share/classes/java/nio/MappedMemoryUtils.java#L197-L200")
@SuppressWarnings("static-method")
@Substitute
@Target_jdk_internal_misc_ScopedMemoryAccess_Scoped
@TargetElement(onlyWith = SharedArenasEnabled.class)
@SVMScoped
@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 @@ -196,13 +203,19 @@ 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 = SharedArenasEnabled.class)
void closeScope0(Target_jdk_internal_foreign_MemorySessionImpl session, @SuppressWarnings("unused") Target_jdk_internal_misc_ScopedMemoryAccess_ScopedAccessError error) {
new SyncCloseScopeOperation(session).enqueue();
}

@Substitute
@TargetElement(name = "closeScope0", onlyWith = SharedArenasDisabled.class)
@SuppressWarnings({"unused", "static-method"})
void closeScope0Unsupported(Target_jdk_internal_foreign_MemorySessionImpl session, Target_jdk_internal_misc_ScopedMemoryAccess_ScopedAccessError error) {
throw SharedArenasDisabled.fail();
}
}

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

@interface SVMScoped {
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -34,7 +34,7 @@ public interface ForeignSupport {
@Fold
static boolean isAvailable() {
boolean result = ImageSingletons.contains(ForeignSupport.class);
assert result || !SubstrateOptions.ForeignAPISupport.getValue();
assert result || !SubstrateOptions.isForeignAPIEnabled();
return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@
import com.oracle.svm.core.c.libc.LibCBase;
import com.oracle.svm.core.c.libc.MuslLibC;
import com.oracle.svm.core.config.ConfigurationValues;
import com.oracle.svm.core.graal.RuntimeCompilation;
import com.oracle.svm.core.heap.ReferenceHandler;
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
import com.oracle.svm.core.jdk.VectorAPIEnabled;
import com.oracle.svm.core.option.APIOption;
import com.oracle.svm.core.option.APIOptionGroup;
import com.oracle.svm.core.option.AccumulatingLocatableMultiOptionValue;
Expand Down Expand Up @@ -1367,11 +1369,34 @@ public enum ReportingMode {
public static final HostedOptionKey<Boolean> UseBaseLayerInclusionPolicy = new HostedOptionKey<>(false);

@Option(help = "Support for calls via the Java Foreign Function and Memory API", type = Expert) //
public static final HostedOptionKey<Boolean> ForeignAPISupport = new HostedOptionKey<>(false);
public static final HostedOptionKey<Boolean> ForeignAPISupport = new HostedOptionKey<>(true);

@Fold
public static boolean isForeignAPIEnabled() {
/*
* FFM API should be enabled by default only if running on a supported and tested platform.
* However, if the option is explicitly enabled, we still return 'true'.
*/
return SubstrateOptions.ForeignAPISupport.getValue() &&
(SubstrateOptions.ForeignAPISupport.hasBeenSet() || Platform.includedIn(PLATFORM_JNI.class) && Platform.includedIn(NATIVE_ONLY.class));
}

@Option(help = "Support for intrinsics from the Java Vector API", type = Expert) //
public static final HostedOptionKey<Boolean> VectorAPISupport = new HostedOptionKey<>(false);

@Option(help = "Enable support for Arena.ofShared ", type = Expert)//
public static final HostedOptionKey<Boolean> SharedArenaSupport = new HostedOptionKey<>(false, key -> {
if (key.getValue()) {
// GR-65268: Shared arenas cannot be used together with runtime compilations
UserError.guarantee(!RuntimeCompilation.isEnabled(), "Arena.ofShared is not supported with runtime compilations. " +
"Replace usages of Arena.ofShared with Arena.ofAuto and disable shared arena support.");
// GR-65162: Shared arenas cannot be used together with Vector API support
UserError.guarantee(!VectorAPIEnabled.getValue(), "Support for Arena.ofShared is not available with Vector API support. " +
"Either disable Vector API support using %s or replace usages of Arena.ofShared with Arena.ofAuto and disable shared arena support.",
SubstrateOptionsParser.commandArgument(VectorAPISupport, "-"));
}
});

@Option(help = "Assume new types cannot be added after analysis", type = OptionType.Expert) //
public static final HostedOptionKey<Boolean> ClosedTypeWorld = new HostedOptionKey<>(true) {
@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -45,7 +45,7 @@
final class ForeignDisabled implements BooleanSupplier {
@Override
public boolean getAsBoolean() {
return !SubstrateOptions.ForeignAPISupport.getValue();
return !SubstrateOptions.isForeignAPIEnabled();
}
}

Expand Down Expand Up @@ -173,7 +173,7 @@ final class ForeignDisabledSubstitutions {
private static final String OPTION_NAME = SubstrateOptionsParser.commandArgument(SubstrateOptions.ForeignAPISupport, "+");

static RuntimeException fail() {
assert !SubstrateOptions.ForeignAPISupport.getValue();
assert !SubstrateOptions.isForeignAPIEnabled();
throw VMError.unsupportedFeature("Support for the Java Foreign Function and Memory API is not active: enable with " + OPTION_NAME);
}
}
Loading