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
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,22 @@
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Stream;

import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.Isolate;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platform.HOSTED_ONLY;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.word.Pointer;

Expand All @@ -59,6 +62,7 @@
import com.oracle.svm.core.util.BasedOnJDKClass;
import com.oracle.svm.core.util.BasedOnJDKFile;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.util.ReflectionUtil;

import jdk.graal.compiler.api.replacements.Fold;
import jdk.graal.compiler.asm.Label;
Expand All @@ -83,7 +87,6 @@
import jdk.internal.foreign.abi.VMStorage;
import jdk.internal.foreign.abi.aarch64.AArch64Architecture;
import jdk.internal.foreign.abi.x64.X86_64Architecture;
import jdk.internal.foreign.abi.x64.sysv.CallArranger;
import jdk.vm.ci.aarch64.AArch64;
import jdk.vm.ci.amd64.AMD64;
import jdk.vm.ci.code.Register;
Expand Down Expand Up @@ -491,15 +494,31 @@ public static AbiUtils singleton() {
return ImageSingletons.lookup(AbiUtils.class);
}

/**
* Specifies if a method handle invoked by an upcall stub needs to drop its return value in case
* of an in-memory return type. See also: {@link java.lang.invoke.MethodHandles#dropReturn} and
* {@code jdk.internal.foreign.abi.SharedUtils#adaptUpcallForIMR}
*/
@Platforms(Platform.HOSTED_ONLY.class)
public abstract boolean dropReturn();

/**
* Calls method {@code isInMemoryReturn} of the appropriate {@code CallArranger}. This method
* determines, if a given return type requires an in-memory return on the current platform.
*/
@Platforms(Platform.HOSTED_ONLY.class)
public abstract boolean isInMemoryReturn(Optional<MemoryLayout> returnLayout);

protected abstract CallingSequence makeCallingSequence(MethodType type, FunctionDescriptor desc, boolean forUpcall, LinkerOptions options);

