From 101c3725e5cf107d437336aefc7b6caf72cc460f Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Thu, 31 Aug 2023 01:49:47 +0200 Subject: [PATCH 1/8] Use ImageHeapMap for resources support. --- .../src/com/oracle/svm/core/jdk/Resources.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java index 28bfec77f7e2..00faeab2e2cb 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Resources.java @@ -42,7 +42,7 @@ import java.util.stream.StreamSupport; import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.MapCursor; import org.graalvm.collections.Pair; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; @@ -88,7 +88,7 @@ public static Resources singleton() { * com.oracle.svm.hosted.ModuleLayerFeature}. */ private final EconomicMap, ResourceStorageEntryBase> resources = ImageHeapMap.create(); - private final EconomicSet includePatterns = EconomicSet.create(); + private final EconomicMap includePatterns = ImageHeapMap.create(); public record ModuleResourcePair(String module, String resource) { } @@ -280,7 +280,7 @@ public void registerIncludePattern(String module, String pattern) { assert MissingRegistrationUtils.throwMissingRegistrationErrors(); synchronized (includePatterns) { updateTimeStamp(); - includePatterns.add(new ModuleResourcePair(module, pattern)); + includePatterns.put(new ModuleResourcePair(module, pattern), Boolean.TRUE); } } @@ -321,7 +321,9 @@ public ResourceStorageEntryBase get(Module module, String resourceName, boolean ResourceStorageEntryBase entry = resources.get(createStorageKey(module, canonicalResourceName)); if (entry == null) { if (MissingRegistrationUtils.throwMissingRegistrationErrors()) { - for (ModuleResourcePair moduleResourcePair : includePatterns) { + MapCursor cursor = includePatterns.getEntries(); + while (cursor.advance()) { + ModuleResourcePair moduleResourcePair = cursor.getKey(); if (Objects.equals(moduleName, moduleResourcePair.module) && (matchResource(moduleResourcePair.resource, resourceName) || matchResource(moduleResourcePair.resource, canonicalResourceName))) { return null; From 167ba87c64f9452b61fd24bfd8c08a8e641a8542 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Thu, 31 Aug 2023 11:50:13 +0200 Subject: [PATCH 2/8] Use ImageHeapMap for SerializationSupport. --- .../svm/core/reflect/serialize/SerializationSupport.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/serialize/SerializationSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/serialize/SerializationSupport.java index ae07d0cd589b..73397a809523 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/serialize/SerializationSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/serialize/SerializationSupport.java @@ -31,15 +31,16 @@ import java.lang.invoke.SerializedLambda; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; -import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.java.LambdaUtils; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; +import com.oracle.svm.core.util.ImageHeapMap; import com.oracle.svm.core.util.VMError; public class SerializationSupport implements SerializationRegistry { @@ -114,11 +115,11 @@ public int hashCode() { } } - private final Map constructorAccessors; + private final EconomicMap constructorAccessors; @Platforms(Platform.HOSTED_ONLY.class) public SerializationSupport(Constructor stubConstructor) { - constructorAccessors = new ConcurrentHashMap<>(); + constructorAccessors = ImageHeapMap.create(); this.stubConstructor = stubConstructor; } From 940f3cd04b82a492c24206bf2796b0aed19fb95e Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Thu, 31 Aug 2023 23:07:25 +0200 Subject: [PATCH 3/8] Use ObservableImageHeapMap for JfrEventSubstitutions. --- .../com/oracle/svm/hosted/jfr/JfrEventSubstitution.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventSubstitution.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventSubstitution.java index bc277421b7e6..ebcb2fddbbea 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventSubstitution.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jfr/JfrEventSubstitution.java @@ -28,9 +28,9 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import org.graalvm.collections.EconomicMap; import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -40,6 +40,7 @@ import com.oracle.svm.core.jfr.JfrEventWriterAccess; import com.oracle.svm.core.jfr.JfrJavaEvents; import com.oracle.svm.core.jfr.JfrJdkCompatibility; +import com.oracle.svm.core.util.ObservableImageHeapMapProvider; import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.ReflectionUtil; @@ -63,7 +64,7 @@ public class JfrEventSubstitution extends SubstitutionProcessor { private final ConcurrentHashMap typeSubstitution; private final ConcurrentHashMap methodSubstitutions; private final ConcurrentHashMap fieldSubstitutions; - private final EconomicMap> mirrorEventMapping; + private final Map> mirrorEventMapping; JfrEventSubstitution(MetaAccessProvider metaAccess) { baseEventType = metaAccess.lookupJavaType(jdk.internal.event.Event.class); @@ -225,8 +226,8 @@ private static Method getMethodToFetchMetaspaceMethod(Class method) throws No * mirror event is registered as well. Otherwise, incorrect JFR metadata would be emitted. */ @SuppressWarnings("unchecked") - private static EconomicMap> createMirrorEventsMapping() { - EconomicMap> result = EconomicMap.create(); + private static Map> createMirrorEventsMapping() { + Map> result = ObservableImageHeapMapProvider.create(); Class mirrorEventAnnotationClass = (Class) ReflectionUtil.lookupClass(false, "jdk.jfr.internal.MirrorEvent"); Class jdkEventsClass = ReflectionUtil.lookupClass(false, "jdk.jfr.internal.instrument.JDKEvents"); Class[] mirrorEventClasses = ReflectionUtil.readStaticField(jdkEventsClass, "mirrorEventClasses"); From bc08969d7a2476fbbfb8c17784e3c8f532992602 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Fri, 1 Sep 2023 00:10:00 +0200 Subject: [PATCH 4/8] Fix ObservableImageHeapMapProviderImpl. Install heap scanner beforeAnalysis, duringSetup is too early. --- .../heap/ObservableImageHeapMapProviderImpl.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/ObservableImageHeapMapProviderImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/ObservableImageHeapMapProviderImpl.java index bcdff5a5f73c..595b94a398fa 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/ObservableImageHeapMapProviderImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/ObservableImageHeapMapProviderImpl.java @@ -33,8 +33,8 @@ import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.util.ObservableImageHeapMapProvider; +import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; import com.oracle.svm.hosted.util.ObservableMap; -import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl; public class ObservableImageHeapMapProviderImpl implements ObservableImageHeapMapProvider { private List> cachedInstances = new ArrayList<>(); @@ -77,8 +77,13 @@ private void registerWithScanner(ObservableMap map) { final class ObservableHeapMapFeature implements InternalFeature { @Override - public void duringSetup(DuringSetupAccess a) { - DuringSetupAccessImpl access = (DuringSetupAccessImpl) a; + public void beforeAnalysis(BeforeAnalysisAccess a) { + /* + * Set the heap scanner beforeAnalysis, i.e., only after all other features have finished + * their set-up. We want to make sure that all features have already registered the object + * replacers before any scanning can happen, e.g., such as HostedDynamicHubFeature. + */ + BeforeAnalysisAccessImpl access = (BeforeAnalysisAccessImpl) a; ObservableImageHeapMapProviderImpl provider = (ObservableImageHeapMapProviderImpl) ImageSingletons.lookup(ObservableImageHeapMapProvider.class); provider.setHeapScanner(access.getUniverse().getHeapScanner()); } From 8eaaa16b88771b679e1736419c7b9ab403663c89 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Fri, 1 Sep 2023 00:42:13 +0200 Subject: [PATCH 5/8] Fix TruffleBaseFeature. LibraryFactory.uncachedDispatch needs scanning during analysis. --- .../src/com/oracle/svm/truffle/TruffleBaseFeature.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java index 1fe9b9e24d55..bd58657979f2 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java @@ -86,6 +86,7 @@ import org.graalvm.nativeimage.hosted.RuntimeReflection; import org.graalvm.nativeimage.impl.ConfigurationCondition; import org.graalvm.nativeimage.impl.RuntimeResourceSupport; +import org.graalvm.polyglot.Engine; import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; @@ -151,7 +152,6 @@ import jdk.internal.misc.Unsafe; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; -import org.graalvm.polyglot.Engine; /** * Base feature for using Truffle in the SVM. If only this feature is used (not included through @@ -230,6 +230,7 @@ public boolean getAsBoolean() { private boolean profilingEnabled; private boolean needsAllEncodings; + private Field uncachedDispatchField; private Field layoutInfoMapField; private Field layoutMapField; private Field libraryFactoryCacheField; @@ -436,6 +437,7 @@ public void duringSetup(DuringSetupAccess access) { DuringSetupAccessImpl config = (DuringSetupAccessImpl) access; metaAccess = config.getMetaAccess(); + uncachedDispatchField = config.findField(LibraryFactory.class, "uncachedDispatch"); layoutInfoMapField = config.findField("com.oracle.truffle.object.DefaultLayout$LayoutInfo", "LAYOUT_INFO_MAP"); layoutMapField = config.findField("com.oracle.truffle.object.DefaultLayout", "LAYOUT_MAP"); libraryFactoryCacheField = config.findField("com.oracle.truffle.api.library.LibraryFactory$ResolvedDispatch", "CACHE"); @@ -542,7 +544,7 @@ public void duringAnalysis(DuringAnalysisAccess a) { if (!a.isReachable(type.getJavaClass())) { continue; } - initializeTruffleLibrariesAtBuildTime(type); + initializeTruffleLibrariesAtBuildTime(access, type); initializeDynamicObjectLayouts(type); } access.rescanRoot(layoutInfoMapField); @@ -707,12 +709,14 @@ public void accept(DuringAnalysisAccess t, Class u) { * * @see #registerTruffleLibrariesAsInHeap */ - private static void initializeTruffleLibrariesAtBuildTime(AnalysisType type) { + private void initializeTruffleLibrariesAtBuildTime(DuringAnalysisAccessImpl access, AnalysisType type) { if (type.isAnnotationPresent(GenerateLibrary.class)) { /* Eagerly resolve library type. */ LibraryFactory factory = LibraryFactory.resolve(type.getJavaClass().asSubclass(Library.class)); /* Trigger computation of uncachedDispatch. */ factory.getUncached(); + /* Manually rescan the field since this is during analysis. */ + access.rescanField(factory, uncachedDispatchField); } if (type.isAnnotationPresent(ExportLibrary.class) || type.isAnnotationPresent(ExportLibrary.Repeat.class)) { /* Eagerly resolve receiver type. */ From 4d0dd14b80511cdb6a3106a2f0f4a64f0af881af Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Mon, 4 Sep 2023 10:51:52 +0200 Subject: [PATCH 6/8] Add Feature.beforeHeapLayout(). Separates setting SubstrateField.constantValue from consuming it (to mark it as immutable). --- .../org.graalvm.nativeimage/snapshot.sigtest | 6 ++ .../graalvm/nativeimage/hosted/Feature.java | 21 ++++++- .../graal/meta/SubstrateReplacements.java | 4 +- .../com/oracle/svm/graal/GraalSupport.java | 4 +- .../hosted/GraalGraphObjectReplacer.java | 4 +- .../LegacyRuntimeCompilationFeature.java | 5 ++ .../ParseOnceRuntimeCompilationFeature.java | 5 ++ .../hosted/RuntimeCompilationFeature.java | 9 ++- .../com/oracle/svm/hosted/FeatureImpl.java | 55 +++---------------- .../svm/hosted/NativeImageGenerator.java | 7 ++- .../svm/hosted/image/NativeImageHeap.java | 45 +++++++++++++++ .../svm/truffle/TruffleBaseFeature.java | 4 ++ 12 files changed, 111 insertions(+), 58 deletions(-) diff --git a/sdk/src/org.graalvm.nativeimage/snapshot.sigtest b/sdk/src/org.graalvm.nativeimage/snapshot.sigtest index 2a8b790eee46..ff0fa7d5e4eb 100644 --- a/sdk/src/org.graalvm.nativeimage/snapshot.sigtest +++ b/sdk/src/org.graalvm.nativeimage/snapshot.sigtest @@ -943,6 +943,7 @@ innr public abstract interface static AfterImageWriteAccess innr public abstract interface static AfterRegistrationAccess innr public abstract interface static BeforeAnalysisAccess innr public abstract interface static BeforeCompilationAccess +innr public abstract interface static BeforeHeapLayoutAccess innr public abstract interface static BeforeImageWriteAccess innr public abstract interface static BeforeUniverseBuildingAccess innr public abstract interface static CompilationAccess @@ -963,6 +964,7 @@ meth public void afterImageWrite(org.graalvm.nativeimage.hosted.Feature$AfterIma meth public void afterRegistration(org.graalvm.nativeimage.hosted.Feature$AfterRegistrationAccess) meth public void beforeAnalysis(org.graalvm.nativeimage.hosted.Feature$BeforeAnalysisAccess) meth public void beforeCompilation(org.graalvm.nativeimage.hosted.Feature$BeforeCompilationAccess) +meth public void beforeHeapLayout(org.graalvm.nativeimage.hosted.Feature$BeforeHeapLayoutAccess) meth public void beforeImageWrite(org.graalvm.nativeimage.hosted.Feature$BeforeImageWriteAccess) meth public void beforeUniverseBuilding(org.graalvm.nativeimage.hosted.Feature$BeforeUniverseBuildingAccess) meth public void cleanup() @@ -1008,6 +1010,10 @@ CLSS public abstract interface static org.graalvm.nativeimage.hosted.Feature$Bef outer org.graalvm.nativeimage.hosted.Feature intf org.graalvm.nativeimage.hosted.Feature$CompilationAccess +CLSS public abstract interface static org.graalvm.nativeimage.hosted.Feature$BeforeHeapLayoutAccess + outer org.graalvm.nativeimage.hosted.Feature +intf org.graalvm.nativeimage.hosted.Feature$CompilationAccess + CLSS public abstract interface static org.graalvm.nativeimage.hosted.Feature$BeforeImageWriteAccess outer org.graalvm.nativeimage.hosted.Feature intf org.graalvm.nativeimage.hosted.Feature$FeatureAccess diff --git a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/Feature.java b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/Feature.java index dc5efc882d09..87ce85c52ed9 100644 --- a/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/Feature.java +++ b/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/Feature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -452,6 +452,15 @@ interface BeforeCompilationAccess extends CompilationAccess { interface AfterCompilationAccess extends CompilationAccess { } + /** + * Access methods available for {@link Feature#beforeHeapLayout}. + * + * @since 23.2 + */ + @Platforms(Platform.HOSTED_ONLY.class) + interface BeforeHeapLayoutAccess extends CompilationAccess { + } + /** * Access methods available for {@link Feature#afterHeapLayout}. * @@ -607,6 +616,16 @@ default void beforeCompilation(BeforeCompilationAccess access) { default void afterCompilation(AfterCompilationAccess access) { } + /** + * Handler for initializations before the native image heap and code layout. + * + * @param access The supported operations that the feature can perform at this time + * + * @since 23.2 + */ + default void beforeHeapLayout(BeforeHeapLayoutAccess access) { + } + /** * Handler for initializations after the native image heap and code layout. Objects and methods * have their offsets assigned. At this point, no additional objects must be added to the native diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java index acfae20b7045..343308e79e9a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java @@ -83,7 +83,7 @@ import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.hosted.Feature.BeforeHeapLayoutAccess; import com.oracle.svm.core.SubstrateTargetDescription; import com.oracle.svm.core.config.ConfigurationValues; @@ -163,7 +163,7 @@ public SubstrateReplacements(Providers providers, SnippetReflectionProvider snip } @Platforms(Platform.HOSTED_ONLY.class) - public void registerImmutableObjects(Feature.CompilationAccess access) { + public void registerImmutableObjects(BeforeHeapLayoutAccess access) { access.registerAsImmutable(this); access.registerAsImmutable(snippetEncoding); access.registerAsImmutable(snippetObjects); diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSupport.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSupport.java index c42a0b1a95b8..1a4518e6e303 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSupport.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSupport.java @@ -66,7 +66,7 @@ import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.hosted.Feature.CompilationAccess; +import org.graalvm.nativeimage.hosted.Feature.BeforeHeapLayoutAccess; import org.graalvm.nativeimage.hosted.Feature.DuringAnalysisAccess; import org.graalvm.nativeimage.hosted.Feature.FeatureAccess; import org.graalvm.word.Pointer; @@ -301,7 +301,7 @@ public static void rescan(AnalysisUniverse universe, Object object) { } @Platforms(Platform.HOSTED_ONLY.class) - public static void registerImmutableObjects(CompilationAccess access) { + public static void registerImmutableObjects(BeforeHeapLayoutAccess access) { access.registerAsImmutable(get().graphEncoding); access.registerAsImmutable(get().graphObjects); access.registerAsImmutable(get().graphNodeTypes); diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java index 133b13edc964..5a5d2d8c5a69 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java @@ -41,7 +41,7 @@ import org.graalvm.compiler.nodes.FieldLocationIdentity; import org.graalvm.compiler.phases.util.Providers; import org.graalvm.nativeimage.c.function.RelocatedPointer; -import org.graalvm.nativeimage.hosted.Feature.CompilationAccess; +import org.graalvm.nativeimage.hosted.Feature.BeforeHeapLayoutAccess; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.meta.AnalysisField; @@ -465,7 +465,7 @@ public void updateSubstrateDataAfterHeapLayout(HostedUniverse hUniverse) { } } - public void registerImmutableObjects(CompilationAccess access) { + public void registerImmutableObjects(BeforeHeapLayoutAccess access) { for (SubstrateMethod method : methods.values()) { access.registerAsImmutable(method); access.registerAsImmutable(method.getRawImplementations()); diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/LegacyRuntimeCompilationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/LegacyRuntimeCompilationFeature.java index 465cd01c2d10..b54009e25aa4 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/LegacyRuntimeCompilationFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/LegacyRuntimeCompilationFeature.java @@ -517,6 +517,11 @@ public void afterCompilation(AfterCompilationAccess a) { super.afterCompilationHelper(a); } + @Override + public void beforeHeapLayout(BeforeHeapLayoutAccess a) { + super.beforeHeapLayoutHelper(a); + } + @Override public void afterHeapLayout(AfterHeapLayoutAccess a) { super.afterHeapLayoutHelper(a); diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java index 1ac638f0f059..b957b6e185e6 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/ParseOnceRuntimeCompilationFeature.java @@ -714,6 +714,11 @@ public void afterCompilation(AfterCompilationAccess a) { super.afterCompilationHelper(a); } + @Override + public void beforeHeapLayout(BeforeHeapLayoutAccess a) { + super.beforeHeapLayoutHelper(a); + } + @Override public void afterHeapLayout(AfterHeapLayoutAccess a) { afterHeapLayoutHelper(a); diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java index 2142b60dee66..666ddc23f09e 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java @@ -63,6 +63,7 @@ import org.graalvm.nativeimage.hosted.Feature.AfterCompilationAccess; import org.graalvm.nativeimage.hosted.Feature.AfterHeapLayoutAccess; import org.graalvm.nativeimage.hosted.Feature.BeforeAnalysisAccess; +import org.graalvm.nativeimage.hosted.Feature.BeforeHeapLayoutAccess; import org.graalvm.nativeimage.hosted.Feature.DuringSetupAccess; import org.graalvm.nativeimage.hosted.RuntimeReflection; @@ -653,10 +654,12 @@ protected final void afterCompilationHelper(AfterCompilationAccess a) { HostedMetaAccess hMetaAccess = config.getMetaAccess(); HostedUniverse hUniverse = hMetaAccess.getUniverse(); objectReplacer.updateSubstrateDataAfterCompilation(hUniverse, config.getProviders()); + } - objectReplacer.registerImmutableObjects(config); - GraalSupport.registerImmutableObjects(config); - ((SubstrateReplacements) GraalSupport.getRuntimeConfig().getProviders().getReplacements()).registerImmutableObjects(config); + protected final void beforeHeapLayoutHelper(BeforeHeapLayoutAccess a) { + objectReplacer.registerImmutableObjects(a); + GraalSupport.registerImmutableObjects(a); + ((SubstrateReplacements) GraalSupport.getRuntimeConfig().getProviders().getReplacements()).registerImmutableObjects(a); } protected final void afterHeapLayoutHelper(AfterHeapLayoutAccess a) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java index 52d0ceda9222..acf96119b0e1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java @@ -30,13 +30,10 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.nio.file.Path; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.Deque; import java.util.HashSet; -import java.util.IdentityHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -70,7 +67,6 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.graal.meta.RuntimeConfiguration; -import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.meta.SharedField; import com.oracle.svm.core.meta.SharedMethod; import com.oracle.svm.core.meta.SharedType; @@ -92,8 +88,6 @@ import com.oracle.svm.util.ReflectionUtil; import com.oracle.svm.util.UnsafePartitionKind; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; @SuppressWarnings("deprecation") @@ -584,47 +578,7 @@ public void registerAsImmutable(Object object) { @Override public void registerAsImmutable(Object root, Predicate includeObject) { - Deque worklist = new ArrayDeque<>(); - IdentityHashMap registeredObjects = new IdentityHashMap<>(); - - worklist.push(root); - - while (!worklist.isEmpty()) { - Object cur = worklist.pop(); - registerAsImmutable(cur); - - if (!getMetaAccess().optionalLookupJavaType(cur.getClass()).isPresent()) { - /* - * The type is unused (actually was never created by the static analysis), so we - * do not need to follow any children. - */ - } else if (cur instanceof Object[]) { - for (Object element : ((Object[]) cur)) { - addToWorklist(aUniverse.replaceObject(element), includeObject, worklist, registeredObjects); - } - } else { - JavaConstant constant = aUniverse.getSnippetReflection().forObject(cur); - for (HostedField field : getMetaAccess().lookupJavaType(constant).getInstanceFields(true)) { - if (field.isAccessed() && field.getStorageKind() == JavaKind.Object) { - Object fieldValue = aUniverse.getSnippetReflection().asObject(Object.class, heap.hConstantReflection.readFieldValue(field, constant)); - addToWorklist(fieldValue, includeObject, worklist, registeredObjects); - } - } - } - } - } - - private static void addToWorklist(Object object, Predicate includeObject, Deque worklist, IdentityHashMap registeredObjects) { - if (object == null || registeredObjects.containsKey(object)) { - return; - } else if (object instanceof DynamicHub || object instanceof Class) { - /* Classes are handled specially, some fields of it are immutable and some not. */ - return; - } else if (!includeObject.test(object)) { - return; - } - registeredObjects.put(object, Boolean.TRUE); - worklist.push(object); + heap.registerAsImmutable(root, includeObject); } public HostedMetaAccess getMetaAccess() { @@ -689,6 +643,13 @@ public NativeImageCodeCache getCodeCache() { } } + public static class BeforeHeapLayoutAccessImpl extends CompilationAccessImpl implements Feature.BeforeHeapLayoutAccess { + public BeforeHeapLayoutAccessImpl(FeatureHandler featureHandler, ImageClassLoader imageClassLoader, AnalysisUniverse aUniverse, HostedUniverse hUniverse, NativeImageHeap heap, + DebugContext debugContext, RuntimeConfiguration runtimeConfiguration, NativeLibraries nativeLibraries) { + super(featureHandler, imageClassLoader, aUniverse, hUniverse, heap, debugContext, runtimeConfiguration, nativeLibraries); + } + } + public static class AfterHeapLayoutAccessImpl extends FeatureAccessImpl implements Feature.AfterHeapLayoutAccess { protected final HostedMetaAccess hMetaAccess; protected final NativeImageHeap heap; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index c828c9b001bd..2247ba11c1f9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -56,7 +56,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BooleanSupplier; -import com.oracle.svm.hosted.analysis.ReachabilityTracePrinter; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; import org.graalvm.collections.MapCursor; @@ -241,6 +240,7 @@ import com.oracle.svm.hosted.FeatureImpl.AfterRegistrationAccessImpl; import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; import com.oracle.svm.hosted.FeatureImpl.BeforeCompilationAccessImpl; +import com.oracle.svm.hosted.FeatureImpl.BeforeHeapLayoutAccessImpl; import com.oracle.svm.hosted.FeatureImpl.BeforeImageWriteAccessImpl; import com.oracle.svm.hosted.FeatureImpl.BeforeUniverseBuildingAccessImpl; import com.oracle.svm.hosted.FeatureImpl.ConcurrentAnalysisAccessImpl; @@ -252,6 +252,7 @@ import com.oracle.svm.hosted.analysis.Inflation; import com.oracle.svm.hosted.analysis.NativeImagePointsToAnalysis; import com.oracle.svm.hosted.analysis.NativeImageReachabilityAnalysisEngine; +import com.oracle.svm.hosted.analysis.ReachabilityTracePrinter; import com.oracle.svm.hosted.analysis.SVMAnalysisMetaAccess; import com.oracle.svm.hosted.analysis.SubstrateUnsupportedFeatures; import com.oracle.svm.hosted.annotation.SubstrateAnnotationExtractor; @@ -695,6 +696,10 @@ protected void doRun(Map entryPoints, try (StopTimer t = TimerCollection.createTimerAndStart(TimerCollection.Registry.IMAGE)) { bb.getHeartbeatCallback().run(); + BeforeHeapLayoutAccessImpl beforeLayoutConfig = new BeforeHeapLayoutAccessImpl(featureHandler, loader, aUniverse, hUniverse, heap, debug, runtimeConfiguration, + nativeLibraries); + featureHandler.forEachFeature(feature -> feature.beforeHeapLayout(beforeLayoutConfig)); + buildNativeImageHeap(heap, codeCache); AfterHeapLayoutAccessImpl config = new AfterHeapLayoutAccessImpl(featureHandler, loader, heap, hMetaAccess, debug); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java index 0ef281182c94..e6031db07471 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java @@ -39,6 +39,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.function.Predicate; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.core.common.CompressEncoding; @@ -271,6 +272,50 @@ public void registerAsImmutable(Object object) { knownImmutableObjects.add(object); } + public void registerAsImmutable(Object root, Predicate includeObject) { + Deque worklist = new ArrayDeque<>(); + IdentityHashMap registeredObjects = new IdentityHashMap<>(); + + worklist.push(root); + + while (!worklist.isEmpty()) { + Object cur = worklist.pop(); + registerAsImmutable(cur); + + if (!hMetaAccess.optionalLookupJavaType(cur.getClass()).isPresent()) { + /* + * The type is unused (actually was never created by the static analysis), so we do + * not need to follow any children. + */ + } else if (cur instanceof Object[]) { + for (Object element : ((Object[]) cur)) { + addToWorklist(aUniverse.replaceObject(element), includeObject, worklist, registeredObjects); + } + } else { + JavaConstant constant = aUniverse.getSnippetReflection().forObject(cur); + for (HostedField field : hMetaAccess.lookupJavaType(constant).getInstanceFields(true)) { + if (field.isAccessed() && field.getStorageKind() == JavaKind.Object) { + Object fieldValue = aUniverse.getSnippetReflection().asObject(Object.class, hConstantReflection.readFieldValue(field, constant)); + addToWorklist(fieldValue, includeObject, worklist, registeredObjects); + } + } + } + } + } + + private static void addToWorklist(Object object, Predicate includeObject, Deque worklist, IdentityHashMap registeredObjects) { + if (object == null || registeredObjects.containsKey(object)) { + return; + } else if (object instanceof DynamicHub || object instanceof Class) { + /* Classes are handled specially, some fields of it are immutable and some not. */ + return; + } else if (!includeObject.test(object)) { + return; + } + registeredObjects.put(object, Boolean.TRUE); + worklist.push(object); + } + /** * If necessary, add an object to the model of the native image heap. * diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java index bd58657979f2..957bbdf32dfc 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java @@ -568,6 +568,10 @@ public void afterCompilation(AfterCompilationAccess access) { FeatureImpl.AfterCompilationAccessImpl config = (FeatureImpl.AfterCompilationAccessImpl) access; graalGraphObjectReplacer.updateSubstrateDataAfterCompilation(config.getUniverse(), config.getProviders()); + } + + @Override + public void beforeHeapLayout(BeforeHeapLayoutAccess access) { graalGraphObjectReplacer.registerImmutableObjects(access); } From 38ae0f9e76276608a6a74da2ae8bcfcc01d43374 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Fri, 1 Sep 2023 23:23:03 +0200 Subject: [PATCH 7/8] Mark unknown primitive fields. --- .../com/oracle/svm/core/graal/meta/KnownOffsets.java | 10 ++++++++++ .../svm/core/jni/access/JNIAccessibleField.java | 3 +++ .../svm/core/jni/access/JNIAccessibleMethod.java | 12 ++++++++++++ 3 files changed, 25 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/KnownOffsets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/KnownOffsets.java index 099c3524abe5..186c32ed42c7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/KnownOffsets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/KnownOffsets.java @@ -29,16 +29,26 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; +import com.oracle.svm.core.BuildPhaseProvider.ReadyForCompilation; import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.heap.UnknownPrimitiveField; public final class KnownOffsets { + @UnknownPrimitiveField(availability = ReadyForCompilation.class) // private int vtableBaseOffset; + @UnknownPrimitiveField(availability = ReadyForCompilation.class) // private int vtableEntrySize; + @UnknownPrimitiveField(availability = ReadyForCompilation.class) // private int typeIDSlotsOffset; + @UnknownPrimitiveField(availability = ReadyForCompilation.class) // private int componentHubOffset; + @UnknownPrimitiveField(availability = ReadyForCompilation.class) // private int javaFrameAnchorLastSPOffset; + @UnknownPrimitiveField(availability = ReadyForCompilation.class) // private int javaFrameAnchorLastIPOffset; + @UnknownPrimitiveField(availability = ReadyForCompilation.class) // private int vmThreadStatusOffset; + @UnknownPrimitiveField(availability = ReadyForCompilation.class) // private int imageCodeInfoCodeStartOffset; @Fold diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleField.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleField.java index 9168f91b29b0..fc3cfbac3820 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleField.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleField.java @@ -33,8 +33,10 @@ import org.graalvm.word.WordBase; import org.graalvm.word.WordFactory; +import com.oracle.svm.core.BuildPhaseProvider.ReadyForCompilation; import com.oracle.svm.core.StaticFieldsSupport; import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.heap.UnknownPrimitiveField; import com.oracle.svm.core.jni.headers.JNIFieldId; import jdk.vm.ci.meta.JavaKind; @@ -76,6 +78,7 @@ public static WordBase getOffsetFromId(JNIFieldId id) { *
  • Remaining 62 bits for (unsigned) offset in the object
  • * */ + @UnknownPrimitiveField(availability = ReadyForCompilation.class)// private UnsignedWord id = WordFactory.zero(); @Platforms(HOSTED_ONLY.class) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleMethod.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleMethod.java index e2a0150140f4..ea9ec7629e44 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleMethod.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleMethod.java @@ -35,7 +35,9 @@ import org.graalvm.word.PointerBase; import com.oracle.svm.core.AlwaysInline; +import com.oracle.svm.core.BuildPhaseProvider.ReadyForCompilation; import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.heap.UnknownPrimitiveField; import com.oracle.svm.core.jni.CallVariant; import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.ReflectionUtil; @@ -71,15 +73,25 @@ public static ResolvedJavaField getCallVariantWrapperField(MetaAccessProvider me } private final int modifiers; + @UnknownPrimitiveField(availability = ReadyForCompilation.class)// private int vtableOffset = VTABLE_OFFSET_NOT_YET_COMPUTED; + @UnknownPrimitiveField(availability = ReadyForCompilation.class)// private CodePointer nonvirtualTarget; + @UnknownPrimitiveField(availability = ReadyForCompilation.class)// private PointerBase newObjectTarget; // for constructors + @UnknownPrimitiveField(availability = ReadyForCompilation.class)// private CodePointer callWrapper; + @UnknownPrimitiveField(availability = ReadyForCompilation.class)// @SuppressWarnings("unused") private CodePointer varargsWrapper; + @UnknownPrimitiveField(availability = ReadyForCompilation.class)// @SuppressWarnings("unused") private CodePointer arrayWrapper; + @UnknownPrimitiveField(availability = ReadyForCompilation.class)// @SuppressWarnings("unused") private CodePointer valistWrapper; + @UnknownPrimitiveField(availability = ReadyForCompilation.class)// @SuppressWarnings("unused") private CodePointer varargsNonvirtualWrapper; + @UnknownPrimitiveField(availability = ReadyForCompilation.class)// @SuppressWarnings("unused") private CodePointer arrayNonvirtualWrapper; + @UnknownPrimitiveField(availability = ReadyForCompilation.class)// @SuppressWarnings("unused") private CodePointer valistNonvirtualWrapper; @Platforms(HOSTED_ONLY.class) From 3792a0fa57be2ea45cd2733a5678a90c96eb4d70 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Mon, 4 Sep 2023 10:37:08 +0200 Subject: [PATCH 8/8] Throw on missing type. --- .../src/com/oracle/svm/hosted/image/NativeImageHeap.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java index e6031db07471..84bfa0f1b57d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java @@ -282,11 +282,8 @@ public void registerAsImmutable(Object root, Predicate includeObject) { Object cur = worklist.pop(); registerAsImmutable(cur); - if (!hMetaAccess.optionalLookupJavaType(cur.getClass()).isPresent()) { - /* - * The type is unused (actually was never created by the static analysis), so we do - * not need to follow any children. - */ + if (hMetaAccess.optionalLookupJavaType(cur.getClass()).isEmpty()) { + throw VMError.shouldNotReachHere("Type missing from static analysis: " + cur.getClass().getTypeName()); } else if (cur instanceof Object[]) { for (Object element : ((Object[]) cur)) { addToWorklist(aUniverse.replaceObject(element), includeObject, worklist, registeredObjects);