diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2584b75b7736..25035d790e7b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -79,12 +79,10 @@ jobs: JDK: "labsjdk-ce-17" GATE: "build,debuginfotest" PRIMARY: "substratevm" - GHA_EXPECTED_FAILURE: true # temporarily marked as expected failure due to #4018 / GR-35118 - env: JDK: "labsjdk-ce-11" GATE: "build,debuginfotest" PRIMARY: "substratevm" - GHA_EXPECTED_FAILURE: true # temporarily marked as expected failure due to #4018 / GR-35118 - env: JDK: "labsjdk-ce-11" GATE: "hellomodule" diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIJavaCallWrappers.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIJavaCallWrappers.java index e481d3d11eb9..f0221e464a8d 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIJavaCallWrappers.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/JNIJavaCallWrappers.java @@ -30,7 +30,6 @@ import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaMethod; /** * Holder class for generated {@link JNIJavaCallWrapperMethod} code. @@ -42,7 +41,7 @@ public static ConstantPool getConstantPool(MetaAccessProvider metaAccess) { return metaAccess.lookupJavaType(JNIJavaCallWrappers.class).getDeclaredConstructors()[0].getConstantPool(); } - public static ResolvedJavaMethod lookupJavaCallTrampoline(MetaAccessProvider metaAccess, CallVariant variant, boolean nonVirtual) { + public static String getTrampolineName(CallVariant variant, boolean nonVirtual) { StringBuilder name = new StringBuilder(48); if (variant == CallVariant.VARARGS) { name.append("varargs"); @@ -57,11 +56,7 @@ public static ResolvedJavaMethod lookupJavaCallTrampoline(MetaAccessProvider met name.append("Nonvirtual"); } name.append("JavaCallTrampoline"); - try { - return metaAccess.lookupJavaMethod(JNIJavaCallWrappers.class.getDeclaredMethod(name.toString())); - } catch (NoSuchMethodException e) { - throw VMError.shouldNotReachHere(e); - } + return name.toString(); } private JNIJavaCallWrappers() { diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessFeature.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessFeature.java index 433d14283a67..da292cd61153 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessFeature.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessFeature.java @@ -31,11 +31,13 @@ import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; +import com.oracle.svm.core.util.VMError; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.options.Option; import org.graalvm.nativeimage.ImageSingletons; @@ -90,12 +92,7 @@ public static JNIAccessFeature singleton() { private boolean sealed = false; private NativeLibraries nativeLibraries; - private JNICallTrampolineMethod varargsCallTrampolineMethod; - private JNICallTrampolineMethod arrayCallTrampolineMethod; - private JNICallTrampolineMethod valistCallTrampolineMethod; - private JNICallTrampolineMethod varargsNonvirtualCallTrampolineMethod; - private JNICallTrampolineMethod arrayNonvirtualCallTrampolineMethod; - private JNICallTrampolineMethod valistNonvirtualCallTrampolineMethod; + private final Map trampolineMethods = new HashMap<>(); private int loadedConfigurations; @@ -169,12 +166,12 @@ public void beforeAnalysis(BeforeAnalysisAccess arg) { BeforeAnalysisAccessImpl access = (BeforeAnalysisAccessImpl) arg; this.nativeLibraries = access.getNativeLibraries(); - varargsCallTrampolineMethod = createJavaCallTrampoline(access, CallVariant.VARARGS, false); - arrayCallTrampolineMethod = createJavaCallTrampoline(access, CallVariant.ARRAY, false); - valistCallTrampolineMethod = createJavaCallTrampoline(access, CallVariant.VA_LIST, false); - varargsNonvirtualCallTrampolineMethod = createJavaCallTrampoline(access, CallVariant.VARARGS, true); - arrayNonvirtualCallTrampolineMethod = createJavaCallTrampoline(access, CallVariant.ARRAY, true); - valistNonvirtualCallTrampolineMethod = createJavaCallTrampoline(access, CallVariant.VA_LIST, true); + createJavaCallTrampoline(access, CallVariant.VARARGS, false); + createJavaCallTrampoline(access, CallVariant.ARRAY, false); + createJavaCallTrampoline(access, CallVariant.VA_LIST, false); + createJavaCallTrampoline(access, CallVariant.VARARGS, true); + createJavaCallTrampoline(access, CallVariant.ARRAY, true); + createJavaCallTrampoline(access, CallVariant.VA_LIST, true); /* duplicated to reduce the number of analysis iterations */ getConditionalConfigurationRegistry().flushConditionalConfiguration(access); @@ -184,28 +181,32 @@ private static ConditionalConfigurationRegistry getConditionalConfigurationRegis return (ConditionalConfigurationRegistry) ImageSingletons.lookup(JNIRuntimeAccess.JNIRuntimeAccessibilitySupport.class); } - private static JNICallTrampolineMethod createJavaCallTrampoline(BeforeAnalysisAccessImpl access, CallVariant variant, boolean nonVirtual) { + private void createJavaCallTrampoline(BeforeAnalysisAccessImpl access, CallVariant variant, boolean nonVirtual) { MetaAccessProvider wrappedMetaAccess = access.getMetaAccess().getWrapped(); ResolvedJavaField field = JNIAccessibleMethod.getCallWrapperField(wrappedMetaAccess, variant, nonVirtual); access.getUniverse().lookup(field.getDeclaringClass()).registerAsReachable(); access.registerAsAccessed(access.getUniverse().lookup(field)); - ResolvedJavaMethod method = JNIJavaCallWrappers.lookupJavaCallTrampoline(wrappedMetaAccess, variant, nonVirtual); + String trampolineName = JNIJavaCallWrappers.getTrampolineName(variant, nonVirtual); + ResolvedJavaMethod method; + try { + method = wrappedMetaAccess.lookupJavaMethod(JNIJavaCallWrappers.class.getDeclaredMethod(trampolineName)); + } catch (NoSuchMethodException e) { + throw VMError.shouldNotReachHere(e); + } JNICallTrampolineMethod trampoline = new JNICallTrampolineMethod(method, field, nonVirtual); access.registerAsCompiled(access.getUniverse().lookup(trampoline)); - return trampoline; + trampolineMethods.put(trampolineName, trampoline); } public JNICallTrampolineMethod getCallTrampolineMethod(CallVariant variant, boolean nonVirtual) { - JNICallTrampolineMethod method = null; - if (variant == CallVariant.VARARGS) { - method = nonVirtual ? varargsNonvirtualCallTrampolineMethod : varargsCallTrampolineMethod; - } else if (variant == CallVariant.ARRAY) { - method = nonVirtual ? arrayNonvirtualCallTrampolineMethod : arrayCallTrampolineMethod; - } else if (variant == CallVariant.VA_LIST) { - method = nonVirtual ? valistNonvirtualCallTrampolineMethod : valistCallTrampolineMethod; - } - assert method != null; - return method; + String trampolineName = JNIJavaCallWrappers.getTrampolineName(variant, nonVirtual); + return getCallTrampolineMethod(trampolineName); + } + + public JNICallTrampolineMethod getCallTrampolineMethod(String javaTrampolineName) { + JNICallTrampolineMethod jniCallTrampolineMethod = trampolineMethods.get(javaTrampolineName); + assert jniCallTrampolineMethod != null; + return jniCallTrampolineMethod; } public JNINativeLinkage makeLinkage(String declaringClass, String name, String descriptor) { diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/hosted/JNINativeCallWrapperSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/hosted/JNINativeCallWrapperSubstitutionProcessor.java index ff6f342c4314..7b5137d74310 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/hosted/JNINativeCallWrapperSubstitutionProcessor.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/hosted/JNINativeCallWrapperSubstitutionProcessor.java @@ -29,6 +29,7 @@ import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; +import com.oracle.svm.jni.access.JNIAccessFeature; import jdk.vm.ci.meta.ResolvedJavaMethod; /** @@ -41,6 +42,13 @@ class JNINativeCallWrapperSubstitutionProcessor extends SubstitutionProcessor { @Override public ResolvedJavaMethod lookup(ResolvedJavaMethod method) { assert method.isNative() : "Must have been registered as a native substitution processor"; + if (method.getDeclaringClass().getName().equals("Lcom/oracle/svm/jni/JNIJavaCallWrappers;")) { + // Avoid generating JNINativeCallWrapperMethods for trampolines + JNICallTrampolineMethod callTrampolineMethod = JNIAccessFeature.singleton().getCallTrampolineMethod(method.getName()); + if (callTrampolineMethod != null) { + return callTrampolineMethod; + } + } return callWrappers.computeIfAbsent(method, JNINativeCallWrapperMethod::new); }