Skip to content

Commit 9d87c20

Browse files
committed
[GR-62109] Add directives to defer initialization to App Layer.
PullRequest: graal/20297
2 parents 9bde10c + 598d59c commit 9d87c20

33 files changed

+1032
-161
lines changed

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public void scanBootImageHeapRoots(Comparator<AnalysisField> fieldComparator, Co
109109
}
110110
for (AnalysisField field : fields) {
111111
if (Modifier.isStatic(field.getModifiers()) && field.isRead()) {
112-
execute(() -> scanRootField(field));
112+
execute(() -> scanStaticFieldRoot(field));
113113
}
114114
}
115115

@@ -155,9 +155,9 @@ protected void scanEmbeddedRoot(JavaConstant root, Object position) {
155155
*
156156
* @param field the scanned root field
157157
*/
158-
protected final void scanRootField(AnalysisField field) {
159-
if (field.isInBaseLayer()) {
160-
// skip base layer roots
158+
protected final void scanStaticFieldRoot(AnalysisField field) {
159+
if (!field.installableInLayer()) {
160+
// skip fields not installable in this layer
161161
return;
162162
}
163163
scanField(field, null, null);

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,20 @@ public boolean enableReachableInCurrentLayer() {
391391
return false;
392392
}
393393

394+
public boolean buildingImageLayer() {
395+
return false;
396+
}
397+
398+
@SuppressWarnings("unused")
399+
public boolean installableInLayer(AnalysisField aField) {
400+
return true;
401+
}
402+
403+
@SuppressWarnings("unused")
404+
public boolean preventConstantFolding(AnalysisField aField) {
405+
return false;
406+
}
407+
394408
/**
395409
* Helpers to determine what analysis actions should be taken for a given Multi-Method version.
396410
*/

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapRelocatableConstant.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,9 @@ public JavaConstant uncompress() {
7777
public ImageHeapConstant forObjectClone() {
7878
throw AnalysisError.shouldNotReachHere("Unsupported in ImageHeapRelocatableConstant");
7979
}
80+
81+
@Override
82+
public String toString() {
83+
return "(ImageHeapRelocatableConstant) " + super.toString();
84+
}
8085
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,10 @@ public void onFieldRead(AnalysisField field) {
133133
AnalysisType declaringClass = field.getDeclaringClass();
134134
if (field.isStatic()) {
135135
FieldScan reason = new FieldScan(field);
136-
if (field.isInBaseLayer()) {
136+
if (!field.installableInLayer()) {
137137
/*
138-
* For base layer static fields we don't want to scan the constant value, but
139-
* instead inject its type state in the field flow. This will be propagated to any
138+
* For non-installable static fields we do not scan the constant value, but instead
139+
* inject its type state in the field flow. This will be propagated to any
140140
* corresponding field loads.
141141
*
142142
* GR-52421: the field state needs to be serialized from the base layer analysis
@@ -146,9 +146,7 @@ public void onFieldRead(AnalysisField field) {
146146
} else if (bb.trackPrimitiveValues() && field.getStorageKind().isPrimitive()) {
147147
((PointsToAnalysisField) field).saturatePrimitiveField();
148148
}
149-
return;
150-
}
151-
if (isValueAvailable(field)) {
149+
} else if (isValueAvailable(field)) {
152150
JavaConstant fieldValue = readStaticFieldValue(field);
153151
if (fieldValue instanceof ImageHeapConstant imageHeapConstant && field.isFinal()) {
154152
AnalysisError.guarantee(imageHeapConstant.getOrigin() != null, "The origin of the constant %s should have been registered before", imageHeapConstant);

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ public abstract class AnalysisField extends AnalysisElement implements WrappedJa
107107
*/
108108
protected Object fieldValueInterceptor;
109109

110+
/**
111+
* When building layered images, for static fields we must keep track of what layer's static
112+
* fields array the field is assigned in. This also impacts when the underlying value can be
113+
* read and/or constant folded.
114+
*/
115+
private final boolean isLayeredStaticField;
116+
110117
@SuppressWarnings("this-escape")
111118
public AnalysisField(AnalysisUniverse universe, ResolvedJavaField wrappedField) {
112119
super(universe.hostVM.enableTrackAcrossLayers());
@@ -152,6 +159,7 @@ public AnalysisField(AnalysisUniverse universe, ResolvedJavaField wrappedField)
152159
id = universe.computeNextFieldId();
153160
isInBaseLayer = false;
154161
}
162+
isLayeredStaticField = isStatic() && universe.hostVM.buildingImageLayer();
155163
}
156164

157165
@Override
@@ -188,6 +196,22 @@ public boolean isInBaseLayer() {
188196
return isInBaseLayer;
189197
}
190198

199+
public boolean installableInLayer() {
200+
if (isLayeredStaticField) {
201+
return getUniverse().hostVM.installableInLayer(this);
202+
} else {
203+
return true;
204+
}
205+
}
206+
207+
public boolean preventConstantFolding() {
208+
if (isLayeredStaticField) {
209+
return getUniverse().hostVM.preventConstantFolding(this);
210+
} else {
211+
return false;
212+
}
213+
}
214+
191215
@Override
192216
public int hashCode() {
193217
return id;

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/StaticFieldsSupport.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import jdk.graal.compiler.graph.NodeClass;
5555
import jdk.graal.compiler.nodeinfo.NodeInfo;
5656
import jdk.graal.compiler.nodes.ConstantNode;
57+
import jdk.graal.compiler.nodes.StructuredGraph;
5758
import jdk.graal.compiler.nodes.ValueNode;
5859
import jdk.graal.compiler.nodes.calc.FloatingNode;
5960
import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
@@ -99,9 +100,9 @@ static HostedStaticFieldSupport singleton() {
99100
return ImageSingletons.lookup(HostedStaticFieldSupport.class);
100101
}
101102

102-
JavaConstant getStaticPrimitiveFieldsConstant(int layerNum, Function<Object, JavaConstant> toConstant);
103+
JavaConstant getStaticFieldsBaseConstant(int layerNum, boolean primitive, Function<Object, JavaConstant> toConstant);
103104

104-
JavaConstant getStaticObjectFieldsConstant(int layerNum, Function<Object, JavaConstant> toConstant);
105+
FloatingNode getStaticFieldsBaseReplacement(int layerNum, boolean primitive, LoweringTool tool, StructuredGraph graph);
105106

106107
boolean isPrimitive(ResolvedJavaField field);
107108

@@ -137,7 +138,7 @@ public static JavaConstant getStaticFieldsConstant(ResolvedJavaField field, Func
137138
var hostedSupport = HostedStaticFieldSupport.singleton();
138139
boolean primitive = hostedSupport.isPrimitive(field);
139140
int layerNum = getInstalledLayerNum(field);
140-
return primitive ? hostedSupport.getStaticPrimitiveFieldsConstant(layerNum, toConstant) : hostedSupport.getStaticObjectFieldsConstant(layerNum, toConstant);
141+
return hostedSupport.getStaticFieldsBaseConstant(layerNum, primitive, toConstant);
141142
}
142143

143144
public static int getInstalledLayerNum(ResolvedJavaField field) {
@@ -249,25 +250,22 @@ public void lower(LoweringTool tool) {
249250
*/
250251
return;
251252
}
252-
JavaConstant constant;
253+
FloatingNode replacement;
253254
if (SubstrateUtil.HOSTED) {
254255
/*
255256
* Build-time version of lowering.
256257
*/
257-
Function<Object, JavaConstant> toConstantFunction = (obj) -> tool.getSnippetReflection().forObject(obj);
258-
259258
HostedStaticFieldSupport hostedSupport = HostedStaticFieldSupport.singleton();
260-
constant = primitive ? hostedSupport.getStaticPrimitiveFieldsConstant(layerNum, toConstantFunction)
261-
: hostedSupport.getStaticObjectFieldsConstant(layerNum, toConstantFunction);
259+
replacement = hostedSupport.getStaticFieldsBaseReplacement(layerNum, primitive, tool, graph());
262260
} else {
263261
/*
264262
* JIT version of lowering.
265263
*/
266-
constant = tool.getSnippetReflection()
264+
JavaConstant constant = tool.getSnippetReflection()
267265
.forObject(primitive ? StaticFieldsSupport.getStaticPrimitiveFieldsAtRuntime(layerNum) : StaticFieldsSupport.getStaticObjectFieldsAtRuntime(layerNum));
266+
replacement = ConstantNode.forConstant(constant, tool.getMetaAccess(), graph());
268267
}
269-
assert constant.isNonNull() : constant;
270-
replaceAndDelete(ConstantNode.forConstant(constant, tool.getMetaAccess(), graph()));
268+
replaceAndDelete(graph().addOrUniqueWithInputs(replacement));
271269
}
272270
}
273271

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@ protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Boolean o
167167
@Option(help = "Mark singleton as application layer only")//
168168
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> ApplicationLayerOnlySingletons = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.build());
169169

170+
@Option(help = "Register class as being initialized in the app layer.")//
171+
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> ApplicationLayerInitializedClasses = new HostedOptionKey<>(
172+
AccumulatingLocatableMultiOptionValue.Strings.build());
173+
170174
@APIOption(name = "libc")//
171175
@Option(help = "Selects the libc implementation to use. Available implementations: glibc, musl, bionic")//
172176
public static final HostedOptionKey<String> UseLibC = new HostedOptionKey<>(null) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ConstantPoolProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
* {@link Target_jdk_internal_reflect_ConstantPool}.
4545
*/
4646
public class ConstantPoolProvider implements MultiLayeredImageSingleton, UnsavedSingleton {
47-
private final Target_jdk_internal_reflect_ConstantPool constantPool = new Target_jdk_internal_reflect_ConstantPool(DynamicImageLayerInfo.singleton().layerNumber);
47+
private final Target_jdk_internal_reflect_ConstantPool constantPool = new Target_jdk_internal_reflect_ConstantPool(DynamicImageLayerInfo.getCurrentLayerNumber());
4848

4949
public static ConstantPoolProvider[] singletons() {
5050
return MultiLayeredImageSingleton.getAllLayers(ConstantPoolProvider.class);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/DynamicImageLayerInfo.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,14 @@
2929
import org.graalvm.nativeimage.Platforms;
3030

3131
import com.oracle.svm.core.graal.code.CGlobalDataInfo;
32+
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
3233
import com.oracle.svm.core.meta.SharedMethod;
3334

3435
@Platforms(Platform.HOSTED_ONLY.class)
3536
public abstract class DynamicImageLayerInfo {
3637
public static final int CREMA_LAYER_ID = Byte.MAX_VALUE;
3738

38-
public final int layerNumber;
39+
private final int layerNumber;
3940
public final int nextLayerNumber;
4041
public final int numLayers;
4142

@@ -56,4 +57,12 @@ public record PriorLayerMethodLocation(CGlobalDataInfo base, int offset) {
5657
* Returns a (Base, Offset) pair which can be used to call a method defined in a prior layer.
5758
*/
5859
public abstract PriorLayerMethodLocation getPriorLayerMethodLocation(SharedMethod method);
60+
61+
public static int getCurrentLayerNumber() {
62+
if (!ImageLayerBuildingSupport.buildingImageLayer()) {
63+
return MultiLayeredImageSingleton.UNUSED_LAYER_NUMBER;
64+
} else {
65+
return singleton().layerNumber;
66+
}
67+
}
5968
}

substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ struct PersistedAnalysisField {
128128
declaringTypeId @2 :TypeId;
129129
typeId @3 :TypeId;
130130
position @4 :Int32;
131-
location @5 :Int32;
131+
location @5 :Int32; # note currently we only read information about static fields' location
132132
modifiers @6 :Int32;
133133
isInternal @7 :Bool;
134134
isAccessed @8 :Bool;
@@ -139,6 +139,8 @@ struct PersistedAnalysisField {
139139
isSynthetic @13 :Bool;
140140
annotationList @14 :List(Annotation);
141141
name @15 :Text;
142+
priorInstalledLayerNum @16 :Int32;
143+
assignmentStatus @17 :Int32;
142144
}
143145

144146
struct CEntryPointLiteralReference {

0 commit comments

Comments
 (0)