From 3f688851d8f6e957848fb0bd5337c643e9fb433f Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Tue, 12 Jul 2022 17:11:53 +0200 Subject: [PATCH 01/12] svm: VirtualThreads are not yet implemented on JDK 19 --- .../oracle/svm/core/thread/SubstrateVirtualThread.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/SubstrateVirtualThread.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/SubstrateVirtualThread.java index 379da0d5c462..0eaddd8fa40c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/SubstrateVirtualThread.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/SubstrateVirtualThread.java @@ -35,6 +35,7 @@ import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.nativeimage.IsolateThread; import com.oracle.svm.core.annotate.Alias; @@ -45,6 +46,7 @@ import com.oracle.svm.core.monitor.MonitorSupport; import com.oracle.svm.core.stack.JavaFrameAnchor; import com.oracle.svm.core.stack.JavaFrameAnchors; +import com.oracle.svm.core.util.VMError; import jdk.internal.misc.Unsafe; @@ -431,6 +433,9 @@ boolean joinNanos(long nanos) throws InterruptedException { } private Object interruptLock() { + if (JavaVersionUtil.JAVA_SPEC >= 19) { + throw VMError.unsupportedFeature("Loom is not yet supported on JDK 19"); + } return JavaThreads.toTarget(this).blockerLock; } @@ -466,6 +471,9 @@ private void releaseInterruptLockAndSwitchBack(Object token) { @Override public void interrupt() { + if (JavaVersionUtil.JAVA_SPEC >= 19) { + throw VMError.unsupportedFeature("Loom is not yet supported on JDK 19"); + } if (Thread.currentThread() != this) { Object token = switchToCarrierAndAcquireInterruptLock(); try { From 928547df769540bb19659d25a9034c8d38e04cd5 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Wed, 13 Jul 2022 12:05:00 +0200 Subject: [PATCH 02/12] svm: recompute Thread$FieldHolder on JDK 19 --- .../JavaLangThreadGroupSubstitutions.java | 28 +++++++++++++++++++ .../core/thread/Target_java_lang_Thread.java | 1 + 2 files changed, 29 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaLangThreadGroupSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaLangThreadGroupSubstitutions.java index c13000ce596e..b71e8c64a4aa 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaLangThreadGroupSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaLangThreadGroupSubstitutions.java @@ -26,6 +26,7 @@ import java.util.Arrays; +import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -41,6 +42,7 @@ import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.jdk.JDK17OrEarlier; import com.oracle.svm.core.jdk.UninterruptibleUtils; +import com.oracle.svm.util.ReflectionUtil; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaField; @@ -148,6 +150,32 @@ public Object compute(MetaAccessProvider metaAccess, ResolvedJavaField original, return ThreadStatus.NEW; } } + +} + +@Platforms(Platform.HOSTED_ONLY.class) +class ThreadHolderRecomputation implements RecomputeFieldValue.CustomFieldValueTransformer { + @Override + public RecomputeFieldValue.ValueAvailability valueAvailability() { + return RecomputeFieldValue.ValueAvailability.BeforeAnalysis; + } + + @Override + public Object transform(MetaAccessProvider metaAccess, ResolvedJavaField original, ResolvedJavaField annotated, Object receiver, Object originalValue) { + assert JavaVersionUtil.JAVA_SPEC >= 19 : "ThreadHolder only exist on JDK 19+"; + int threadStatus = ReflectionUtil.readField(ReflectionUtil.lookupClass(false, "java.lang.Thread$FieldHolder"), "threadStatus", receiver); + if (threadStatus == ThreadStatus.TERMINATED) { + return ThreadStatus.TERMINATED; + } + assert threadStatus == ThreadStatus.NEW : "All threads are in NEW state during image generation"; + if (receiver == ReflectionUtil.readField(Thread.class, "holder", PlatformThreads.singleton().mainThread)) { + /* The main thread is recomputed as running. */ + return ThreadStatus.RUNNABLE; + } else { + /* All other threads remain unstarted. */ + return ThreadStatus.NEW; + } + } } @Platforms(Platform.HOSTED_ONLY.class) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java index 04d42139fb55..ebe783b46358 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java @@ -618,6 +618,7 @@ final class Target_java_lang_Thread_FieldHolder { @Alias // boolean daemon; @Alias // + @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = ThreadHolderRecomputation.class) // volatile int threadStatus; Target_java_lang_Thread_FieldHolder( From 04760c40254f7b1c065cfbbbcf812260666a5af6 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Wed, 13 Jul 2022 13:40:38 +0200 Subject: [PATCH 03/12] svm: reset ThreadGroup.weaks on JDK 19 All ThreadGroups are recomputed and stored in the strong ThreadGroup.groups field. --- .../thread/JavaLangThreadGroupSubstitutions.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaLangThreadGroupSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaLangThreadGroupSubstitutions.java index b71e8c64a4aa..70bf722d150d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaLangThreadGroupSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaLangThreadGroupSubstitutions.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.thread; +import java.lang.ref.WeakReference; import java.util.Arrays; import org.graalvm.compiler.serviceprovider.JavaVersionUtil; @@ -41,6 +42,7 @@ import com.oracle.svm.core.annotate.Uninterruptible; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.jdk.JDK17OrEarlier; +import com.oracle.svm.core.jdk.JDK19OrLater; import com.oracle.svm.core.jdk.UninterruptibleUtils; import com.oracle.svm.util.ReflectionUtil; @@ -77,6 +79,16 @@ final class Target_java_lang_ThreadGroup { @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = ThreadGroupGroupsRecomputation.class, disableCaching = true)// private ThreadGroup[] groups; + /* + * All ThreadGroups in the image heap are strong and will be stored in ThreadGroup.groups. + */ + @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset)// + @TargetElement(onlyWith = JDK19OrLater.class)// + private int nweaks; + @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset)// + @TargetElement(onlyWith = JDK19OrLater.class)// + private WeakReference[] weaks; + @Inject @InjectAccessors(ThreadGroupIdAccessor.class) // public long id; From db7da4c48afaa748df1ec70c07436666b218101e Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Wed, 13 Jul 2022 15:09:56 +0200 Subject: [PATCH 04/12] svm: Do not use the field handle based field accessor but the one based on unsafe [GR-39586] --- .../src/com/oracle/svm/core/hub/DynamicHub.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java index c065283fb0ee..b9d1f9da589d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java @@ -79,6 +79,7 @@ import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode; import com.oracle.svm.core.jdk.JDK11OrEarlier; import com.oracle.svm.core.jdk.JDK17OrLater; +import com.oracle.svm.core.jdk.JDK19OrLater; import com.oracle.svm.core.jdk.Resources; import com.oracle.svm.core.meta.SharedType; import com.oracle.svm.core.reflect.ReflectionMetadataDecoder; @@ -1726,6 +1727,17 @@ final class Target_jdk_internal_reflect_ReflectionFactory { public static ReflectionFactory getReflectionFactory() { return soleInstance; } + + /** + * Do not use the field handle based field accessor but the one based on unsafe. It takes effect + * when {@code Target_java_lang_reflect_Field#fieldAccessorField#fieldAccessor} is recomputed at + * runtime. See also GR-39586. + */ + @TargetElement(onlyWith = JDK19OrLater.class) + @Substitute + static boolean useFieldHandleAccessor() { + return false; + } } @TargetClass(className = "java.lang.Class", innerClass = "EnclosingMethodInfo") From a5a0530a24a88da6f74986b6344b6566cf81ad20 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Thu, 14 Jul 2022 14:58:48 +0200 Subject: [PATCH 05/12] svm: disable SecurityServiceTest on JDK 19 --- .../com/oracle/svm/test/SecurityServiceTest.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/SecurityServiceTest.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/SecurityServiceTest.java index b2ab9d8a011c..271ca5b1a0ac 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/SecurityServiceTest.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/SecurityServiceTest.java @@ -28,6 +28,7 @@ import java.security.Provider; import java.security.Security; +import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.hosted.RuntimeClassInitialization; import org.graalvm.nativeimage.hosted.RuntimeReflection; @@ -80,12 +81,15 @@ public void testUnknownSecurityServices() throws Exception { @Test public void testAutomaticSecurityServiceRegistration() { - try { - JCACompliantNoOpService service = JCACompliantNoOpService.getInstance("no-op-algo-two"); - Assert.assertNotNull("No service instance was created", service); - Assert.assertThat("Unexpected service implementtation class", service, CoreMatchers.instanceOf(JcaCompliantNoOpServiceImpl.class)); - } catch (NoSuchAlgorithmException e) { - Assert.fail("Failed to fetch noop service with exception: " + e); + if (JavaVersionUtil.JAVA_SPEC < 19) { + // Does not work on JDK 19 for yet unknown reasons (GR-39827) + try { + JCACompliantNoOpService service = JCACompliantNoOpService.getInstance("no-op-algo-two"); + Assert.assertNotNull("No service instance was created", service); + Assert.assertThat("Unexpected service implementtation class", service, CoreMatchers.instanceOf(JcaCompliantNoOpServiceImpl.class)); + } catch (NoSuchAlgorithmException e) { + Assert.fail("Failed to fetch noop service with exception: " + e); + } } } From 71eb19621f155b3e5bcd80366259c93a86456a38 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Thu, 14 Jul 2022 15:38:46 +0200 Subject: [PATCH 06/12] svm: run mx gate tag test on JDK 19 --- substratevm/ci.jsonnet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/ci.jsonnet b/substratevm/ci.jsonnet index 695f3e8973f9..7f0bbb1be898 100644 --- a/substratevm/ci.jsonnet +++ b/substratevm/ci.jsonnet @@ -80,7 +80,7 @@ linux_amd64_jdk11 + gate("build-ce", "build,checkstubs,helloworld,test,nativeimagehelp,muslcbuild,debuginfotest") + maven + svm_unittest + t("35:00") + musl_toolchain + gdb("10.2"), linux_amd64_jdk11 + gate("modules-basic", "build,hellomodule,test") + maven + svm_unittest + t("30:00"), linux_amd64_jdk17 + gate("style-fullbuild", "style,fullbuild,helloworld,test,svmjunit,debuginfotest") + common.eclipse + common.jdt + maven + jsonschema + svm_unittest + t("50:00") + mx_build_exploded + gdb("10.2"), - linux_amd64_jdk19 + gate("build-ce", "build,helloworld") + maven + svm_unittest + t("35:00"), + linux_amd64_jdk19 + gate("build-ce", "build,helloworld,test") + maven + svm_unittest + t("55:00"), windows_jdk17 + gate("basics", "build,helloworld,test,svmjunit") + svm_unittest + t("1:30:00"), windows_jdk17 + gate("basics-quickbuild", "build,helloworld_quickbuild,test_quickbuild,svmjunit_quickbuild") + svm_unittest + t("1:30:00"), ], From 43cb2e20d45ab33f14daf6e0a461c77308932bd6 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Thu, 14 Jul 2022 16:57:32 +0200 Subject: [PATCH 07/12] svm: initialize Proxy and Lambda classes at build time in the ProvenSafeClassInitializationSupport --- .../classinitialization/ClassInitializationFeature.java | 3 --- .../ProvenSafeClassInitializationSupport.java | 8 ++++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java index 0ea99e2ae91f..76cd8fdda63e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java @@ -29,7 +29,6 @@ import static com.oracle.svm.hosted.classinitialization.InitKind.RUN_TIME; import java.io.PrintWriter; -import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -41,7 +40,6 @@ import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.util.Providers; -import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; @@ -188,7 +186,6 @@ public void afterAnalysis(AfterAnalysisAccess access) { if (ClassInitializationOptions.AssertInitializationSpecifiedForAllClasses.getValue()) { List unspecifiedClasses = classInitializationSupport.classesWithKind(RUN_TIME).stream() .filter(c -> classInitializationSupport.specifiedInitKindFor(c) == null) - .filter(c -> JavaVersionUtil.JAVA_SPEC < 19 || !Proxy.isProxyClass(c)) .map(Class::getTypeName) .collect(Collectors.toList()); if (!unspecifiedClasses.isEmpty()) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ProvenSafeClassInitializationSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ProvenSafeClassInitializationSupport.java index d2e5e6f86948..91a363e0ac59 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ProvenSafeClassInitializationSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ProvenSafeClassInitializationSupport.java @@ -28,12 +28,15 @@ import static com.oracle.svm.hosted.classinitialization.InitKind.RUN_TIME; import java.lang.reflect.Field; +import java.lang.reflect.Proxy; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import org.graalvm.compiler.java.LambdaUtils; + import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.AnalysisUniverse; @@ -323,6 +326,11 @@ InitKind computeInitKindAndMaybeInitializeClass(Class clazz, boolean memoize, } superResult = superResult.max(processInterfaces(clazz, memoize, earlyClassInitializerAnalyzedClasses)); + if (superResult == InitKind.BUILD_TIME && (Proxy.isProxyClass(clazz) || LambdaUtils.isLambdaType(metaAccess.lookupJavaType(clazz)))) { + forceInitializeHosted(clazz, "proxy/lambda classes with interfaces initialized at build time are also initialized at build time", false); + return InitKind.BUILD_TIME; + } + if (memoize && superResult != InitKind.RUN_TIME && clazzResult == InitKind.RUN_TIME && canBeProvenSafe(clazz)) { /* * Check if the class initializer is side-effect free using a simple intraprocedural From 0809c185a0b586a66b72b014a793d2ad4079f7ab Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Mon, 18 Jul 2022 12:22:57 +0200 Subject: [PATCH 08/12] svm: do not initialize Proxy classes at build time if the interface methods contain run-time initialized types See also com.oracle.svm.test.proxy.ProxyExceptionTest. --- .../ProvenSafeClassInitializationSupport.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ProvenSafeClassInitializationSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ProvenSafeClassInitializationSupport.java index 91a363e0ac59..a5e610c34c7e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ProvenSafeClassInitializationSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ProvenSafeClassInitializationSupport.java @@ -29,11 +29,13 @@ import java.lang.reflect.Field; import java.lang.reflect.Proxy; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.graalvm.compiler.java.LambdaUtils; @@ -327,8 +329,10 @@ InitKind computeInitKindAndMaybeInitializeClass(Class clazz, boolean memoize, superResult = superResult.max(processInterfaces(clazz, memoize, earlyClassInitializerAnalyzedClasses)); if (superResult == InitKind.BUILD_TIME && (Proxy.isProxyClass(clazz) || LambdaUtils.isLambdaType(metaAccess.lookupJavaType(clazz)))) { - forceInitializeHosted(clazz, "proxy/lambda classes with interfaces initialized at build time are also initialized at build time", false); - return InitKind.BUILD_TIME; + if (!Proxy.isProxyClass(clazz) || areAllInterfaceMethodsSafeToInitializeAtBuildTime(clazz)) { + forceInitializeHosted(clazz, "proxy/lambda classes with interfaces initialized at build time are also initialized at build time", false); + return InitKind.BUILD_TIME; + } } if (memoize && superResult != InitKind.RUN_TIME && clazzResult == InitKind.RUN_TIME && canBeProvenSafe(clazz)) { @@ -372,6 +376,17 @@ InitKind computeInitKindAndMaybeInitializeClass(Class clazz, boolean memoize, return result; } + /** + * Interfaces are only safe to initialize at build time if no interface method references a type + * that {@linkplain #shouldInitializeAtRuntime should be initialized at run time}. + */ + private boolean areAllInterfaceMethodsSafeToInitializeAtBuildTime(Class clazz) { + var interfaces = Arrays.stream(clazz.getInterfaces()); + var methods = interfaces.flatMap(c -> Arrays.stream(c.getDeclaredMethods())); + var types = methods.flatMap(m -> Stream.concat(Stream.of(m.getReturnType()), Arrays.stream(m.getParameterTypes()))); + return types.noneMatch(this::shouldInitializeAtRuntime); + } + private InitKind processInterfaces(Class clazz, boolean memoizeEager, Set> earlyClassInitializerAnalyzedClasses) { /* * Note that we do not call computeInitKindForClass(clazz) on purpose: if clazz is the root From 87f9ac290ac843650fea09c0b186c12a9e156be8 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Thu, 14 Jul 2022 17:05:47 +0200 Subject: [PATCH 09/12] svm: Object.wait0 substitution for JDK 19 --- .../src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java index 2b1662462748..b9512f79b146 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java @@ -99,13 +99,13 @@ private int hashCodeSubst() { } @Substitute - @TargetElement(name = "wait", onlyWith = NotLoomJDK.class) + @TargetElement(name = "wait", onlyWith = JDK17OrEarlier.class) private void waitSubst(long timeoutMillis) throws InterruptedException { MonitorSupport.singleton().wait(this, timeoutMillis); } @Substitute - @TargetElement(name = "wait0", onlyWith = LoomJDK.class) + @TargetElement(name = "wait0", onlyWith = JDK19OrLater.class) private void waitSubstLoom(long timeoutMillis) throws InterruptedException { MonitorSupport.singleton().wait(this, timeoutMillis); } From cd87f0ae594d668d428ec8973580a6e3ef8fbfd1 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Thu, 14 Jul 2022 17:24:23 +0200 Subject: [PATCH 10/12] svm: run mx gate tag svmjunit on JDK 19 --- substratevm/ci.jsonnet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/ci.jsonnet b/substratevm/ci.jsonnet index 7f0bbb1be898..49243e0c7279 100644 --- a/substratevm/ci.jsonnet +++ b/substratevm/ci.jsonnet @@ -80,7 +80,7 @@ linux_amd64_jdk11 + gate("build-ce", "build,checkstubs,helloworld,test,nativeimagehelp,muslcbuild,debuginfotest") + maven + svm_unittest + t("35:00") + musl_toolchain + gdb("10.2"), linux_amd64_jdk11 + gate("modules-basic", "build,hellomodule,test") + maven + svm_unittest + t("30:00"), linux_amd64_jdk17 + gate("style-fullbuild", "style,fullbuild,helloworld,test,svmjunit,debuginfotest") + common.eclipse + common.jdt + maven + jsonschema + svm_unittest + t("50:00") + mx_build_exploded + gdb("10.2"), - linux_amd64_jdk19 + gate("build-ce", "build,helloworld,test") + maven + svm_unittest + t("55:00"), + linux_amd64_jdk19 + gate("basics", "build,helloworld,test,svmjunit") + svm_unittest + t("55:00"), windows_jdk17 + gate("basics", "build,helloworld,test,svmjunit") + svm_unittest + t("1:30:00"), windows_jdk17 + gate("basics-quickbuild", "build,helloworld_quickbuild,test_quickbuild,svmjunit_quickbuild") + svm_unittest + t("1:30:00"), ], From 3f3817389c09ecc2c136408f4e213b999cb14db7 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Mon, 18 Jul 2022 15:05:29 +0200 Subject: [PATCH 11/12] svm: substitute Thread getAndClearInterrupt and clearInterrupt in JDK 19 --- .../svm/core/thread/Target_java_lang_Thread.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java index ebe783b46358..aee511c32f06 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java @@ -406,10 +406,23 @@ public boolean isInterrupted() { } @Substitute + @TargetElement(onlyWith = JDK17OrEarlier.class) public static boolean interrupted() { return JavaThreads.getAndClearInterrupt(Thread.currentThread()); } + @Substitute + @TargetElement(onlyWith = JDK19OrLater.class) + void clearInterrupt() { + getAndClearInterrupt(); + } + + @Substitute + @TargetElement(onlyWith = JDK19OrLater.class) + boolean getAndClearInterrupt() { + return JavaThreads.getAndClearInterrupt(SubstrateUtil.cast(this, Thread.class)); + } + @Delete @TargetElement(onlyWith = JDK11OrEarlier.class) private native boolean isInterrupted(boolean clearInterrupted); From d603e085a99dfe1a2542a815ad17b205bc5d5f79 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Tue, 19 Jul 2022 15:52:41 +0200 Subject: [PATCH 12/12] svm: also look for run-time initialized super interfaces before considering Proxies as build-time initialized --- .../ProvenSafeClassInitializationSupport.java | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ProvenSafeClassInitializationSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ProvenSafeClassInitializationSupport.java index a5e610c34c7e..e8f565dad932 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ProvenSafeClassInitializationSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ProvenSafeClassInitializationSupport.java @@ -37,6 +37,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.graalvm.collections.EconomicSet; +import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.java.LambdaUtils; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; @@ -329,7 +331,7 @@ InitKind computeInitKindAndMaybeInitializeClass(Class clazz, boolean memoize, superResult = superResult.max(processInterfaces(clazz, memoize, earlyClassInitializerAnalyzedClasses)); if (superResult == InitKind.BUILD_TIME && (Proxy.isProxyClass(clazz) || LambdaUtils.isLambdaType(metaAccess.lookupJavaType(clazz)))) { - if (!Proxy.isProxyClass(clazz) || areAllInterfaceMethodsSafeToInitializeAtBuildTime(clazz)) { + if (!Proxy.isProxyClass(clazz) || !implementsRunTimeInitializedInterface(clazz)) { forceInitializeHosted(clazz, "proxy/lambda classes with interfaces initialized at build time are also initialized at build time", false); return InitKind.BUILD_TIME; } @@ -377,14 +379,29 @@ InitKind computeInitKindAndMaybeInitializeClass(Class clazz, boolean memoize, } /** - * Interfaces are only safe to initialize at build time if no interface method references a type - * that {@linkplain #shouldInitializeAtRuntime should be initialized at run time}. + * Interfaces must be initialized at run time if any interface method references a type that + * {@linkplain #shouldInitializeAtRuntime should be initialized at run time}. */ - private boolean areAllInterfaceMethodsSafeToInitializeAtBuildTime(Class clazz) { - var interfaces = Arrays.stream(clazz.getInterfaces()); - var methods = interfaces.flatMap(c -> Arrays.stream(c.getDeclaredMethods())); + private boolean implementsRunTimeInitializedInterface(Class clazz) { + EconomicSet> visited = EconomicSet.create(); + return Arrays.stream(clazz.getInterfaces()).anyMatch(c -> shouldInitializeInterfaceAtRunTime(c, visited)); + } + + private boolean shouldInitializeInterfaceAtRunTime(Class clazz, EconomicSet> visited) { + if (visited.contains(clazz)) { + // already visited + return false; + } + GraalError.guarantee(clazz.isInterface(), "expected interface, got %s", clazz); + visited.add(clazz); + var methods = Arrays.stream(clazz.getDeclaredMethods()); var types = methods.flatMap(m -> Stream.concat(Stream.of(m.getReturnType()), Arrays.stream(m.getParameterTypes()))); - return types.noneMatch(this::shouldInitializeAtRuntime); + // check for initialize at run time + if (types.anyMatch(this::shouldInitializeAtRuntime)) { + return true; + } + // iterate super interfaces recursively + return Arrays.stream(clazz.getInterfaces()).anyMatch(c -> shouldInitializeInterfaceAtRunTime(c, visited)); } private InitKind processInterfaces(Class clazz, boolean memoizeEager, Set> earlyClassInitializerAnalyzedClasses) {