/**
* This method re-implements a part of the logic from the JDK so that we can get the callee-type
* (i.e. the ABI low-level type) of a function from its descriptor.
*/
@Platforms(HOSTED_ONLY.class)
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java#L99")
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/java.base/share/classes/jdk/internal/foreign/abi/DowncallLinker.java#L71-L85")
public NativeEntryPointInfo makeNativeEntrypoint(FunctionDescriptor desc, LinkerOptions linkerOptions) {
public final NativeEntryPointInfo makeNativeEntrypoint(FunctionDescriptor desc, LinkerOptions linkerOptions) {
// From Linker.downcallHandle implemented in AbstractLinker.downcallHandle:
// From AbstractLinker.downcallHandle0
MethodType type = desc.toMethodType();
Expand All @@ -519,9 +538,9 @@ public NativeEntryPointInfo makeNativeEntrypoint(FunctionDescriptor desc, Linker
linkerOptions.allowsHeapAccess());
}

@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java#L124")
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java#L126")
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/java.base/share/classes/jdk/internal/foreign/abi/UpcallLinker.java#L62-L110")
public JavaEntryPointInfo makeJavaEntryPoint(FunctionDescriptor desc, LinkerOptions linkerOptions) {
public final JavaEntryPointInfo makeJavaEntryPoint(FunctionDescriptor desc, LinkerOptions linkerOptions) {
// Linker.upcallStub implemented in AbstractLinker.upcallStub
MethodType type = desc.toMethodType();

Expand Down Expand Up @@ -659,7 +678,7 @@ public Pointer write(Pointer at, Isolate isolate, Word methodHandle, Word stubPo
}

@Platforms(Platform.HOSTED_ONLY.class)
public abstract TrampolineTemplate generateTrampolineTemplate();
abstract TrampolineTemplate generateTrampolineTemplate();
}

class ABIs {
Expand Down Expand Up @@ -716,12 +735,26 @@ public int trampolineSize() {
public TrampolineTemplate generateTrampolineTemplate() {
return null;
}

@Override
public boolean dropReturn() {
return fail();
}

@Override
public boolean isInMemoryReturn(Optional<MemoryLayout> returnLayout) {
return fail();
}
}

@BasedOnJDKClass(AArch64Architecture.class)
@BasedOnJDKClass(jdk.internal.foreign.abi.DowncallLinker.class)
@BasedOnJDKClass(jdk.internal.foreign.abi.UpcallLinker.class)
abstract static class ARM64 extends AbiUtils {

@Platforms(Platform.HOSTED_ONLY.class) //
private static final Method IS_IN_MEMORY_RETURN = ReflectionUtil.lookupMethod(jdk.internal.foreign.abi.aarch64.CallArranger.class, "isInMemoryReturn", Optional.class);

@Override
public Registers upcallSpecialArgumentsRegisters() {
return new Registers(SubstrateAArch64MacroAssembler.scratch1, SubstrateAArch64MacroAssembler.scratch2);
Expand Down Expand Up @@ -815,6 +848,17 @@ public TrampolineTemplate generateTrampolineTemplate() {

return new TrampolineTemplate(assembly, posIsolate, posMHArray, posCallTarget);
}

@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/CallArranger.java#L195")
@Override
public boolean dropReturn() {
return true;
}

@Override
public boolean isInMemoryReturn(Optional<MemoryLayout> returnLayout) {
return ReflectionUtil.invokeMethod(IS_IN_MEMORY_RETURN, null, returnLayout);
}
}

@BasedOnJDKClass(jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker.class)
Expand Down Expand Up @@ -961,6 +1005,10 @@ public TrampolineTemplate generateTrampolineTemplate() {
@BasedOnJDKClass(jdk.internal.foreign.abi.x64.sysv.SysVx64Linker.class)
@BasedOnJDKClass(jdk.internal.foreign.abi.x64.sysv.CallArranger.class)
static final class SysV extends X86_64 {

@Platforms(Platform.HOSTED_ONLY.class) //
private static final Method IS_IN_MEMORY_RETURN = ReflectionUtil.lookupMethod(jdk.internal.foreign.abi.x64.sysv.CallArranger.class, "isInMemoryReturn", Optional.class);

@Override
protected CallingSequence makeCallingSequence(MethodType type, FunctionDescriptor desc, boolean forUpcall, LinkerOptions options) {
return jdk.internal.foreign.abi.x64.sysv.CallArranger.getBindings(type, desc, forUpcall, options).callingSequence();
Expand Down Expand Up @@ -1002,11 +1050,26 @@ public void checkLibrarySupport() {
public Map<String, MemoryLayout> canonicalLayouts() {
return SharedUtils.canonicalLayouts(ValueLayout.JAVA_LONG, ValueLayout.JAVA_LONG, ValueLayout.JAVA_INT);
}

@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/CallArranger.java#L147")
@Override
public boolean dropReturn() {
return true;
}

@Override
public boolean isInMemoryReturn(Optional<MemoryLayout> returnLayout) {
return ReflectionUtil.invokeMethod(IS_IN_MEMORY_RETURN, null, returnLayout);
}
}

@BasedOnJDKClass(jdk.internal.foreign.abi.x64.windows.Windowsx64Linker.class)
@BasedOnJDKClass(jdk.internal.foreign.abi.x64.windows.CallArranger.class)
static final class Win64 extends X86_64 {

@Platforms(Platform.HOSTED_ONLY.class) //
private static final Method IS_IN_MEMORY_RETURN = ReflectionUtil.lookupMethod(jdk.internal.foreign.abi.x64.windows.CallArranger.class, "isInMemoryReturn", Optional.class);

@Override
protected CallingSequence makeCallingSequence(MethodType type, FunctionDescriptor desc, boolean forUpcall, LinkerOptions options) {
return jdk.internal.foreign.abi.x64.windows.CallArranger.getBindings(type, desc, forUpcall, options).callingSequence();
Expand Down Expand Up @@ -1058,6 +1121,17 @@ public void checkLibrarySupport() {
public Map<String, MemoryLayout> canonicalLayouts() {
return SharedUtils.canonicalLayouts(ValueLayout.JAVA_INT, ValueLayout.JAVA_LONG, ValueLayout.JAVA_CHAR);
}

@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/CallArranger.java#L139")
@Override
public boolean dropReturn() {
return false;
}

@Override
public boolean isInMemoryReturn(Optional<MemoryLayout> returnLayout) {
return ReflectionUtil.invokeMethod(IS_IN_MEMORY_RETURN, null, returnLayout);
}
}

@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+11/src/java.base/share/classes/jdk/internal/foreign/abi/DowncallLinker.java#L122-L140")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import static jdk.graal.compiler.core.common.spi.ForeignCallDescriptor.CallSideEffect.HAS_SIDE_EFFECT;

import java.lang.constant.DirectMethodHandleDesc;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySegment.Scope;
import java.lang.invoke.MethodHandle;
Expand All @@ -36,6 +37,7 @@
import java.util.function.BiConsumer;

import org.graalvm.collections.EconomicMap;
import org.graalvm.collections.Pair;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
Expand Down Expand Up @@ -64,6 +66,7 @@
import jdk.internal.foreign.CABI;
import jdk.internal.foreign.MemorySessionImpl;
import jdk.internal.foreign.abi.CapturableState;
import jdk.internal.foreign.abi.LinkerOptions;

public class ForeignFunctionsRuntime implements ForeignSupport {
@Fold
Expand All @@ -73,7 +76,7 @@ public static ForeignFunctionsRuntime singleton() {

private final AbiUtils.TrampolineTemplate trampolineTemplate;
private final EconomicMap<NativeEntryPointInfo, FunctionPointerHolder> downcallStubs = EconomicMap.create();
private final EconomicMap<DirectMethodHandleDesc, FunctionPointerHolder> directUpcallStubs = EconomicMap.create();
private final EconomicMap<Pair<DirectMethodHandleDesc, JavaEntryPointInfo>, FunctionPointerHolder> directUpcallStubs = EconomicMap.create();
private final EconomicMap<JavaEntryPointInfo, FunctionPointerHolder> upcallStubs = EconomicMap.create();

private final Map<Long, TrampolineSet> trampolines = new HashMap<>();
Expand Down Expand Up @@ -115,9 +118,10 @@ public void addUpcallStubPointer(JavaEntryPointInfo jep, CFunctionPointer ptr) {
}

@Platforms(Platform.HOSTED_ONLY.class)
public void addDirectUpcallStubPointer(DirectMethodHandleDesc desc, CFunctionPointer ptr) {
VMError.guarantee(!directUpcallStubs.containsKey(desc), "Seems like multiple stubs were generated for %s", desc);
VMError.guarantee(directUpcallStubs.put(desc, new FunctionPointerHolder(ptr)) == null);
public void addDirectUpcallStubPointer(DirectMethodHandleDesc desc, JavaEntryPointInfo jep, CFunctionPointer ptr) {
var key = Pair.create(desc, jep);
VMError.guarantee(!directUpcallStubs.containsKey(key), "Seems like multiple stubs were generated for %s", desc);
VMError.guarantee(directUpcallStubs.put(key, new FunctionPointerHolder(ptr)) == null);
}

/**
Expand Down Expand Up @@ -168,8 +172,9 @@ Pointer registerForUpcall(MethodHandle methodHandle, JavaEntryPointInfo jep) {
* @param trampolineAddress The address of the upcall trampoline.
* @param desc A direct method handle descriptor used to lookup the direct upcall stub.
*/
void patchForDirectUpcall(long trampolineAddress, DirectMethodHandleDesc desc) {
FunctionPointerHolder functionPointerHolder = directUpcallStubs.get(desc);
void patchForDirectUpcall(long trampolineAddress, DirectMethodHandleDesc desc, FunctionDescriptor functionDescriptor, LinkerOptions options) {
JavaEntryPointInfo jep = AbiUtils.singleton().makeJavaEntryPoint(functionDescriptor, options);
FunctionPointerHolder functionPointerHolder = directUpcallStubs.get(Pair.create(desc, jep));
if (functionPointerHolder == null) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ final class Target_jdk_internal_foreign_abi_SoftReferenceCache {
*
* @param delegate The original upcall stub factory as created by JDK's call arranger.
*/
record UpcallStubFactoryDecorator(UpcallStubFactory delegate) implements UpcallStubFactory {
record UpcallStubFactoryDecorator(UpcallStubFactory delegate, FunctionDescriptor function, LinkerOptions options) implements UpcallStubFactory {

@Override
public MemorySegment makeStub(MethodHandle target, Arena arena) {
Expand All @@ -86,7 +86,7 @@ public MemorySegment makeStub(MethodHandle target, Arena arena) {
*/
Optional<MethodHandleDesc> methodHandleDesc = target.describeConstable();
if (methodHandleDesc.isPresent() && methodHandleDesc.get() instanceof DirectMethodHandleDesc desc) {
ForeignFunctionsRuntime.singleton().patchForDirectUpcall(segment.address(), desc);
ForeignFunctionsRuntime.singleton().patchForDirectUpcall(segment.address(), desc, function, options);
}
return segment;
}
Expand All @@ -97,7 +97,7 @@ final class Target_jdk_internal_foreign_abi_x64_sysv_SysVx64Linker {

@Substitute
UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) {
return new UpcallStubFactoryDecorator(jdk.internal.foreign.abi.x64.sysv.CallArranger.arrangeUpcall(targetType, function, options));
return new UpcallStubFactoryDecorator(jdk.internal.foreign.abi.x64.sysv.CallArranger.arrangeUpcall(targetType, function, options), function, options);
}
}

Expand All @@ -106,7 +106,7 @@ final class Target_jdk_internal_foreign_abi_x64_windows_Windowsx64Linker {

@Substitute
UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) {
return new UpcallStubFactoryDecorator(jdk.internal.foreign.abi.x64.windows.CallArranger.arrangeUpcall(targetType, function, options));
return new UpcallStubFactoryDecorator(jdk.internal.foreign.abi.x64.windows.CallArranger.arrangeUpcall(targetType, function, options), function, options);
}
}

Expand All @@ -115,7 +115,7 @@ final class Target_jdk_internal_foreign_abi_aarch64_macos_MacOsAArch64Linker {

@Substitute
UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) {
return new UpcallStubFactoryDecorator(jdk.internal.foreign.abi.aarch64.CallArranger.MACOS.arrangeUpcall(targetType, function, options));
return new UpcallStubFactoryDecorator(jdk.internal.foreign.abi.aarch64.CallArranger.MACOS.arrangeUpcall(targetType, function, options), function, options);
}
}

Expand All @@ -124,6 +124,6 @@ final class Target_jdk_internal_foreign_abi_aarch64_linux_LinuxAArch64Linker {

@Substitute
UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) {
return new UpcallStubFactoryDecorator(jdk.internal.foreign.abi.aarch64.CallArranger.LINUX.arrangeUpcall(targetType, function, options));
return new UpcallStubFactoryDecorator(jdk.internal.foreign.abi.aarch64.CallArranger.LINUX.arrangeUpcall(targetType, function, options), function, options);
}
}
Loading