diff --git a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/AbiUtils.java b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/AbiUtils.java index 4256daa31b6f..a24e3d7fec43 100644 --- a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/AbiUtils.java +++ b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/AbiUtils.java @@ -33,6 +33,7 @@ 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; @@ -40,12 +41,14 @@ 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; @@ -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; @@ -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; @@ -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 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(); @@ -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(); @@ -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 { @@ -716,12 +735,26 @@ public int trampolineSize() { public TrampolineTemplate generateTrampolineTemplate() { return null; } + + @Override + public boolean dropReturn() { + return fail(); + } + + @Override + public boolean isInMemoryReturn(Optional 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); @@ -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 returnLayout) { + return ReflectionUtil.invokeMethod(IS_IN_MEMORY_RETURN, null, returnLayout); + } } @BasedOnJDKClass(jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker.class) @@ -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(); @@ -1002,11 +1050,26 @@ public void checkLibrarySupport() { public Map 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 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(); @@ -1058,6 +1121,17 @@ public void checkLibrarySupport() { public Map 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 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") diff --git a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/ForeignFunctionsRuntime.java b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/ForeignFunctionsRuntime.java index 2830a39f6033..c4001e462802 100644 --- a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/ForeignFunctionsRuntime.java +++ b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/ForeignFunctionsRuntime.java @@ -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; @@ -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; @@ -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 @@ -73,7 +76,7 @@ public static ForeignFunctionsRuntime singleton() { private final AbiUtils.TrampolineTemplate trampolineTemplate; private final EconomicMap downcallStubs = EconomicMap.create(); - private final EconomicMap directUpcallStubs = EconomicMap.create(); + private final EconomicMap, FunctionPointerHolder> directUpcallStubs = EconomicMap.create(); private final EconomicMap upcallStubs = EconomicMap.create(); private final Map trampolines = new HashMap<>(); @@ -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); } /** @@ -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; } diff --git a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_foreign_abi_AbstractLinker.java b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_foreign_abi_AbstractLinker.java index 9c9e3112b4e8..821be997fc9f 100644 --- a/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_foreign_abi_AbstractLinker.java +++ b/substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/Target_jdk_internal_foreign_abi_AbstractLinker.java @@ -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) { @@ -86,7 +86,7 @@ public MemorySegment makeStub(MethodHandle target, Arena arena) { */ Optional 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; } @@ -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); } } @@ -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); } } @@ -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); } } @@ -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); } } diff --git a/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/ForeignFunctionsFeature.java b/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/ForeignFunctionsFeature.java index 1f6a98ae76b3..d210c067aeee 100644 --- a/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/ForeignFunctionsFeature.java +++ b/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/ForeignFunctionsFeature.java @@ -40,7 +40,6 @@ import java.lang.reflect.Executable; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -110,6 +109,7 @@ import jdk.internal.foreign.MemorySessionImpl; import jdk.internal.foreign.abi.AbstractLinker; import jdk.internal.foreign.abi.LinkerOptions; +import jdk.internal.foreign.abi.SharedUtils; import jdk.internal.misc.ScopedMemoryAccess.ScopedAccessError; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -393,6 +393,7 @@ private static final class DirectUpcallStubFactory implements StubFactory registeredUpcalls; DirectUpcallStubFactory(AnalysisUniverse universe, MetaAccessProvider metaAccessProvider, Set registeredUpcalls) { @@ -400,12 +401,16 @@ private static final class DirectUpcallStubFactory implements StubFactory doBindingsMaker = lookupAndReadUnaryOperatorField(upcallStubFactory); - MethodHandle doBindings = doBindingsMaker.apply(desc.mh()); + UnaryOperator doBindingsMaker = lookupAndReadUnaryOperatorField(upcallStubFactory, inMemoryReturn); + MethodHandle doBindings = doBindingsMaker.apply(target); doBindings = insertArguments(exactInvoker(doBindings.type()), 0, doBindings); - JavaEntryPointInfo jepi = AbiUtils.singleton().makeJavaEntryPoint(desc.fd(), desc.options()); + + JavaEntryPointInfo jepi = abiUtils.makeJavaEntryPoint(desc.fd(), desc.options()); registeredUpcalls.add(desc.toSharedDesc()); return new DirectUpcall(desc.mhDesc(), doBindings, jepi); } @@ -431,30 +446,56 @@ public UpcallStub generateStub(DirectUpcall directUpcall) { @Override public void registerStub(DirectUpcall stubDescriptor, CFunctionPointer stubPointer) { - ForeignFunctionsRuntime.singleton().addDirectUpcallStubPointer(stubDescriptor.targetDesc(), stubPointer); + ForeignFunctionsRuntime.singleton().addDirectUpcallStubPointer(stubDescriptor.targetDesc(), stubDescriptor.jep(), stubPointer); } /** * Looks up a field of type {@link UnaryOperator}, reads its value and returns it. There * must be exactly one such field that is readable. Otherwise, an Error is thrown. */ - private static UnaryOperator lookupAndReadUnaryOperatorField(AbstractLinker.UpcallStubFactory upcallStubFactory) { - Class upcallStubFactoryClass = upcallStubFactory.getClass(); - List list = Arrays.stream(upcallStubFactoryClass.getDeclaredFields()) - .filter(field -> UnaryOperator.class.isAssignableFrom(field.getType())).toList(); - if (list.size() != 1) { - throw VMError.shouldNotReachHere(COULD_NOT_EXTRACT_METHOD_HANDLE_FOR_UPCALL); + @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/java.base/share/classes/jdk/internal/foreign/abi/UpcallLinker.java#L62-L110") + @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java#L201-L207") + private static UnaryOperator lookupAndReadUnaryOperatorField(AbstractLinker.UpcallStubFactory outerFactory, boolean inMemoryReturn) { + AbstractLinker.UpcallStubFactory upcallStubFactory = outerFactory; + + /* + * The upcall stub factory created in 'UpcallLinker.makeFactory' may be decorated in + * 'SharedUtils.arrangeUpcallHelper' if an in-memory return is necessary. We need to + * extract the original factory first. + */ + if (inMemoryReturn) { + Class outerFactoryClass = outerFactory.getClass(); + Field upcallStubFactoryField = findSingleFieldOfType(AbstractLinker.UpcallStubFactory.class, outerFactoryClass.getDeclaredFields()); + upcallStubFactory = ReflectionUtil.readField(outerFactoryClass, upcallStubFactoryField.getName(), outerFactory); } - Field candidate = list.getFirst(); - assert candidate != null; - UnaryOperator value = ReflectionUtil.readField(upcallStubFactoryClass, candidate.getName(), upcallStubFactory); + Class upcallStubFactoryClass = upcallStubFactory.getClass(); + Field unaryOperatorField = findSingleFieldOfType(UnaryOperator.class, upcallStubFactoryClass.getDeclaredFields()); + UnaryOperator value = ReflectionUtil.readField(upcallStubFactoryClass, unaryOperatorField.getName(), upcallStubFactory); if (value == null) { throw VMError.shouldNotReachHere(COULD_NOT_EXTRACT_METHOD_HANDLE_FOR_UPCALL); } return value; } + + private static Field findSingleFieldOfType(Class expectedFieldType, Field[] declaredFields) { + Field candidate = null; + for (Field field : declaredFields) { + if (expectedFieldType.isAssignableFrom(field.getType())) { + if (candidate != null) { + // found a second field of type 'expectedFieldType' -> fail + throw VMError.shouldNotReachHere(COULD_NOT_EXTRACT_METHOD_HANDLE_FOR_UPCALL); + } + candidate = field; + } + } + if (candidate == null) { + // did not find any field of type 'expectedFieldType' -> fail + throw VMError.shouldNotReachHere(COULD_NOT_EXTRACT_METHOD_HANDLE_FOR_UPCALL); + } + return candidate; + } } private void createUpcallStubs(FeatureImpl.BeforeAnalysisAccessImpl access) { @@ -496,7 +537,7 @@ private static Map createStubs( return created; } - private static final String JLI_PREFIX = "java.lang.invoke."; + private static final String JLI_PACKAGE = "java.lang.invoke"; /** * List of (generated) classes that provide accessor methods for memory segments. Those methods @@ -518,7 +559,7 @@ private static Map createStubs( "VarHandleSegmentAsDoubles"); private static void registerVarHandleMethodsForReflection(FeatureAccess access, Class subtype) { - assert subtype.getPackage().getName().equals(JLI_PREFIX.substring(0, JLI_PREFIX.length() - 1)); + assert JLI_PACKAGE.equals(subtype.getPackage().getName()); RuntimeReflection.register(subtype.getDeclaredMethods()); } @@ -534,7 +575,7 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { AbiUtils.singleton().checkLibrarySupport(); for (String simpleName : VAR_HANDLE_SEGMENT_ACCESSORS) { - Class varHandleSegmentAsXClass = ReflectionUtil.lookupClass(JLI_PREFIX + simpleName); + Class varHandleSegmentAsXClass = ReflectionUtil.lookupClass(JLI_PACKAGE + '.' + simpleName); access.registerSubtypeReachabilityHandler(ForeignFunctionsFeature::registerVarHandleMethodsForReflection, varHandleSegmentAsXClass); }