Skip to content

Commit 5956cf6

Browse files
committed
[GR-67504] Install all GCCauses in initial layer.
PullRequest: graal/21531
2 parents 5c53d3a + db4c5e7 commit 5956cf6

File tree

2 files changed

+145
-10
lines changed

2 files changed

+145
-10
lines changed

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GenScavengeGCCause.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@
2424
*/
2525
package com.oracle.svm.core.genscavenge;
2626

27+
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
28+
import com.oracle.svm.core.feature.InternalFeature;
2729
import com.oracle.svm.core.heap.GCCause;
30+
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
2831

2932
final class GenScavengeGCCause extends GCCause {
3033
public static final GCCause OnAllocation = new GenScavengeGCCause("Collect on allocation", 10);
@@ -33,3 +36,19 @@ private GenScavengeGCCause(String name, int id) {
3336
super(name, id);
3437
}
3538
}
39+
40+
/**
41+
* For layered builds we must eagerly register all GCCauses in the initial layer.
42+
*/
43+
@AutomaticallyRegisteredFeature
44+
class GenScavengeGCCauseRegistration implements InternalFeature {
45+
@Override
46+
public boolean isInConfiguration(IsInConfigurationAccess access) {
47+
return ImageLayerBuildingSupport.buildingInitialLayer();
48+
}
49+
50+
@Override
51+
public void duringSetup(DuringSetupAccess access) {
52+
GCCause.registerGCCause(GenScavengeGCCause.OnAllocation);
53+
}
54+
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/GCCause.java

Lines changed: 126 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@
2424
*/
2525
package com.oracle.svm.core.heap;
2626

27+
import java.util.Collections;
28+
import java.util.EnumSet;
2729
import java.util.List;
30+
import java.util.function.Function;
2831

2932
import org.graalvm.nativeimage.ImageSingletons;
3033
import org.graalvm.nativeimage.Platform;
@@ -34,10 +37,19 @@
3437
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
3538
import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
3639
import com.oracle.svm.core.feature.InternalFeature;
40+
import com.oracle.svm.core.imagelayer.BuildingImageLayerPredicate;
41+
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
42+
import com.oracle.svm.core.layeredimagesingleton.ImageSingletonLoader;
43+
import com.oracle.svm.core.layeredimagesingleton.ImageSingletonWriter;
44+
import com.oracle.svm.core.layeredimagesingleton.InitialLayerOnlyImageSingleton;
45+
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton;
46+
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
3747
import com.oracle.svm.core.util.DuplicatedInNativeCode;
3848
import com.oracle.svm.core.util.ImageHeapList;
3949
import com.oracle.svm.core.util.VMError;
4050

51+
import jdk.graal.compiler.debug.Assertions;
52+
4153
/**
4254
* This class holds garbage collection causes that are common and therefore shared between different
4355
* garbage collector implementations.
@@ -77,34 +89,138 @@ public static GCCause fromId(int causeId) {
7789
public static List<GCCause> getGCCauses() {
7890
return ImageSingletons.lookup(GCCauseSupport.class).gcCauses;
7991
}
92+
93+
@Platforms(Platform.HOSTED_ONLY.class)
94+
public static void registerGCCause(GCCause cause) {
95+
ImageSingletons.lookup(GCCauseSupport.class).installGCCause(cause);
96+
}
8097
}
8198

8299
@AutomaticallyRegisteredImageSingleton
83-
class GCCauseSupport {
100+
class GCCauseSupport implements InitialLayerOnlyImageSingleton {
84101
final List<GCCause> gcCauses = ImageHeapList.create(GCCause.class, null);
85102

86103
@Platforms(Platform.HOSTED_ONLY.class)
87104
Object collectGCCauses(Object obj) {
88105
if (obj instanceof GCCause gcCause) {
89106
synchronized (gcCauses) {
90-
int id = gcCause.getId();
91-
while (gcCauses.size() <= id) {
92-
gcCauses.add(null);
93-
}
94-
var existing = gcCauses.set(id, gcCause);
95-
if (existing != null && existing != gcCause) {
96-
throw VMError.shouldNotReachHere("Two GCCause objects have the same id " + id + ": " + gcCause.getName() + ", " + existing.getName());
97-
}
107+
installGCCause(gcCause);
98108
}
99109
}
100110
return obj;
101111
}
112+
113+
@Platforms(Platform.HOSTED_ONLY.class)
114+
void installGCCause(GCCause gcCause) {
115+
int id = gcCause.getId();
116+
while (gcCauses.size() <= id) {
117+
gcCauses.add(null);
118+
}
119+
var existing = gcCauses.set(id, gcCause);
120+
if (existing != null && existing != gcCause) {
121+
throw VMError.shouldNotReachHere("Two GCCause objects have the same id " + id + ": " + gcCause.getName() + ", " + existing.getName());
122+
}
123+
}
124+
125+
@Override
126+
public boolean accessibleInFutureLayers() {
127+
return true;
128+
}
129+
130+
@Override
131+
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
132+
return LayeredImageSingletonBuilderFlags.ALL_ACCESS;
133+
}
102134
}
103135

104136
@AutomaticallyRegisteredFeature
105137
class GCCauseFeature implements InternalFeature {
138+
106139
@Override
107140
public void duringSetup(DuringSetupAccess access) {
108-
access.registerObjectReplacer(ImageSingletons.lookup(GCCauseSupport.class)::collectGCCauses);
141+
if (!ImageLayerBuildingSupport.buildingImageLayer()) {
142+
/*
143+
* In traditional builds we lazily register GCCauses as they become visible to the
144+
* native-image generator.
145+
*/
146+
access.registerObjectReplacer(ImageSingletons.lookup(GCCauseSupport.class)::collectGCCauses);
147+
} else {
148+
/*
149+
* For layered builds we eagerly register all GCCauses in the initial layer. In all
150+
* layers, via an object replacer, we then validate all referenced GCCauses have been
151+
* registered.
152+
*/
153+
Function<Integer, String> idToGCCauseName;
154+
if (ImageLayerBuildingSupport.buildingInitialLayer()) {
155+
GCCauseSupport support = ImageSingletons.lookup(GCCauseSupport.class);
156+
support.installGCCause(GCCause.JavaLangSystemGC);
157+
support.installGCCause(GCCause.UnitTest);
158+
support.installGCCause(GCCause.TestGCInDeoptimizer);
159+
support.installGCCause(GCCause.HintedGC);
160+
support.installGCCause(GCCause.JvmtiForceGC);
161+
support.installGCCause(GCCause.HeapDump);
162+
support.installGCCause(GCCause.DiagnosticCommand);
163+
164+
var gcCauseList = GCCause.getGCCauses();
165+
idToGCCauseName = (idx) -> gcCauseList.get(idx).getName();
166+
} else {
167+
var gcCauseNames = LayeredGCCauseTracker.getRegisteredGCCauses();
168+
idToGCCauseName = gcCauseNames::get;
169+
}
170+
access.registerObjectReplacer(obj -> {
171+
if (obj instanceof GCCause gcCause) {
172+
if (!idToGCCauseName.apply(gcCause.getId()).equals(gcCause.getName())) {
173+
var id = gcCause.getId();
174+
VMError.shouldNotReachHere("Mismatch in GCCause name for id %s: %s %s", id, idToGCCauseName.apply(id), gcCause.getName());
175+
}
176+
}
177+
return obj;
178+
});
179+
}
180+
}
181+
}
182+
183+
/**
184+
* In layered builds all {@link GCCause}s are registered and installed in the initial layer. Here we
185+
* track which {@link GCCause}s were installed in the initial layer to detect issues.
186+
*/
187+
@AutomaticallyRegisteredImageSingleton(onlyWith = BuildingImageLayerPredicate.class)
188+
class LayeredGCCauseTracker implements LayeredImageSingleton {
189+
List<String> registeredGCCauses;
190+
191+
public static List<String> getRegisteredGCCauses() {
192+
assert ImageLayerBuildingSupport.buildingExtensionLayer();
193+
return ImageSingletons.lookup(LayeredGCCauseTracker.class).registeredGCCauses;
194+
}
195+
196+
@Override
197+
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
198+
return LayeredImageSingletonBuilderFlags.BUILDTIME_ACCESS_ONLY;
199+
}
200+
201+
@Override
202+
public PersistFlags preparePersist(ImageSingletonWriter writer) {
203+
List<String> gcCauses;
204+
if (ImageLayerBuildingSupport.buildingInitialLayer()) {
205+
gcCauses = GCCause.getGCCauses().stream().map(gcCause -> {
206+
if (gcCause == null) {
207+
return "";
208+
} else {
209+
assert !gcCause.getName().isEmpty() : Assertions.errorMessage("Empty string is reserved for non-existent GCCauses", gcCause);
210+
return gcCause.getName();
211+
}
212+
}).toList();
213+
} else {
214+
gcCauses = registeredGCCauses;
215+
}
216+
writer.writeStringList("registeredGCCauses", gcCauses);
217+
return PersistFlags.CREATE;
218+
}
219+
220+
@SuppressWarnings("unused")
221+
public static Object createFromLoader(ImageSingletonLoader loader) {
222+
var causeTracker = new LayeredGCCauseTracker();
223+
causeTracker.registeredGCCauses = Collections.unmodifiableList(loader.readStringList("registeredGCCauses"));
224+
return causeTracker;
109225
}
110226
}

0 commit comments

Comments
 (0)