diff --git a/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp b/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp index c5adcbaa086d..ac72b3bd1f9b 100644 --- a/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp +++ b/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp @@ -133,7 +133,6 @@ struct PersistedAnalysisField { isSynthetic @13 :Bool; annotationList @14 :List(Annotation); name @15 :Text; - fieldCheckIndex @16 :Int32; } struct CEntryPointLiteralReference { @@ -257,6 +256,15 @@ struct SharedLayerSnapshot { singletonObjects @12 :List(ImageSingletonObject); fields @13 :List(PersistedAnalysisField); nextLayerNumber @14 :Int32; + staticFinalFieldFoldingSingleton @15 :StaticFinalFieldFoldingSingleton; +} + +struct StaticFinalFieldFoldingSingleton { + fields @0 :List(FieldId); + fieldCheckIndexes @1 :List(Int32); + fieldInitializationStatusList @2 :List(Bool); + bytecodeParsedFoldedFieldValues @3 :List(ConstantReference); + afterParsingHooksDoneFoldedFieldValues @4 :List(ConstantReference); } struct PrimitiveValue { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/IsStaticFinalFieldInitializedNode.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/IsStaticFinalFieldInitializedNode.java index 2eb7156beb89..10fbcf8c8c08 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/IsStaticFinalFieldInitializedNode.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/IsStaticFinalFieldInitializedNode.java @@ -44,7 +44,7 @@ /** * Node that checks if a static final field is initialized. This is basically just a load of the - * value in the {@link StaticFinalFieldFoldingFeature#fieldInitializationStatus} array. But we + * value in the {@link StaticFinalFieldFoldingSingleton#fieldInitializationStatus} array. But we * cannot immediately emit a {@link LoadIndexedNode} in the bytecode parser because we do not know * at the time of parsing if the declaring class of the field is initialized at image build time. */ @@ -87,10 +87,10 @@ public void simplify(SimplifierTool tool) { replacementNode = ConstantNode.forBoolean(true, graph()); } else { - StaticFinalFieldFoldingFeature feature = StaticFinalFieldFoldingFeature.singleton(); - Integer fieldCheckIndex = feature.getFieldCheckIndex(field); + StaticFinalFieldFoldingSingleton singleton = StaticFinalFieldFoldingSingleton.singleton(); + Integer fieldCheckIndex = singleton.getFieldCheckIndex(field); assert fieldCheckIndex != null : "Field must be optimizable: " + field; - ConstantNode fieldInitializationStatusNode = ConstantNode.forConstant(tool.getSnippetReflection().forObject(feature.fieldInitializationStatus), tool.getMetaAccess(), graph()); + ConstantNode fieldInitializationStatusNode = ConstantNode.forConstant(tool.getSnippetReflection().forObject(singleton.fieldInitializationStatus), tool.getMetaAccess(), graph()); ConstantNode fieldCheckIndexNode = ConstantNode.forInt(fieldCheckIndex, graph()); replacementNode = graph().addOrUniqueWithInputs(LoadIndexedNode.create(graph().getAssumptions(), fieldInitializationStatusNode, fieldCheckIndexNode, diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/MarkStaticFinalFieldInitializedNode.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/MarkStaticFinalFieldInitializedNode.java index 8acc9e925818..c5d0df3483e2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/MarkStaticFinalFieldInitializedNode.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/MarkStaticFinalFieldInitializedNode.java @@ -43,10 +43,10 @@ /** * Node that marks a static final field as initialized. This is basically just a store of the value - * true in the {@link StaticFinalFieldFoldingFeature#fieldInitializationStatus} array. But we cannot - * immediately emit a {@link StoreIndexedNode} in the bytecode parser because we do not know at the - * time of parsing if the field can actually be optimized or not. So this node is emitted for every - * static final field store, and then just removed if the field cannot be optimized. + * true in the {@link StaticFinalFieldFoldingSingleton#fieldInitializationStatus} array. But we + * cannot immediately emit a {@link StoreIndexedNode} in the bytecode parser because we do not know + * at the time of parsing if the field can actually be optimized or not. So this node is emitted for + * every static final field store, and then just removed if the field cannot be optimized. */ @NodeInfo(size = NodeSize.SIZE_1, cycles = NodeCycles.CYCLES_1) public final class MarkStaticFinalFieldInitializedNode extends AbstractStateSplit implements Simplifiable { @@ -75,10 +75,10 @@ public void simplify(SimplifierTool tool) { } assert field instanceof HostedField; - StaticFinalFieldFoldingFeature feature = StaticFinalFieldFoldingFeature.singleton(); - Integer fieldCheckIndex = feature.getFieldCheckIndex(field); + StaticFinalFieldFoldingSingleton singleton = StaticFinalFieldFoldingSingleton.singleton(); + Integer fieldCheckIndex = singleton.getFieldCheckIndex(field); if (fieldCheckIndex != null) { - ConstantNode fieldInitializationStatusNode = ConstantNode.forConstant(tool.getSnippetReflection().forObject(feature.fieldInitializationStatus), tool.getMetaAccess(), graph()); + ConstantNode fieldInitializationStatusNode = ConstantNode.forConstant(tool.getSnippetReflection().forObject(singleton.fieldInitializationStatus), tool.getMetaAccess(), graph()); ConstantNode fieldCheckIndexNode = ConstantNode.forInt(fieldCheckIndex, graph()); ConstantNode trueNode = ConstantNode.forBoolean(true, graph()); StoreIndexedNode replacementNode = graph().add(new StoreIndexedNode(fieldInitializationStatusNode, fieldCheckIndexNode, null, null, JavaKind.Boolean, trueNode)); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/StaticFinalFieldFoldingFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/StaticFinalFieldFoldingFeature.java index f30d9175b431..28bb47970199 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/StaticFinalFieldFoldingFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/StaticFinalFieldFoldingFeature.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.Comparator; +import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -44,6 +45,12 @@ import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; +import com.oracle.svm.core.layeredimagesingleton.FeatureSingleton; +import com.oracle.svm.core.layeredimagesingleton.ImageSingletonLoader; +import com.oracle.svm.core.layeredimagesingleton.ImageSingletonWriter; +import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton; +import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.util.UserError; @@ -52,6 +59,11 @@ import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl; import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; +import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerLoader; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerLoader.JavaConstantSupplier; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerSingletonLoader; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerWriter; import com.oracle.svm.hosted.meta.HostedField; import jdk.graal.compiler.graph.Node; @@ -85,8 +97,9 @@ * initializing field store is done. The field load is therefore not intrinsified to a single * constant, but an if-else structure with the likely case returning the constant value, and the * slow-path case of returning the uninitialized value. All these boolean values are stored in the - * {@link #fieldInitializationStatus} array, and {@link #fieldCheckIndexMap} stores the index for - * the optimized fields. + * {@link StaticFinalFieldFoldingSingleton#fieldInitializationStatus} array, and + * {@link StaticFinalFieldFoldingSingleton#fieldCheckIndexMap} stores the index for the optimized + * fields. * * The optimized field load is also preceded by a {@link EnsureClassInitializedNode} to trigger the * necessary class initialization. It would be possible to combine the class initialization check @@ -111,34 +124,14 @@ * parsing requests may be processed by different threads and could then depend on each other. */ @AutomaticallyRegisteredFeature -public final class StaticFinalFieldFoldingFeature implements InternalFeature { +public final class StaticFinalFieldFoldingFeature implements InternalFeature, FeatureSingleton { public static class Options { @Option(help = "Optimize static final fields that get a constant assigned in the class initializer.")// public static final HostedOptionKey OptStaticFinalFieldFolding = new HostedOptionKey<>(true); } - /** - * Folded field values after stage {@link Stage#BYTECODE_PARSED}. - */ - private final Map bytecodeParsedFoldedFieldValues = new ConcurrentHashMap<>(); - - /** - * Folded field values after stage {@link Stage#OPTIMIZATIONS_APPLIED}. - */ - private final Map afterParsingHooksDoneFoldedFieldValues = new ConcurrentHashMap<>(); - BigBang bb; - Map fieldCheckIndexMap; - /** - * Stores the field check index from the base layer. - * - * GR-59855: This is currently only used to determine that a field was folded in a previous - * layer already. The value from the base layer should also be reused in extension layers to - * ensure valid field folding across layers. - */ - Map baseLayerFieldCheckIndexMap = new HashMap<>(); - boolean[] fieldInitializationStatus; private final Set analyzedMethods = ConcurrentHashMap.newKeySet(); @@ -155,6 +148,13 @@ public boolean isInConfiguration(IsInConfigurationAccess access) { return Options.OptStaticFinalFieldFolding.getValue(); } + @Override + public void afterRegistration(AfterRegistrationAccess access) { + if (ImageLayerBuildingSupport.firstImageBuild()) { + ImageSingletons.add(StaticFinalFieldFoldingSingleton.class, new StaticFinalFieldFoldingSingleton()); + } + } + @Override public void duringSetup(DuringSetupAccess a) { DuringSetupAccessImpl access = (DuringSetupAccessImpl) a; @@ -180,6 +180,20 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { BeforeAnalysisAccessImpl access = (BeforeAnalysisAccessImpl) a; bb = access.getBigBang(); + + StaticFinalFieldFoldingSingleton singleton = StaticFinalFieldFoldingSingleton.singleton(); + SVMImageLayerLoader imageLayerLoader = HostedImageLayerBuildingSupport.singleton().getLoader(); + for (var entry : singleton.baseLayerFieldFoldingInfos.entrySet()) { + addFoldedValue(imageLayerLoader, entry.getKey(), entry.getValue().bytecodeParsedFoldedFieldValue(), singleton.bytecodeParsedFoldedFieldValues); + addFoldedValue(imageLayerLoader, entry.getKey(), entry.getValue().afterParsingHooksDoneFoldedFieldValue(), singleton.afterParsingHooksDoneFoldedFieldValues); + } + } + + private static void addFoldedValue(SVMImageLayerLoader imageLayerLoader, int fid, JavaConstantSupplier javaConstantSupplier, Map singleton) { + JavaConstant javaConstant = javaConstantSupplier.get(imageLayerLoader); + if (javaConstant != null) { + singleton.put(imageLayerLoader.getAnalysisFieldForBaseLayerId(fid), javaConstant); + } } /** @@ -189,22 +203,30 @@ public void beforeAnalysis(BeforeAnalysisAccess a) { @Override public void afterAnalysis(AfterAnalysisAccess access) { bb = null; - - List foldedFields = new ArrayList<>(getFoldedFieldValues(Stage.finalStage()).keySet()); - VMError.guarantee(getFoldedFieldValues(Stage.finalStage()).keySet().containsAll(getFoldedFieldValues(Stage.firstStage()).keySet()), + StaticFinalFieldFoldingSingleton singleton = StaticFinalFieldFoldingSingleton.singleton(); + List foldedFields = new ArrayList<>(singleton.getFoldedFieldValues(Stage.finalStage()).keySet()); + VMError.guarantee(singleton.getFoldedFieldValues(Stage.finalStage()).keySet().containsAll(singleton.getFoldedFieldValues(Stage.firstStage()).keySet()), "All fields folded in earlier stages must be present in the final stage."); - /* Make the fieldCheckIndex deterministic by using an (arbitrary) sort order. */ - foldedFields.sort(Comparator.comparing(field -> field.format("%H.%n"))); + /* + * Make the fieldCheckIndex deterministic by using the AnalysisField id to ensure the fields + * from the extension layers get a bigger fieldCheckIndex. + */ + foldedFields.sort(Comparator.comparing(AnalysisField::getId)); - fieldCheckIndexMap = new HashMap<>(); - int fieldCheckIndex = 0; + int fieldCheckIndex = singleton.baseLayerFieldFoldingInfos.size(); for (AnalysisField field : foldedFields) { - assert !baseLayerFieldCheckIndexMap.containsKey(field.getId()) : "The field %s was already assigned an index in the base layer".formatted(field); - fieldCheckIndexMap.put(field, fieldCheckIndex); - fieldCheckIndex++; + if (!singleton.baseLayerFieldFoldingInfos.containsKey(field.getId())) { + singleton.fieldCheckIndexMap.put(field, fieldCheckIndex); + fieldCheckIndex++; + } } - fieldInitializationStatus = new boolean[fieldCheckIndex]; + SVMImageLayerLoader imageLayerLoader = HostedImageLayerBuildingSupport.singleton().getLoader(); + for (var entry : singleton.baseLayerFieldFoldingInfos.entrySet()) { + singleton.fieldCheckIndexMap.put(imageLayerLoader.getAnalysisFieldForBaseLayerId(entry.getKey()), entry.getValue().fieldCheckIndex()); + } + + singleton.fieldInitializationStatus = new boolean[fieldCheckIndex]; } /** @@ -215,20 +237,21 @@ public void afterAnalysis(AfterAnalysisAccess access) { */ @Override public void afterHeapLayout(AfterHeapLayoutAccess access) { - for (Map.Entry entry : fieldCheckIndexMap.entrySet()) { - if (entry.getKey().getDeclaringClass().isInitialized()) { - fieldInitializationStatus[entry.getValue()] = true; + StaticFinalFieldFoldingSingleton singleton = StaticFinalFieldFoldingSingleton.singleton(); + for (Map.Entry entry : singleton.fieldCheckIndexMap.entrySet()) { + AnalysisField key = entry.getKey(); + if (key.getDeclaringClass().isInitialized()) { + singleton.fieldInitializationStatus[entry.getValue()] = true; + } + if (singleton.baseLayerFieldFoldingInfos.containsKey(key.getId())) { + boolean priorLayerStatus = singleton.baseLayerFieldFoldingInfos.get(key.getId()).initializationStatus(); + boolean currentLayerStatus = singleton.fieldInitializationStatus[entry.getValue()]; + assert priorLayerStatus == currentLayerStatus : "Field %s initialization status was %s in the base layer, but is %s in the application" + .formatted(key, priorLayerStatus, currentLayerStatus); } } } - private Map getFoldedFieldValues(Stage stage) { - return switch (stage) { - case BYTECODE_PARSED -> bytecodeParsedFoldedFieldValues; - case OPTIMIZATIONS_APPLIED -> afterParsingHooksDoneFoldedFieldValues; - }; - } - private void methodAfterBytecodeParsedListener(AnalysisMethod method, StructuredGraph graph) { /* * This method is registered as callback for the first parsing stage. Therefore, it may only @@ -245,11 +268,14 @@ private void methodAfterParsingListener(AnalysisMethod method, StructuredGraph g /** * Invoked for each method that is parsed during static analysis, before the type flow graph of * that method is created. If the method is a class initializer, the static final fields that - * can be optimized are detected and added to {@link #bytecodeParsedFoldedFieldValues} or - * {@link #afterParsingHooksDoneFoldedFieldValues} (depending on the stage). If the method is - * not a class initializer, it is verified that there is no illegal store to an optimized field. + * can be optimized are detected and added to + * {@link StaticFinalFieldFoldingSingleton#bytecodeParsedFoldedFieldValues} or + * {@link StaticFinalFieldFoldingSingleton#afterParsingHooksDoneFoldedFieldValues} (depending on + * the stage). If the method is not a class initializer, it is verified that there is no illegal + * store to an optimized field. */ private void analyzeParsedMethod(Stage stage, AnalysisMethod method, StructuredGraph graph) { + StaticFinalFieldFoldingSingleton singleton = StaticFinalFieldFoldingSingleton.singleton(); boolean isClassInitializer = method.isClassInitializer(); Map optimizableFields = isClassInitializer ? new HashMap<>() : null; Set ineligibleFields = isClassInitializer ? new HashSet<>() : null; @@ -261,15 +287,15 @@ private void analyzeParsedMethod(Stage stage, AnalysisMethod method, StructuredG if (isClassInitializer && field.getDeclaringClass().equals(method.getDeclaringClass())) { analyzeStoreInClassInitializer(node, field, optimizableFields, ineligibleFields); } else { - analyzeStoreOutsideClassInitializer(stage, method, field); + analyzeStoreOutsideClassInitializer(singleton, stage, method, field); } } } } if (optimizableFields != null && !optimizableFields.isEmpty()) { - verifyOptimizableFields(stage, method, optimizableFields); - getFoldedFieldValues(stage).putAll(optimizableFields); + verifyOptimizableFields(singleton, stage, method, optimizableFields); + singleton.getFoldedFieldValues(stage).putAll(optimizableFields); } // remember that the method was analyzed for static final fields @@ -286,14 +312,14 @@ private void analyzeParsedMethod(Stage stage, AnalysisMethod method, StructuredG * violation is detected, the image build fails and static final field folding needs to be * disabled. */ - private void verifyOptimizableFields(Stage stage, AnalysisMethod method, Map optimizableFields) { + private void verifyOptimizableFields(StaticFinalFieldFoldingSingleton singleton, Stage stage, AnalysisMethod method, Map optimizableFields) { if (!analyzedMethods.contains(method)) { return; } for (Entry entry : optimizableFields.entrySet()) { for (Stage curStage = stage; curStage != null; curStage = curStage.previous()) { - JavaConstant javaConstant = getFoldedFieldValue(stage, entry.getKey()); + JavaConstant javaConstant = singleton.getFoldedFieldValue(stage, entry.getKey()); /* * The field is found optimizable, i.e., a constant is assigned in a class * initializer, and then the class initializer is parsed again (in a later stage or @@ -343,7 +369,7 @@ private static void analyzeStoreInClassInitializer(StoreFieldNode node, Analysis * to the latest Java VM spec, but languages like Scala do it anyway. As long as the field is * not found as optimizable, this is no problem. */ - private void analyzeStoreOutsideClassInitializer(Stage stage, AnalysisMethod method, AnalysisField field) { + private void analyzeStoreOutsideClassInitializer(StaticFinalFieldFoldingSingleton singleton, Stage stage, AnalysisMethod method, AnalysisField field) { if (field.getDeclaringClass().getClassInitializer() != null) { /* * Analyze the class initializer of the class that defines the field. This ensures that @@ -353,7 +379,7 @@ private void analyzeStoreOutsideClassInitializer(Stage stage, AnalysisMethod met field.getDeclaringClass().getClassInitializer().ensureGraphParsed(bb); } - if (getFoldedFieldValues(stage).containsKey(field)) { + if (singleton.getFoldedFieldValues(stage).containsKey(field)) { /* * The field is found optimizable, i.e., a constant is assigned in a class initializer, * and then the field is written again outside the class initializer. The user needs to @@ -366,6 +392,65 @@ private void analyzeStoreOutsideClassInitializer(Stage stage, AnalysisMethod met } } + static boolean isOptimizationCandidate(AnalysisField aField, AnalysisMethod definingClassInitializer, FieldValueInterceptionSupport fieldValueInterceptionSupport) { + if (definingClassInitializer == null) { + /* If there is no class initializer, there cannot be a foldable constant found in it. */ + return false; + } + + if (!fieldValueInterceptionSupport.isValueAvailable(aField)) { + /* + * Cannot optimize static field whose value is recomputed and is not yet available, + * i.e., it may depend on analysis/compilation derived data. + */ + return false; + } + return true; + } + + static boolean isAllowedTargetMethod(ResolvedJavaMethod method) { + /* + * (1) Don't do this optimization for run-time compiled methods because this plugin and the + * nodes it references are not safe for execution at image run time. + * + * (2) Don't apply this optimization to deopt targets to save effort since deopt targets are + * not expected to be optimized + */ + return !SubstrateCompilationDirectives.isRuntimeCompiledMethod(method) && !SubstrateCompilationDirectives.isDeoptTarget(method); + } +} + +class StaticFinalFieldFoldingSingleton implements LayeredImageSingleton { + + /** + * Folded field values after stage {@link Stage#BYTECODE_PARSED}. + */ + final Map bytecodeParsedFoldedFieldValues = new ConcurrentHashMap<>(); + + /** + * Folded field values after stage {@link Stage#OPTIMIZATIONS_APPLIED}. + */ + final Map afterParsingHooksDoneFoldedFieldValues = new ConcurrentHashMap<>(); + final Map baseLayerFieldFoldingInfos; + final Map fieldCheckIndexMap = new HashMap<>(); + boolean[] fieldInitializationStatus; + + record PriorLayerFinalFieldFoldingInfo(JavaConstantSupplier bytecodeParsedFoldedFieldValue, JavaConstantSupplier afterParsingHooksDoneFoldedFieldValue, + int fieldCheckIndex, boolean initializationStatus) { + } + + StaticFinalFieldFoldingSingleton(Map baseLayerFieldFoldingInfos) { + this.baseLayerFieldFoldingInfos = baseLayerFieldFoldingInfos; + } + + StaticFinalFieldFoldingSingleton() { + this(new HashMap<>()); + } + + public static StaticFinalFieldFoldingSingleton singleton() { + return ImageSingletons.lookup(StaticFinalFieldFoldingSingleton.class); + } + static AnalysisField toAnalysisField(ResolvedJavaField field) { if (field instanceof HostedField) { return ((HostedField) field).wrapped; @@ -379,50 +464,81 @@ static AnalysisField toAnalysisField(ResolvedJavaField field) { * added in different parsing stages, the stage must be provided to ensure deterministic image * builds. If the field could not be folded, null will be returned. */ - JavaConstant getFoldedFieldValue(Stage stage, AnalysisField field) { + public JavaConstant getFoldedFieldValue(Stage stage, AnalysisField field) { return getFoldedFieldValues(stage).get(field); } + Map getFoldedFieldValues(Stage stage) { + return switch (stage) { + case BYTECODE_PARSED -> bytecodeParsedFoldedFieldValues; + case OPTIMIZATIONS_APPLIED -> afterParsingHooksDoneFoldedFieldValues; + }; + } + public Integer getFieldCheckIndex(ResolvedJavaField field) { return getFieldCheckIndex(toAnalysisField(field)); } public Integer getFieldCheckIndex(AnalysisField field) { - if (field.isInBaseLayer()) { - return baseLayerFieldCheckIndexMap.get(field.getId()); - } else { - return fieldCheckIndexMap.get(field); - } + return fieldCheckIndexMap.get(field); } - public void putBaseLayerFieldCheckIndex(int id, Integer fieldCheckIndex) { - baseLayerFieldCheckIndexMap.put(id, fieldCheckIndex); + @Override + public EnumSet getImageBuilderFlags() { + return LayeredImageSingletonBuilderFlags.BUILDTIME_ACCESS_ONLY; } - static boolean isOptimizationCandidate(AnalysisField aField, AnalysisMethod definingClassInitializer, FieldValueInterceptionSupport fieldValueInterceptionSupport) { - if (definingClassInitializer == null) { - /* If there is no class initializer, there cannot be a foldable constant found in it. */ - return false; + @Override + public PersistFlags preparePersist(ImageSingletonWriter writer) { + var snapshotWriter = ((SVMImageLayerWriter.ImageSingletonWriterImpl) writer).getSnapshotBuilder(); + SVMImageLayerWriter imageLayerWriter = HostedImageLayerBuildingSupport.singleton().getWriter(); + + List fields = new ArrayList<>(); + List fieldCheckIndexes = new ArrayList<>(); + List fieldInitializationStatusList = new ArrayList<>(); + List bytecodeParsedFoldedFieldValuesList = new ArrayList<>(); + List afterParsingHooksDoneFoldedFieldValuesList = new ArrayList<>(); + for (var entry : fieldCheckIndexMap.entrySet()) { + fields.add(entry.getKey().getId()); + fieldCheckIndexes.add(entry.getValue()); + fieldInitializationStatusList.add(fieldInitializationStatus[entry.getValue()]); + bytecodeParsedFoldedFieldValuesList.add(bytecodeParsedFoldedFieldValues.get(entry.getKey())); + afterParsingHooksDoneFoldedFieldValuesList.add(afterParsingHooksDoneFoldedFieldValues.get(entry.getKey())); } - if (!fieldValueInterceptionSupport.isValueAvailable(aField)) { - /* - * Cannot optimize static field whose value is recomputed and is not yet available, - * i.e., it may depend on analysis/compilation derived data. - */ - return false; + var staticFinalFieldFoldingSingleton = snapshotWriter.initStaticFinalFieldFoldingSingleton(); + var fieldsBuilder = staticFinalFieldFoldingSingleton.initFields(fields.size()); + var fieldCheckIndexesBuilder = staticFinalFieldFoldingSingleton.initFieldCheckIndexes(fieldCheckIndexes.size()); + var fieldInitializationStatusListBuilder = staticFinalFieldFoldingSingleton.initFieldInitializationStatusList(fieldInitializationStatusList.size()); + var bytecodeParsedFoldedFieldValuesListBuilder = staticFinalFieldFoldingSingleton.initBytecodeParsedFoldedFieldValues(bytecodeParsedFoldedFieldValuesList.size()); + var afterParsingHooksDoneFoldedFieldValuesListBuilder = staticFinalFieldFoldingSingleton.initAfterParsingHooksDoneFoldedFieldValues(afterParsingHooksDoneFoldedFieldValuesList.size()); + for (int i = 0; i < fields.size(); ++i) { + fieldsBuilder.set(i, fields.get(i)); + fieldCheckIndexesBuilder.set(i, fieldCheckIndexes.get(i)); + fieldInitializationStatusListBuilder.set(i, fieldInitializationStatusList.get(i)); + imageLayerWriter.writeConstant(bytecodeParsedFoldedFieldValuesList.get(i), bytecodeParsedFoldedFieldValuesListBuilder.get(i)); + imageLayerWriter.writeConstant(afterParsingHooksDoneFoldedFieldValuesList.get(i), afterParsingHooksDoneFoldedFieldValuesListBuilder.get(i)); } - return true; + + return PersistFlags.CREATE; } - static boolean isAllowedTargetMethod(ResolvedJavaMethod method) { - /* - * (1) Don't do this optimization for run-time compiled methods because this plugin and the - * nodes it references are not safe for execution at image run time. - * - * (2) Don't apply this optimization to deopt targets to save effort since deopt targets are - * not expected to be optimized - */ - return !SubstrateCompilationDirectives.isRuntimeCompiledMethod(method) && !SubstrateCompilationDirectives.isDeoptTarget(method); + @SuppressWarnings("unused") + public static Object createFromLoader(ImageSingletonLoader loader) { + var snapshotReader = ((SVMImageLayerSingletonLoader.ImageSingletonLoaderImpl) loader).getSnapshotReader(); + + var staticFinalFieldFoldingSingleton = snapshotReader.getStaticFinalFieldFoldingSingleton(); + var fields = staticFinalFieldFoldingSingleton.getFields(); + var fieldCheckIndexes = staticFinalFieldFoldingSingleton.getFieldCheckIndexes(); + var fieldInitializationStatusList = staticFinalFieldFoldingSingleton.getFieldInitializationStatusList(); + var bytecodeParsedFoldedFieldValuesList = staticFinalFieldFoldingSingleton.getBytecodeParsedFoldedFieldValues(); + var afterParsingHooksDoneFoldedFieldValuesList = staticFinalFieldFoldingSingleton.getAfterParsingHooksDoneFoldedFieldValues(); + + Map baseLayerFieldFoldingInfos = new HashMap<>(); + for (int i = 0; i < fields.size(); ++i) { + baseLayerFieldFoldingInfos.put(fields.get(i), new PriorLayerFinalFieldFoldingInfo(SVMImageLayerLoader.getConstant(bytecodeParsedFoldedFieldValuesList.get(i)), + SVMImageLayerLoader.getConstant(afterParsingHooksDoneFoldedFieldValuesList.get(i)), fieldCheckIndexes.get(i), fieldInitializationStatusList.get(i))); + } + return new StaticFinalFieldFoldingSingleton(baseLayerFieldFoldingInfos); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/StaticFinalFieldFoldingNodePlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/StaticFinalFieldFoldingNodePlugin.java index e0675ac46a9d..ee30264ba9ef 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/StaticFinalFieldFoldingNodePlugin.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/StaticFinalFieldFoldingNodePlugin.java @@ -62,7 +62,7 @@ public boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField fi return false; } - AnalysisField aField = StaticFinalFieldFoldingFeature.toAnalysisField(field); + AnalysisField aField = StaticFinalFieldFoldingSingleton.toAnalysisField(field); AnalysisMethod definingClassInitializer = aField.getDeclaringClass().getClassInitializer(); if (!StaticFinalFieldFoldingFeature.isOptimizationCandidate(aField, definingClassInitializer, fieldValueInterceptionSupport)) { return false; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/StaticFinalFieldFoldingPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/StaticFinalFieldFoldingPhase.java index ef657f96e1f9..2c01cfdaa7cd 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/StaticFinalFieldFoldingPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/fieldfolding/StaticFinalFieldFoldingPhase.java @@ -26,6 +26,7 @@ import java.util.Arrays; +import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.flow.AnalysisParsedGraph.Stage; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; @@ -64,11 +65,11 @@ public final class StaticFinalFieldFoldingPhase extends BasePhase { private final FieldValueInterceptionSupport fieldValueInterceptionSupport; - private final StaticFinalFieldFoldingFeature feature; + private final BigBang bb; public StaticFinalFieldFoldingPhase() { assert StaticFinalFieldFoldingFeature.isAvailable(); - this.feature = StaticFinalFieldFoldingFeature.singleton(); + this.bb = StaticFinalFieldFoldingFeature.singleton().bb; this.fieldValueInterceptionSupport = FieldValueInterceptionSupport.singleton(); } @@ -78,9 +79,7 @@ public static boolean isEnabled() { @Override protected void run(StructuredGraph graph, CoreProviders context) { - if (feature == null) { - return; - } + assert StaticFinalFieldFoldingFeature.isAvailable(); for (Node node : graph.getNodes()) { if (node instanceof LoadFieldNode loadFieldNode) { @@ -95,7 +94,7 @@ private void handleLoadFieldNode(StructuredGraph graph, MetaAccessProvider metaA return; } - AnalysisField aField = StaticFinalFieldFoldingFeature.toAnalysisField(field); + AnalysisField aField = StaticFinalFieldFoldingSingleton.toAnalysisField(field); AnalysisMethod definingClassInitializer = aField.getDeclaringClass().getClassInitializer(); if (!StaticFinalFieldFoldingFeature.isOptimizationCandidate(aField, definingClassInitializer, fieldValueInterceptionSupport)) { return; @@ -124,7 +123,7 @@ private void handleLoadFieldNode(StructuredGraph graph, MetaAccessProvider metaA */ if (!inClassInitializer || !graph.method().equals(definingClassInitializer)) { assert definingClassInitializer.isOriginalMethod(); - definingClassInitializer.ensureGraphParsed(feature.bb, stage); + definingClassInitializer.ensureGraphParsed(bb, stage); } /* @@ -140,7 +139,7 @@ private void handleLoadFieldNode(StructuredGraph graph, MetaAccessProvider metaA * results could vary depending on whether the declaring class initializer was already * parsed before or not. */ - JavaConstant initializedValue = feature.getFoldedFieldValue(stage, aField); + JavaConstant initializedValue = StaticFinalFieldFoldingSingleton.singleton().getFoldedFieldValue(stage, aField); if (initializedValue == null) { /* Field cannot be optimized. Remove the StateSplitProxyNode. */ FrameState frameState = stateSplitProxyNode.stateAfter(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java index 5506b5ec0c6c..ab0906b77370 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java @@ -97,7 +97,6 @@ import com.oracle.svm.hosted.code.CEntryPointCallStubSupport; import com.oracle.svm.hosted.code.CEntryPointData; import com.oracle.svm.hosted.code.FactoryMethodSupport; -import com.oracle.svm.hosted.fieldfolding.StaticFinalFieldFoldingFeature; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference; @@ -1046,12 +1045,6 @@ public void addBaseLayerField(AnalysisField analysisField) { @Override public void initializeBaseLayerField(AnalysisField analysisField) { PersistedAnalysisField.Reader fieldData = getFieldData(analysisField); - - int fieldCheckIndex = fieldData.getFieldCheckIndex(); - if (fieldCheckIndex != -1) { - StaticFinalFieldFoldingFeature.singleton().putBaseLayerFieldCheckIndex(analysisField.getId(), fieldCheckIndex); - } - assert fieldData != null : "The field should be in the base layer"; int location = fieldData.getLocation(); if (location != 0) { @@ -1599,4 +1592,31 @@ public ClassInitializationInfo getClassInitializationInfo(AnalysisType type) { return new ClassInitializationInfo(initState, initInfo.getHasInitializer(), initInfo.getIsBuildTimeInitialized(), isTracked); } } + + public static class JavaConstantSupplier { + private final ConstantReference.Reader constantReference; + + JavaConstantSupplier(ConstantReference.Reader constantReference) { + this.constantReference = constantReference; + } + + public JavaConstant get(SVMImageLayerLoader imageLayerLoader) { + return switch (constantReference.which()) { + case OBJECT_CONSTANT -> { + int id = constantReference.getObjectConstant().getConstantId(); + yield id == 0 ? null : imageLayerLoader.getOrCreateConstant(id); + } + case NULL_POINTER -> JavaConstant.NULL_POINTER; + case PRIMITIVE_VALUE -> { + PrimitiveValue.Reader pv = constantReference.getPrimitiveValue(); + yield JavaConstant.forPrimitive((char) pv.getTypeChar(), pv.getRawValue()); + } + default -> throw GraalError.shouldNotReachHere("Unexpected constant reference: " + constantReference.which()); + }; + } + } + + public static JavaConstantSupplier getConstant(ConstantReference.Reader constantReference) { + return new JavaConstantSupplier(constantReference); + } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java index fd6d4d46ad9c..858eb3352df1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java @@ -117,7 +117,6 @@ import com.oracle.svm.hosted.code.CEntryPointCallStubMethod; import com.oracle.svm.hosted.code.CEntryPointCallStubSupport; import com.oracle.svm.hosted.code.FactoryMethod; -import com.oracle.svm.hosted.fieldfolding.StaticFinalFieldFoldingFeature; import com.oracle.svm.hosted.image.NativeImageHeap; import com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue; @@ -136,7 +135,6 @@ import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant.Object.Relinking.EnumConstant; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant.Object.Relinking.StringConstant; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray; -import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.SharedLayerSnapshot; import com.oracle.svm.hosted.jni.JNIJavaCallVariantWrapperMethod; import com.oracle.svm.hosted.lambda.LambdaSubstitutionType; @@ -620,8 +618,6 @@ private void persistField(AnalysisField field, Supplier 0) { builder.setLocation(location); } - Integer fieldCheckIndex = StaticFinalFieldFoldingFeature.singleton().getFieldCheckIndex(field); - builder.setFieldCheckIndex((fieldCheckIndex != null) ? fieldCheckIndex : -1); Field originalField = OriginalFieldProvider.getJavaField(field); if (originalField != null && !originalField.getDeclaringClass().equals(field.getDeclaringClass().getJavaClass())) { @@ -828,20 +824,31 @@ private void persistConstantObjectData(PersistedConstant.Object.Builder builder, ConstantReference.Builder b = refsBuilder.get(i); if (delegateProcessing(b, object)) { /* The object was already persisted */ - } else if (object instanceof ImageHeapConstant imageHeapConstant) { - assert constantsMap.containsKey(imageHeapConstant); - b.initObjectConstant().setConstantId(ImageHeapConstant.getConstantID(imageHeapConstant)); - } else if (object == JavaConstant.NULL_POINTER) { - b.setNullPointer(Void.VOID); - } else if (object instanceof PrimitiveConstant pc) { - PrimitiveValue.Builder pb = b.initPrimitiveValue(); - pb.setTypeChar(NumUtil.safeToUByte(pc.getJavaKind().getTypeChar())); - pb.setRawValue(pc.getRawValue()); - } else { - AnalysisError.guarantee(object instanceof AnalysisFuture, "Unexpected constant %s", object); - b.setNotMaterialized(Void.VOID); + continue; + } + if (object instanceof JavaConstant javaConstant && maybeWriteConstant(javaConstant, b)) { + continue; } + AnalysisError.guarantee(object instanceof AnalysisFuture, "Unexpected constant %s", object); + b.setNotMaterialized(Void.VOID); + } + } + + private boolean maybeWriteConstant(JavaConstant constant, ConstantReference.Builder builder) { + if (constant instanceof ImageHeapConstant imageHeapConstant) { + assert constantsMap.containsKey(imageHeapConstant); + var ocb = builder.initObjectConstant(); + ocb.setConstantId(ImageHeapConstant.getConstantID(imageHeapConstant)); + } else if (constant instanceof PrimitiveConstant primitiveConstant) { + var pb = builder.initPrimitiveValue(); + pb.setTypeChar(NumUtil.safeToUByte(primitiveConstant.getJavaKind().getTypeChar())); + pb.setRawValue(primitiveConstant.getRawValue()); + } else if (constant == JavaConstant.NULL_POINTER) { + builder.setNullPointer(Void.VOID); + } else { + return false; } + return true; } private static boolean delegateProcessing(ConstantReference.Builder builder, Object constant) { @@ -1045,11 +1052,20 @@ private static void writeImageSingletonKeyStore(ImageSingletonObject.Builder obj } } + public void writeConstant(JavaConstant constant, ConstantReference.Builder builder) { + if (constant == null) { + return; + } + if (!maybeWriteConstant(constant, builder)) { + throw VMError.shouldNotReachHere("Unexpected constant: " + constant); + } + } + public static class ImageSingletonWriterImpl implements ImageSingletonWriter { private final EconomicMap keyValueStore = EconomicMap.create(); - private final SharedLayerSnapshotCapnProtoSchemaHolder.SharedLayerSnapshot.Builder snapshotBuilder; + private final SharedLayerSnapshot.Builder snapshotBuilder; - ImageSingletonWriterImpl(SharedLayerSnapshotCapnProtoSchemaHolder.SharedLayerSnapshot.Builder snapshotBuilder) { + ImageSingletonWriterImpl(SharedLayerSnapshot.Builder snapshotBuilder) { this.snapshotBuilder = snapshotBuilder; } @@ -1104,7 +1120,7 @@ public void writeStringList(String keyName, List value) { assert previous == null : Assertions.errorMessage(keyName, previous); } - public SharedLayerSnapshotCapnProtoSchemaHolder.SharedLayerSnapshot.Builder getSnapshotBuilder() { + public SharedLayerSnapshot.Builder getSnapshotBuilder() { return snapshotBuilder; } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java index 314092b6d105..cbe3313979e2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java @@ -2059,13 +2059,6 @@ public final void setName(String value) { public final org.capnproto.Text.Builder initName(int size) { return _initPointerField(org.capnproto.Text.factory, 2, size); } - public final int getFieldCheckIndex() { - return _getIntField(7); - } - public final void setFieldCheckIndex(int value) { - _setIntField(7, value); - } - } public static final class Reader extends org.capnproto.StructReader { @@ -2146,10 +2139,6 @@ public org.capnproto.Text.Reader getName() { return _getPointerField(org.capnproto.Text.factory, 2, null, 0, 0); } - public final int getFieldCheckIndex() { - return _getIntField(7); - } - } } @@ -4330,7 +4319,7 @@ public final org.capnproto.StructList.Reader { public Factory() { } @@ -4497,6 +4486,15 @@ public final void setNextLayerNumber(int value) { _setIntField(8, value); } + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.StaticFinalFieldFoldingSingleton.Builder getStaticFinalFieldFoldingSingleton() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.StaticFinalFieldFoldingSingleton.factory, 7, null, 0); + } + public final void setStaticFinalFieldFoldingSingleton(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.StaticFinalFieldFoldingSingleton.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.StaticFinalFieldFoldingSingleton.factory,7, value); + } + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.StaticFinalFieldFoldingSingleton.Builder initStaticFinalFieldFoldingSingleton() { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.StaticFinalFieldFoldingSingleton.factory,7, 0); + } } public static final class Reader extends org.capnproto.StructReader { @@ -4585,6 +4583,148 @@ public final int getNextLayerNumber() { return _getIntField(8); } + public boolean hasStaticFinalFieldFoldingSingleton() { + return !_pointerFieldIsNull(7); + } + public com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.StaticFinalFieldFoldingSingleton.Reader getStaticFinalFieldFoldingSingleton() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.StaticFinalFieldFoldingSingleton.factory,7,null, 0); + } + + } + + } + + + public static class StaticFinalFieldFoldingSingleton { + public static final org.capnproto.StructSize STRUCT_SIZE = new org.capnproto.StructSize((short)0,(short)5); + public static final class Factory extends org.capnproto.StructFactory { + public Factory() { + } + public final Reader constructReader(org.capnproto.SegmentReader segment, int data,int pointers, int dataSize, short pointerCount, int nestingLimit) { + return new Reader(segment,data,pointers,dataSize,pointerCount,nestingLimit); + } + public final Builder constructBuilder(org.capnproto.SegmentBuilder segment, int data,int pointers, int dataSize, short pointerCount) { + return new Builder(segment, data, pointers, dataSize, pointerCount); + } + public final org.capnproto.StructSize structSize() { + return StaticFinalFieldFoldingSingleton.STRUCT_SIZE; + } + public final Reader asReader(Builder builder) { + return builder.asReader(); + } + } + public static final Factory factory = new Factory(); + public static final org.capnproto.StructList.Factory listFactory = + new org.capnproto.StructList.Factory(factory); + public static final class Builder extends org.capnproto.StructBuilder { + Builder(org.capnproto.SegmentBuilder segment, int data, int pointers,int dataSize, short pointerCount){ + super(segment, data, pointers, dataSize, pointerCount); + } + public final Reader asReader() { + return new Reader(segment, data, pointers, dataSize, pointerCount, 0x7fffffff); + } + public final boolean hasFields() { + return !_pointerFieldIsNull(0); + } + public final org.capnproto.PrimitiveList.Int.Builder getFields() { + return _getPointerField(org.capnproto.PrimitiveList.Int.factory, 0, null, 0); + } + public final void setFields(org.capnproto.PrimitiveList.Int.Reader value) { + _setPointerField(org.capnproto.PrimitiveList.Int.factory, 0, value); + } + public final org.capnproto.PrimitiveList.Int.Builder initFields(int size) { + return _initPointerField(org.capnproto.PrimitiveList.Int.factory, 0, size); + } + public final boolean hasFieldCheckIndexes() { + return !_pointerFieldIsNull(1); + } + public final org.capnproto.PrimitiveList.Int.Builder getFieldCheckIndexes() { + return _getPointerField(org.capnproto.PrimitiveList.Int.factory, 1, null, 0); + } + public final void setFieldCheckIndexes(org.capnproto.PrimitiveList.Int.Reader value) { + _setPointerField(org.capnproto.PrimitiveList.Int.factory, 1, value); + } + public final org.capnproto.PrimitiveList.Int.Builder initFieldCheckIndexes(int size) { + return _initPointerField(org.capnproto.PrimitiveList.Int.factory, 1, size); + } + public final boolean hasFieldInitializationStatusList() { + return !_pointerFieldIsNull(2); + } + public final org.capnproto.PrimitiveList.Boolean.Builder getFieldInitializationStatusList() { + return _getPointerField(org.capnproto.PrimitiveList.Boolean.factory, 2, null, 0); + } + public final void setFieldInitializationStatusList(org.capnproto.PrimitiveList.Boolean.Reader value) { + _setPointerField(org.capnproto.PrimitiveList.Boolean.factory, 2, value); + } + public final org.capnproto.PrimitiveList.Boolean.Builder initFieldInitializationStatusList(int size) { + return _initPointerField(org.capnproto.PrimitiveList.Boolean.factory, 2, size); + } + public final boolean hasBytecodeParsedFoldedFieldValues() { + return !_pointerFieldIsNull(3); + } + public final org.capnproto.StructList.Builder getBytecodeParsedFoldedFieldValues() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference.listFactory, 3, null, 0); + } + public final void setBytecodeParsedFoldedFieldValues(org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference.listFactory, 3, value); + } + public final org.capnproto.StructList.Builder initBytecodeParsedFoldedFieldValues(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference.listFactory, 3, size); + } + public final boolean hasAfterParsingHooksDoneFoldedFieldValues() { + return !_pointerFieldIsNull(4); + } + public final org.capnproto.StructList.Builder getAfterParsingHooksDoneFoldedFieldValues() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference.listFactory, 4, null, 0); + } + public final void setAfterParsingHooksDoneFoldedFieldValues(org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference.listFactory, 4, value); + } + public final org.capnproto.StructList.Builder initAfterParsingHooksDoneFoldedFieldValues(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference.listFactory, 4, size); + } + } + + public static final class Reader extends org.capnproto.StructReader { + Reader(org.capnproto.SegmentReader segment, int data, int pointers,int dataSize, short pointerCount, int nestingLimit){ + super(segment, data, pointers, dataSize, pointerCount, nestingLimit); + } + + public final boolean hasFields() { + return !_pointerFieldIsNull(0); + } + public final org.capnproto.PrimitiveList.Int.Reader getFields() { + return _getPointerField(org.capnproto.PrimitiveList.Int.factory, 0, null, 0); + } + + public final boolean hasFieldCheckIndexes() { + return !_pointerFieldIsNull(1); + } + public final org.capnproto.PrimitiveList.Int.Reader getFieldCheckIndexes() { + return _getPointerField(org.capnproto.PrimitiveList.Int.factory, 1, null, 0); + } + + public final boolean hasFieldInitializationStatusList() { + return !_pointerFieldIsNull(2); + } + public final org.capnproto.PrimitiveList.Boolean.Reader getFieldInitializationStatusList() { + return _getPointerField(org.capnproto.PrimitiveList.Boolean.factory, 2, null, 0); + } + + public final boolean hasBytecodeParsedFoldedFieldValues() { + return !_pointerFieldIsNull(3); + } + public final org.capnproto.StructList.Reader getBytecodeParsedFoldedFieldValues() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference.listFactory, 3, null, 0); + } + + public final boolean hasAfterParsingHooksDoneFoldedFieldValues() { + return !_pointerFieldIsNull(4); + } + public final org.capnproto.StructList.Reader getAfterParsingHooksDoneFoldedFieldValues() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference.listFactory, 4, null, 0); + } + } }