From 46c01ad3e76fcdadcd2d36d1f5e1c826b9a2a816 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Tue, 13 Aug 2024 12:23:06 +0200 Subject: [PATCH] Persist type and methods flags across layers --- .../pointsto/heap/ImageHeapInstance.java | 4 + .../graal/pointsto/heap/ImageHeapScanner.java | 6 +- .../graal/pointsto/heap/ImageLayerLoader.java | 180 ++++++++++++------ .../pointsto/heap/ImageLayerSnapshotUtil.java | 31 ++- .../graal/pointsto/heap/ImageLayerWriter.java | 29 +++ .../graal/pointsto/meta/AnalysisField.java | 2 +- .../graal/pointsto/meta/AnalysisMethod.java | 8 +- .../graal/pointsto/meta/AnalysisUniverse.java | 33 +++- .../graal/pointsto/meta/BaseLayerMethod.java | 13 +- .../graal/pointsto/meta/BaseLayerType.java | 11 +- .../oracle/svm/hosted/ClassValueFeature.java | 4 + .../svm/hosted/HeapBreakdownProvider.java | 30 +-- .../AnalysisConstantReflectionProvider.java | 4 + .../AnalysisMethodHandleAccessProvider.java | 4 + .../analysis/DynamicHubInitializer.java | 9 +- .../ClassInitializationSupport.java | 5 + .../SimulateClassInitializerSupport.java | 4 + .../oracle/svm/hosted/code/CompileQueue.java | 14 +- .../heap/SVMImageLayerSnapshotUtil.java | 8 +- .../svm/hosted/heap/SVMImageLayerWriter.java | 4 + .../methodhandles/MethodHandleFeature.java | 4 + 21 files changed, 308 insertions(+), 99 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java index a2d1a845f70d..dc8298f85f39 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapInstance.java @@ -103,6 +103,10 @@ void setFieldValues(Object[] fieldValues) { AnalysisError.guarantee(success, "Unexpected field values reference for constant %s", this); } + public boolean nullFieldValues() { + return getConstantData().fieldValues == null; + } + /** * {@link InstanceData#fieldValues} are only set once, in {@link #setFieldValues(Object[])} and * shouldn't be accessed before set, i.e., read access is guarded by diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java index 8761aa5f41c7..69ef06d1953d 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java @@ -140,11 +140,7 @@ public void onFieldRead(AnalysisField field) { * GR-52421: the field state needs to be serialized from the base layer analysis */ if (field.getJavaKind().isObject()) { - AnalysisType fieldType = field.getType(); - if (fieldType.isArray() || (fieldType.isInstanceClass() && !fieldType.isAbstract())) { - fieldType.registerAsInstantiated(field); - } - bb.injectFieldTypes(field, List.of(fieldType), true); + bb.injectFieldTypes(field, List.of(field.getType()), true); } return; } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java index 18bf9ad19e9b..2e88bffa5caf 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java @@ -32,6 +32,7 @@ import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CLASS_JAVA_NAME_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CLASS_NAME_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CODE_SIZE_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CODE_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.COMPONENT_TYPE_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CONSTANTS_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CONSTANTS_TO_RELINK_TAG; @@ -55,15 +56,25 @@ import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INTERFACES_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INTRINSIC_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_CONSTRUCTOR_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_DIRECT_ROOT_METHOD; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_ENUM_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_IMPLEMENTATION_INVOKED; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INITIALIZED_AT_BUILD_TIME_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INITIALIZED_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INSTANTIATED; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INTERFACE_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INTERNAL_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INTRINSIC_METHOD; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INVOKED; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_LINKED_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_REACHABLE; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_SYNTHETIC_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_UNSAFE_ALLOCATED; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_VAR_ARGS_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_VIRTUAL_ROOT_METHOD; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.LOCATION_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.METHODS_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.METHOD_HANDLE_INTRINSIC_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.MODIFIERS_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.NAME_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.NEXT_FIELD_ID_TAG; @@ -100,6 +111,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; import java.util.stream.Collectors; import org.graalvm.collections.EconomicMap; @@ -130,6 +142,7 @@ import jdk.graal.compiler.util.json.JsonParser; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MethodHandleAccessProvider.IntrinsicMethod; import jdk.vm.ci.meta.PrimitiveConstant; import jdk.vm.ci.meta.ResolvedJavaType; @@ -157,11 +170,15 @@ * "is interface": isInterface, * "is enum": isEnum, * "is initialized": isInitialized, + * "is initialized at build time": isInitializedAtBuildTime, * "is linked": isLinked, * "source file name": sourceFileName, * "enclosing type": enclosingTid, * "component type": componentTid, * "super class": superClassTid, + * "is instantiated": isInstantiated, + * "is unsafe allocated": isUnsafeAllocated, + * "is reachable": isReachable, * "interfaces": [ * interfaceTid, * ... @@ -194,8 +211,15 @@ * "modifiers": modifiers, * "is constructor": isConstructor, * "is synthetic": isSynthetic, + * "code": code, * "code size": codeSize, + * "method handle intrinsic": methodHandleIntrinsic, * "compiled": compiled, + * "is virtual root method": isVirtualRootMethod, + * "is direct root method": isDirectRootMethod, + * "is invoked": isInvoked, + * "is implementation invoked": isImplementationInvoked, + * "is intrinsic method": isIntrinsicMethod, * "annotations": [ * annotationName, * ... @@ -282,8 +306,14 @@ public class ImageLayerLoader { private final Map baseLayerTypes = new ConcurrentHashMap<>(); private final Map typeToHubIdentityHashCode = new HashMap<>(); private final Map baseLayerMethods = new ConcurrentHashMap<>(); + + /** Map from the type id to its identifier in the jsonMap. */ private final Map typeIdToIdentifier = new HashMap<>(); + + /** Map from the method id to its identifier in the jsonMap. */ private final Map methodIdToIdentifier = new HashMap<>(); + + /** Map from the field id to the information needed to access it in the jsonMap. */ private final Map fieldIdToIdentifier = new HashMap<>(); record FieldIdentifier(String tid, String name) { @@ -367,7 +397,6 @@ private void loadLayerAnalysis0() { imageHeapSize = Long.parseLong(get(jsonMap, IMAGE_HEAP_SIZE_TAG)); - /* Those mappings allow to get the base layer information from a type or method id */ storeIdToIdentifier(TYPES_TAG, typeIdToIdentifier); storeIdToIdentifier(METHODS_TAG, methodIdToIdentifier); @@ -445,6 +474,7 @@ private void loadType(EconomicMap typeData) { boolean isInterface = get(typeData, IS_INTERFACE_TAG); boolean isEnum = get(typeData, IS_ENUM_TAG); boolean isInitialized = get(typeData, IS_INITIALIZED_TAG); + boolean initializedAtBuildTime = get(typeData, IS_INITIALIZED_AT_BUILD_TIME_TAG); boolean isLinked = get(typeData, IS_LINKED_TAG); String sourceFileName = get(typeData, SOURCE_FILE_NAME_TAG); @@ -464,8 +494,8 @@ private void loadType(EconomicMap typeData) { Annotation[] annotations = getAnnotations(typeData); - return new BaseLayerType(className, tid, modifiers, isInterface, isEnum, isInitialized, isLinked, sourceFileName, enclosingType, componentType, superClass, interfaces, objectType, - annotations); + return new BaseLayerType(className, tid, modifiers, isInterface, isEnum, isInitialized, initializedAtBuildTime, isLinked, sourceFileName, enclosingType, componentType, superClass, + interfaces, objectType, annotations); }); BaseLayerType baseLayerType = baseLayerTypes.get(tid); AnalysisType type = universe.lookup(baseLayerType); @@ -524,6 +554,29 @@ private int getBaseLayerTypeId(AnalysisType type) { return id; } + public void initializeBaseLayerType(AnalysisType type) { + String typeIdentifier = typeIdToIdentifier.get(type.getId()); + boolean post = true; + if (typeIdentifier == null) { + /* + * This type was not already created when loading the base layer, so the flags can be + * registered directly. + */ + post = false; + typeIdentifier = imageLayerSnapshotUtil.getTypeIdentifier(type); + } + EconomicMap typeData = getElementData(TYPES_TAG, typeIdentifier); + if (typeData != null) { + boolean isInstantiated = get(typeData, IS_INSTANTIATED); + boolean isUnsafeAllocated = get(typeData, IS_UNSAFE_ALLOCATED); + boolean isReachable = get(typeData, IS_REACHABLE); + + registerFlag(isInstantiated, post, () -> type.registerAsInstantiated(PERSISTED)); + registerFlag(isUnsafeAllocated, post, () -> type.registerAsUnsafeAllocated(PERSISTED)); + registerFlag(isReachable, post, () -> type.registerAsReachable(PERSISTED)); + } + } + /** * Tries to look up the base layer type in the current VM. Some types cannot be looked up by * name (for example $$Lambda types), so this method can return null. @@ -647,11 +700,15 @@ private void createBaseLayerMethod(EconomicMap methodData, int m int modifiers = get(methodData, MODIFIERS_TAG); boolean isSynthetic = get(methodData, IS_SYNTHETIC_TAG); boolean isVarArgs = get(methodData, IS_VAR_ARGS_TAG); + List codeEncoding = get(methodData, CODE_TAG); + byte[] code = codeEncoding == null ? null : getBytes(codeEncoding); int codeSize = get(methodData, CODE_SIZE_TAG); + String methodHandleIntrinsicName = get(methodData, METHOD_HANDLE_INTRINSIC_TAG); + IntrinsicMethod methodHandleIntrinsic = methodHandleIntrinsicName == null ? null : IntrinsicMethod.valueOf(methodHandleIntrinsicName); Annotation[] annotations = getAnnotations(methodData); - baseLayerMethods.computeIfAbsent(mid, - methodId -> new BaseLayerMethod(mid, type, name, isVarArgs, signature, canBeStaticallyBound, isConstructor, modifiers, isSynthetic, codeSize, annotations)); + baseLayerMethods.computeIfAbsent(mid, methodId -> new BaseLayerMethod(mid, type, name, isVarArgs, signature, canBeStaticallyBound, isConstructor, modifiers, isSynthetic, code, codeSize, + methodHandleIntrinsic, annotations)); BaseLayerMethod baseLayerMethod = baseLayerMethods.get(mid); universe.lookup(baseLayerMethod); @@ -689,16 +746,26 @@ private int getBaseLayerMethodId(AnalysisMethod analysisMethod) { return get(methodData, ID_TAG); } - public void initializeBaseLayerMethod(AnalysisMethod analysisMethod) { - int id = analysisMethod.getId(); - methods.putIfAbsent(id, analysisMethod); + public void addBaseLayerMethod(AnalysisMethod analysisMethod) { + methods.putIfAbsent(analysisMethod.getId(), analysisMethod); + } + public void initializeBaseLayerMethod(AnalysisMethod analysisMethod) { initializeBaseLayerMethod(analysisMethod, getMethodData(analysisMethod)); } - @SuppressWarnings("unused") protected void initializeBaseLayerMethod(AnalysisMethod analysisMethod, EconomicMap methodData) { - /* No flags to load in the AnalysisMethod */ + boolean isVirtualRootMethod = get(methodData, IS_VIRTUAL_ROOT_METHOD); + boolean isDirectRootMethod = get(methodData, IS_DIRECT_ROOT_METHOD); + boolean isInvoked = get(methodData, IS_INVOKED); + boolean isImplementationInvoked = get(methodData, IS_IMPLEMENTATION_INVOKED); + boolean isIntrinsicMethod = get(methodData, IS_INTRINSIC_METHOD); + + registerFlag(isVirtualRootMethod, true, () -> analysisMethod.registerAsVirtualRootMethod(PERSISTED)); + registerFlag(isDirectRootMethod, true, () -> analysisMethod.registerAsDirectRootMethod(PERSISTED)); + registerFlag(isInvoked, true, () -> analysisMethod.registerAsInvoked(PERSISTED)); + registerFlag(isImplementationInvoked, true, () -> analysisMethod.registerAsImplementationInvoked(PERSISTED)); + registerFlag(isIntrinsicMethod, true, () -> analysisMethod.registerAsIntrinsicMethod(PERSISTED)); } /** @@ -721,7 +788,7 @@ public AnalysisParsedGraph getAnalysisParsedGraph(AnalysisMethod analysisMethod) * GR-55278: graphs that contain a reference to a $$Lambda cannot be persisted as well. */ if (encodedAnalyzedGraph != null) { - EncodedGraph analyzedGraph = (EncodedGraph) ObjectCopier.decode(imageLayerSnapshotUtil.getGraphDecoder(this, universe.getSnippetReflection()), encodedAnalyzedGraph); + EncodedGraph analyzedGraph = (EncodedGraph) ObjectCopier.decode(imageLayerSnapshotUtil.getGraphDecoder(this, analysisMethod, universe.getSnippetReflection()), encodedAnalyzedGraph); if (hasStrengthenedGraph(analysisMethod)) { loadAllAnalysisElements(get(methodData, STRENGTHENED_GRAPH_TAG)); } @@ -738,7 +805,7 @@ public boolean hasStrengthenedGraph(AnalysisMethod analysisMethod) { public void setStrengthenedGraph(AnalysisMethod analysisMethod) { EconomicMap methodData = getMethodData(analysisMethod); String encodedAnalyzedGraph = get(methodData, STRENGTHENED_GRAPH_TAG); - EncodedGraph analyzedGraph = (EncodedGraph) ObjectCopier.decode(imageLayerSnapshotUtil.getGraphDecoder(this, universe.getSnippetReflection()), encodedAnalyzedGraph); + EncodedGraph analyzedGraph = (EncodedGraph) ObjectCopier.decode(imageLayerSnapshotUtil.getGraphDecoder(this, analysisMethod, universe.getSnippetReflection()), encodedAnalyzedGraph); processGraph(analyzedGraph); analysisMethod.setAnalyzedGraph(analyzedGraph); } @@ -831,33 +898,31 @@ private int getBaseLayerFieldId(AnalysisField analysisField) { return get(fieldData, ID_TAG); } - public void initializeBaseLayerField(AnalysisField analysisField) { - if (fields.putIfAbsent(analysisField.getId(), analysisField) == null) { - EconomicMap fieldData = getFieldData(analysisField); + public void addBaseLayerField(AnalysisField analysisField) { + fields.putIfAbsent(analysisField.getId(), analysisField); + } - if (fieldData == null) { - /* The field was not reachable in the base image */ - return; - } + public void initializeBaseLayerField(AnalysisField analysisField) { + EconomicMap fieldData = getFieldData(analysisField); - Integer location = get(fieldData, LOCATION_TAG); - if (location != null) { - fieldLocations.put(analysisField, location); - } + assert fieldData != null : "The field should be in the base layer"; + Integer location = get(fieldData, LOCATION_TAG); + if (location != null) { + fieldLocations.put(analysisField, location); + } - boolean isAccessed = get(fieldData, FIELD_ACCESSED_TAG); - boolean isRead = get(fieldData, FIELD_READ_TAG); - boolean isWritten = get(fieldData, FIELD_WRITTEN_TAG); - boolean isFolded = get(fieldData, FIELD_FOLDED_TAG); + boolean isAccessed = get(fieldData, FIELD_ACCESSED_TAG); + boolean isRead = get(fieldData, FIELD_READ_TAG); + boolean isWritten = get(fieldData, FIELD_WRITTEN_TAG); + boolean isFolded = get(fieldData, FIELD_FOLDED_TAG); - if (!analysisField.isStatic() && (isAccessed || isRead)) { - analysisField.getDeclaringClass().getInstanceFields(true); - } - registerFieldFlag(isAccessed, () -> analysisField.registerAsAccessed(PERSISTED)); - registerFieldFlag(isRead, () -> analysisField.registerAsRead(PERSISTED)); - registerFieldFlag(isWritten, () -> analysisField.registerAsWritten(PERSISTED)); - registerFieldFlag(isFolded, () -> analysisField.registerAsFolded(PERSISTED)); + if (!analysisField.isStatic() && (isAccessed || isRead)) { + analysisField.getDeclaringClass().getInstanceFields(true); } + registerFlag(isAccessed, true, () -> analysisField.registerAsAccessed(PERSISTED)); + registerFlag(isRead, true, () -> analysisField.registerAsRead(PERSISTED)); + registerFlag(isWritten, true, () -> analysisField.registerAsWritten(PERSISTED)); + registerFlag(isFolded, true, () -> analysisField.registerAsFolded(PERSISTED)); } private EconomicMap getFieldData(AnalysisField analysisField) { @@ -870,10 +935,14 @@ private EconomicMap getFieldData(AnalysisField analysisField) { return get(typeFieldsMap, analysisField.getName()); } - private void registerFieldFlag(boolean flag, Runnable runnable) { + private void registerFlag(boolean flag, boolean post, Runnable runnable) { if (flag) { if (universe.getBigbang() != null) { - universe.getBigbang().postTask(debug -> runnable.run()); + if (post) { + universe.getBigbang().postTask(debug -> runnable.run()); + } else { + runnable.run(); + } } else { heapScannerTasks.add(new AnalysisFuture<>(runnable)); } @@ -922,25 +991,29 @@ protected ImageHeapConstant getOrCreateConstant(EconomicMap cons Object relinkedObject = hostedValuesProvider.asObject(Object.class, relinkedHostedObject); AnalysisError.guarantee(object == relinkedObject, "Found discrepancy between hosted value %s and relinked value %s.", object, relinkedObject); } - ImageHeapInstance imageHeapInstance = new ImageHeapInstance(type, hostedObject == null ? relinkedHostedObject : hostedObject, identityHashCode); - if (instanceData != null) { - Object[] fieldValues = getReferencedValues(constantsMap, imageHeapInstance, instanceData, imageLayerSnapshotUtil.getRelinkedFields(type, metaAccess)); - imageHeapInstance.setFieldValues(fieldValues); - } - addBaseLayerObject(id, imageHeapInstance, objectOffset); + + addBaseLayerObject(id, objectOffset, () -> { + ImageHeapInstance imageHeapInstance = new ImageHeapInstance(type, hostedObject == null ? relinkedHostedObject : hostedObject, identityHashCode); + if (instanceData != null) { + Object[] fieldValues = getReferencedValues(constantsMap, imageHeapInstance, instanceData, imageLayerSnapshotUtil.getRelinkedFields(type, metaAccess)); + imageHeapInstance.setFieldValues(fieldValues); + } + return imageHeapInstance; + }); } case ARRAY_TAG -> { List> arrayData = get(baseLayerConstant, DATA_TAG); - ImageHeapObjectArray imageHeapObjectArray = new ImageHeapObjectArray(type, null, arrayData.size(), identityHashCode); - Object[] elementsValues = getReferencedValues(constantsMap, imageHeapObjectArray, arrayData, Set.of()); - imageHeapObjectArray.setElementValues(elementsValues); - addBaseLayerObject(id, imageHeapObjectArray, objectOffset); + addBaseLayerObject(id, objectOffset, () -> { + ImageHeapObjectArray imageHeapObjectArray = new ImageHeapObjectArray(type, null, arrayData.size(), identityHashCode); + Object[] elementsValues = getReferencedValues(constantsMap, imageHeapObjectArray, arrayData, Set.of()); + imageHeapObjectArray.setElementValues(elementsValues); + return imageHeapObjectArray; + }); } case PRIMITIVE_ARRAY_TAG -> { List primitiveData = get(baseLayerConstant, DATA_TAG); Object array = getArray(type.getComponentType().getJavaKind(), primitiveData); - ImageHeapPrimitiveArray imageHeapPrimitiveArray = new ImageHeapPrimitiveArray(type, null, array, primitiveData.size(), identityHashCode); - addBaseLayerObject(id, imageHeapPrimitiveArray, objectOffset); + addBaseLayerObject(id, objectOffset, () -> new ImageHeapPrimitiveArray(type, null, array, primitiveData.size(), identityHashCode)); } default -> throw GraalError.shouldNotReachHere("Unknown constant type: " + constantType); } @@ -1165,10 +1238,10 @@ private static double getDouble(Object value) { return Double.longBitsToDouble((long) value); } - private void addBaseLayerObject(int id, ImageHeapConstant heapObj, String objectOffset) { - heapObj.markInBaseLayer(); - ImageHeapConstant constant = constants.putIfAbsent(id, heapObj); - if (constant == null) { + private void addBaseLayerObject(int id, String objectOffset, Supplier imageHeapConstantSupplier) { + constants.computeIfAbsent(id, key -> { + ImageHeapConstant heapObj = imageHeapConstantSupplier.get(); + heapObj.markInBaseLayer(); /* * Packages are normally rescanned when the DynamicHub is initialized. However, since * they are not relinked, the packages from the base layer will never be marked as @@ -1180,7 +1253,8 @@ private void addBaseLayerObject(int id, ImageHeapConstant heapObj, String object if (objectOffset != null) { objectOffsets.put(heapObj.constantData.id, Long.parseLong(objectOffset)); } - } + return heapObj; + }); } private EconomicMap getElementData(String registry, String elementIdentifier) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java index 393f903f7add..58f1cdeb921b 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java @@ -78,8 +78,18 @@ public class ImageLayerSnapshotUtil { public static final String CAN_BE_STATICALLY_BOUND_TAG = "can be statically bound"; public static final String IS_CONSTRUCTOR_TAG = "is constructor"; public static final String IS_SYNTHETIC_TAG = "is synthetic"; + public static final String CODE_TAG = "code"; public static final String CODE_SIZE_TAG = "code size"; + public static final String METHOD_HANDLE_INTRINSIC_TAG = "method handle intrinsic"; + public static final String IS_VIRTUAL_ROOT_METHOD = "is virtual root method"; + public static final String IS_DIRECT_ROOT_METHOD = "is direct root method"; + public static final String IS_INVOKED = "is invoked"; + public static final String IS_IMPLEMENTATION_INVOKED = "is implementation invoked"; + public static final String IS_INTRINSIC_METHOD = "is intrinsic method"; public static final String ANNOTATIONS_TAG = "annotations"; + public static final String IS_INSTANTIATED = "is instantiated"; + public static final String IS_UNSAFE_ALLOCATED = "is unsafe allocated"; + public static final String IS_REACHABLE = "is reachable"; public static final String CLASS_NAME_TAG = "class name"; public static final String MODIFIERS_TAG = "modifiers"; public static final String POSITION_TAG = "position"; @@ -109,6 +119,7 @@ public class ImageLayerSnapshotUtil { public static final String THROW_ALLOCATED_OBJECT_TAG = "throw allocated object"; public static final String IDENTITY_HASH_CODE_TAG = "identityHashCode"; public static final String HUB_IDENTITY_HASH_CODE_TAG = "hub identityHashCode"; + public static final String IS_INITIALIZED_AT_BUILD_TIME_TAG = "is initialized at build time"; public static final String ID_TAG = "id"; public static final String ANALYSIS_PARSED_GRAPH_TAG = "analysis parsed graph"; public static final String STRENGTHENED_GRAPH_TAG = "strengthened graph"; @@ -204,8 +215,8 @@ public GraphEncoder getGraphEncoder(ImageLayerWriter imageLayerWriter) { } @SuppressWarnings("unused") - public GraphDecoder getGraphDecoder(ImageLayerLoader imageLayerLoader, SnippetReflectionProvider snippetReflectionProvider) { - return new GraphDecoder(EncodedGraph.class.getClassLoader(), imageLayerLoader); + public GraphDecoder getGraphDecoder(ImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { + return new GraphDecoder(EncodedGraph.class.getClassLoader(), imageLayerLoader, analysisMethod); } public static class GraphEncoder extends ObjectCopier.Encoder { @@ -215,7 +226,7 @@ public GraphEncoder(List externalValues, ImageLayerWriter imageLayerWrite addBuiltin(new NodeClassBuiltIn()); addBuiltin(new ImageHeapConstantBuiltIn(imageLayerWriter, null)); addBuiltin(new AnalysisTypeBuiltIn(imageLayerWriter, null)); - addBuiltin(new AnalysisMethodBuiltIn(imageLayerWriter, null)); + addBuiltin(new AnalysisMethodBuiltIn(imageLayerWriter, null, null)); addBuiltin(new AnalysisFieldBuiltIn(imageLayerWriter, null)); addBuiltin(new FieldLocationIdentityBuiltIn(imageLayerWriter, null)); addBuiltin(new NamedLocationIdentityArrayBuiltIn()); @@ -224,12 +235,12 @@ public GraphEncoder(List externalValues, ImageLayerWriter imageLayerWrite public static class GraphDecoder extends ObjectCopier.Decoder { @SuppressWarnings("this-escape") - public GraphDecoder(ClassLoader classLoader, ImageLayerLoader imageLayerLoader) { + public GraphDecoder(ClassLoader classLoader, ImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod) { super(classLoader); addBuiltin(new NodeClassBuiltIn()); addBuiltin(new ImageHeapConstantBuiltIn(null, imageLayerLoader)); addBuiltin(new AnalysisTypeBuiltIn(null, imageLayerLoader)); - addBuiltin(new AnalysisMethodBuiltIn(null, imageLayerLoader)); + addBuiltin(new AnalysisMethodBuiltIn(null, imageLayerLoader, analysisMethod)); addBuiltin(new AnalysisFieldBuiltIn(null, imageLayerLoader)); addBuiltin(new FieldLocationIdentityBuiltIn(null, imageLayerLoader)); addBuiltin(new NamedLocationIdentityArrayBuiltIn()); @@ -304,11 +315,13 @@ protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, Str public static class AnalysisMethodBuiltIn extends ObjectCopier.Builtin { private final ImageLayerWriter imageLayerWriter; private final ImageLayerLoader imageLayerLoader; + private final AnalysisMethod analysisMethod; - protected AnalysisMethodBuiltIn(ImageLayerWriter imageLayerWriter, ImageLayerLoader imageLayerLoader) { + protected AnalysisMethodBuiltIn(ImageLayerWriter imageLayerWriter, ImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod) { super(AnalysisMethod.class, PointsToAnalysisMethod.class); this.imageLayerWriter = imageLayerWriter; this.imageLayerLoader = imageLayerLoader; + this.analysisMethod = analysisMethod; } @Override @@ -334,7 +347,11 @@ public String encode(ObjectCopier.Encoder encoder, Object obj) { @Override protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, String encoding, String encoded) { - return imageLayerLoader.getAnalysisMethod(Integer.parseInt(encoded)); + int id = Integer.parseInt(encoded); + if (id == analysisMethod.getId()) { + return analysisMethod; + } + return imageLayerLoader.getAnalysisMethod(id); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java index 75bc0f68fefe..0e5f0f9372d6 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java @@ -33,6 +33,7 @@ import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CLASS_JAVA_NAME_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CLASS_NAME_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CODE_SIZE_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CODE_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.COMPONENT_TYPE_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CONSTANTS_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CONSTANTS_TO_RELINK_TAG; @@ -54,14 +55,23 @@ import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INTERFACES_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INTRINSIC_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_CONSTRUCTOR_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_DIRECT_ROOT_METHOD; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_ENUM_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_IMPLEMENTATION_INVOKED; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INITIALIZED_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INSTANTIATED; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INTERFACE_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INTERNAL_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INTRINSIC_METHOD; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INVOKED; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_LINKED_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_REACHABLE; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_SYNTHETIC_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_UNSAFE_ALLOCATED; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_VAR_ARGS_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_VIRTUAL_ROOT_METHOD; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.METHODS_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.METHOD_HANDLE_INTRINSIC_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.MODIFIERS_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.NAME_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.NEXT_FIELD_ID_TAG; @@ -117,6 +127,7 @@ import jdk.graal.compiler.util.json.JsonWriter; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MethodHandleAccessProvider.IntrinsicMethod; import jdk.vm.ci.meta.PrimitiveConstant; import jdk.vm.ci.meta.ResolvedJavaField; @@ -295,6 +306,10 @@ protected void persistType(AnalysisType type, EconomicMap typeMa } typeMap.put(INTERFACES_TAG, Arrays.stream(type.getInterfaces()).map(AnalysisType::getId).toList()); typeMap.put(ANNOTATIONS_TAG, Arrays.stream(AnnotationAccess.getAnnotationTypes(type)).map(Class::getName).toList()); + + typeMap.put(IS_INSTANTIATED, type.isInstantiated()); + typeMap.put(IS_UNSAFE_ALLOCATED, type.isUnsafeAllocated()); + typeMap.put(IS_REACHABLE, type.isReachable()); } /** @@ -327,9 +342,23 @@ public void persistMethod(AnalysisMethod method) { methodMap.put(MODIFIERS_TAG, method.getModifiers()); methodMap.put(IS_CONSTRUCTOR_TAG, method.isConstructor()); methodMap.put(IS_SYNTHETIC_TAG, method.isSynthetic()); + byte[] code = method.getCode(); + if (code != null) { + methodMap.put(CODE_TAG, getString(JavaKind.Byte, method.getCode())); + } methodMap.put(CODE_SIZE_TAG, method.getCodeSize()); + IntrinsicMethod intrinsicMethod = aUniverse.getBigbang().getConstantReflectionProvider().getMethodHandleAccess().lookupMethodHandleIntrinsic(method); + if (intrinsicMethod != null) { + methodMap.put(METHOD_HANDLE_INTRINSIC_TAG, intrinsicMethod.name()); + } methodMap.put(ANNOTATIONS_TAG, Arrays.stream(AnnotationAccess.getAnnotationTypes(method)).map(Class::getName).toList()); + methodMap.put(IS_VIRTUAL_ROOT_METHOD, method.isVirtualRootMethod()); + methodMap.put(IS_DIRECT_ROOT_METHOD, method.isDirectRootMethod()); + methodMap.put(IS_INVOKED, method.isSimplyInvoked()); + methodMap.put(IS_IMPLEMENTATION_INVOKED, method.isSimplyImplementationInvoked()); + methodMap.put(IS_INTRINSIC_METHOD, method.isIntrinsicMethod()); + imageLayerWriterHelper.persistMethod(method, methodMap); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java index c8486dff0990..97c0e223af8d 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java @@ -133,7 +133,7 @@ public AnalysisField(AnalysisUniverse universe, ResolvedJavaField wrappedField) sinkFlow = new ContextInsensitiveFieldTypeFlow(this, getType()); } - if (universe.hostVM().useBaseLayer()) { + if (universe.hostVM().useBaseLayer() && declaringClass.isInBaseLayer()) { int fid = universe.getImageLayerLoader().lookupHostedFieldInBaseLayer(this); if (fid != -1) { /* diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java index 8b6dc0412a31..7c6f8614b7ef 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java @@ -210,7 +210,7 @@ protected AnalysisMethod(AnalysisUniverse universe, ResolvedJavaMethod wrapped, qualifiedName = format("%H.%n(%P)"); modifiers = wrapped.getModifiers(); - if (universe.hostVM().useBaseLayer()) { + if (universe.hostVM().useBaseLayer() && declaringClass.isInBaseLayer()) { int mid = universe.getImageLayerLoader().lookupHostedMethodInBaseLayer(this); if (mid != -1) { /* @@ -520,6 +520,10 @@ public boolean isDirectRootMethod() { return AtomicUtils.isSet(this, isDirectRootMethodUpdater); } + public boolean isSimplyInvoked() { + return AtomicUtils.isSet(this, isInvokedUpdater); + } + public boolean isSimplyImplementationInvoked() { return AtomicUtils.isSet(this, isImplementationInvokedUpdater); } @@ -531,7 +535,7 @@ public boolean isInvoked() { return isIntrinsicMethod() || isVirtualRootMethod() || isDirectRootMethod() || AtomicUtils.isSet(this, isInvokedUpdater); } - protected Object getInvokedReason() { + public Object getInvokedReason() { return isInvoked; } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java index 94c7645260f2..1ff65dd3bc49 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java @@ -215,6 +215,9 @@ public JavaType lookupAllowUnresolved(JavaType rawType) { AnalysisType result = optionalLookup(type); if (result == null) { result = createType(type); + if (hostVM.useBaseLayer()) { + imageLayerLoader.initializeBaseLayerType(result); + } } assert typesById[result.getId()].equals(result) : result; return result; @@ -372,11 +375,20 @@ private AnalysisField createField(ResolvedJavaField field) { return null; } AnalysisField newValue = analysisFactory.createField(this, field); - AnalysisField oldValue = fields.putIfAbsent(field, newValue); - if (oldValue == null && newValue.isInBaseLayer()) { - getImageLayerLoader().initializeBaseLayerField(newValue); + AnalysisField result = fields.computeIfAbsent(field, f -> { + if (newValue.isInBaseLayer()) { + getImageLayerLoader().addBaseLayerField(newValue); + } + return newValue; + }); + + if (result.equals(newValue)) { + if (newValue.isInBaseLayer()) { + getImageLayerLoader().initializeBaseLayerField(newValue); + } } - return oldValue != null ? oldValue : newValue; + + return result; } @Override @@ -418,15 +430,22 @@ private AnalysisMethod createMethod(ResolvedJavaMethod method) { return null; } AnalysisMethod newValue = analysisFactory.createMethod(this, method); - AnalysisMethod oldValue = methods.putIfAbsent(method, newValue); + AnalysisMethod result = methods.computeIfAbsent(method, m -> { + if (newValue.isInBaseLayer()) { + getImageLayerLoader().addBaseLayerMethod(newValue); + } + return newValue; + }); - if (oldValue == null) { + if (result.equals(newValue)) { if (newValue.isInBaseLayer()) { getImageLayerLoader().initializeBaseLayerMethod(newValue); } + prepareMethodImplementations(newValue); } - return oldValue != null ? oldValue : newValue; + + return result; } /** Prepare information that {@link AnalysisMethod#collectMethodImplementations} needs. */ diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerMethod.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerMethod.java index 5418cba73cc4..b1d5e78fe675 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerMethod.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerMethod.java @@ -35,6 +35,7 @@ import jdk.vm.ci.meta.ExceptionHandler; import jdk.vm.ci.meta.LineNumberTable; import jdk.vm.ci.meta.LocalVariableTable; +import jdk.vm.ci.meta.MethodHandleAccessProvider.IntrinsicMethod; import jdk.vm.ci.meta.ProfilingInfo; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; @@ -59,10 +60,12 @@ public class BaseLayerMethod extends BaseLayerElement implements ResolvedJavaMet private final boolean isConstructor; private final int modifiers; private final boolean isSynthetic; + private final byte[] code; private final int codeSize; + private final IntrinsicMethod methodHandleIntrinsic; public BaseLayerMethod(int id, AnalysisType declaringClass, String name, boolean isVarArgs, ResolvedSignature signature, boolean canBeStaticallyBound, boolean isConstructor, - int modifiers, boolean isSynthetic, int codeSize, Annotation[] annotations) { + int modifiers, boolean isSynthetic, byte[] code, int codeSize, IntrinsicMethod methodHandleIntrinsic, Annotation[] annotations) { super(annotations); this.id = id; this.declaringClass = declaringClass.getWrapped(); @@ -73,16 +76,22 @@ public BaseLayerMethod(int id, AnalysisType declaringClass, String name, boolean this.isConstructor = isConstructor; this.modifiers = modifiers; this.isSynthetic = isSynthetic; + this.code = code; this.codeSize = codeSize; + this.methodHandleIntrinsic = methodHandleIntrinsic; } public int getBaseLayerId() { return id; } + public IntrinsicMethod getMethodHandleIntrinsic() { + return methodHandleIntrinsic; + } + @Override public byte[] getCode() { - throw GraalError.unimplemented("This method is incomplete and should not be used."); + return code; } @Override diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerType.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerType.java index 7be1054a7115..0e8bc2bcb6d1 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerType.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerType.java @@ -56,6 +56,7 @@ public class BaseLayerType extends BaseLayerElement implements ResolvedJavaType, private final boolean isInterface; private final boolean isEnum; private final boolean isInitialized; + private final boolean isInitializedAtBuildTime; private final boolean isLinked; private final String sourceFileName; private final ResolvedJavaType enclosingType; @@ -64,8 +65,9 @@ public class BaseLayerType extends BaseLayerElement implements ResolvedJavaType, private final ResolvedJavaType[] interfaces; private final ResolvedJavaType objectType; - public BaseLayerType(String name, int baseLayerId, int modifiers, boolean isInterface, boolean isEnum, boolean isInitialized, boolean isLinked, String sourceFileName, - ResolvedJavaType enclosingType, ResolvedJavaType componentType, ResolvedJavaType superClass, ResolvedJavaType[] interfaces, ResolvedJavaType objectType, Annotation[] annotations) { + public BaseLayerType(String name, int baseLayerId, int modifiers, boolean isInterface, boolean isEnum, boolean isInitialized, boolean initializedAtBuildTime, boolean isLinked, + String sourceFileName, ResolvedJavaType enclosingType, ResolvedJavaType componentType, ResolvedJavaType superClass, ResolvedJavaType[] interfaces, ResolvedJavaType objectType, + Annotation[] annotations) { super(annotations); this.name = name.substring(0, name.length() - 1) + BASE_LAYER_SUFFIX; this.baseLayerId = baseLayerId; @@ -73,6 +75,7 @@ public BaseLayerType(String name, int baseLayerId, int modifiers, boolean isInte this.isInterface = isInterface; this.isEnum = isEnum; this.isInitialized = isInitialized; + this.isInitializedAtBuildTime = initializedAtBuildTime; this.isLinked = isLinked; this.sourceFileName = sourceFileName; this.enclosingType = enclosingType; @@ -332,4 +335,8 @@ public ResolvedJavaType unwrapTowardsOriginalType() { public int getBaseLayerId() { return baseLayerId; } + + public boolean initializedAtBuildTime() { + return isInitializedAtBuildTime; + } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassValueFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassValueFeature.java index 7d50f29b8eb5..2360a208d2ba 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassValueFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ClassValueFeature.java @@ -113,6 +113,10 @@ public void duringAnalysis(DuringAnalysisAccess access) { throw VMError.shouldNotReachHere(ex); } + int numTypes = impl.getUniverse().getTypes().size(); mapsToRescan.forEach(impl::rescanObject); + if (numTypes != impl.getUniverse().getTypes().size()) { + access.requireAnalysisIteration(); + } } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HeapBreakdownProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HeapBreakdownProvider.java index 0377a0d7eeb7..864f7de01645 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HeapBreakdownProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HeapBreakdownProvider.java @@ -39,6 +39,7 @@ import com.oracle.svm.core.code.CodeInfoTable; import com.oracle.svm.core.config.ObjectLayout; import com.oracle.svm.core.configure.ConditionalRuntimeValue; +import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; import com.oracle.svm.core.jdk.Resources; import com.oracle.svm.core.jdk.resources.ResourceStorageEntryBase; import com.oracle.svm.core.reflect.RuntimeMetadataDecoder; @@ -147,21 +148,24 @@ protected void calculate(BeforeImageWriteAccessImpl access) { long metadataSize = objectLayout.getArraySize(JavaKind.Byte, metadataByteLength, true); addEntry(entries, byteArrayEntry, new HeapBreakdownEntry(BYTE_ARRAY_PREFIX, "reflection metadata", "#glossary-reflection-metadata"), metadataSize, 1); } - /* Extract byte[] for resources. */ - long resourcesByteArraySize = 0; - int resourcesByteArrayCount = 0; - for (ConditionalRuntimeValue resourceList : Resources.singleton().resources()) { - if (resourceList.getValueUnconditionally().hasData()) { - for (byte[] resource : resourceList.getValueUnconditionally().getData()) { - resourcesByteArraySize += objectLayout.getArraySize(JavaKind.Byte, resource.length, true); - resourcesByteArrayCount++; + ProgressReporter reporter = ProgressReporter.singleton(); + /* GR-57350: This condition can be removed once resources are adapted for Layered Images */ + if (!ImageLayerBuildingSupport.buildingExtensionLayer()) { + /* Extract byte[] for resources. */ + long resourcesByteArraySize = 0; + int resourcesByteArrayCount = 0; + for (ConditionalRuntimeValue resourceList : Resources.singleton().resources()) { + if (resourceList.getValueUnconditionally().hasData()) { + for (byte[] resource : resourceList.getValueUnconditionally().getData()) { + resourcesByteArraySize += objectLayout.getArraySize(JavaKind.Byte, resource.length, true); + resourcesByteArrayCount++; + } } } - } - ProgressReporter reporter = ProgressReporter.singleton(); - reporter.recordJsonMetric(ImageDetailKey.RESOURCE_SIZE_BYTES, resourcesByteArraySize); - if (resourcesByteArraySize > 0) { - addEntry(entries, byteArrayEntry, new HeapBreakdownEntry(BYTE_ARRAY_PREFIX, "embedded resources", "#glossary-embedded-resources"), resourcesByteArraySize, resourcesByteArrayCount); + reporter.recordJsonMetric(ImageDetailKey.RESOURCE_SIZE_BYTES, resourcesByteArraySize); + if (resourcesByteArraySize > 0) { + addEntry(entries, byteArrayEntry, new HeapBreakdownEntry(BYTE_ARRAY_PREFIX, "embedded resources", "#glossary-embedded-resources"), resourcesByteArraySize, resourcesByteArrayCount); + } } /* Extract byte[] for graph encodings. */ if (graphEncodingByteLength >= 0) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index 36a4e61e99dc..9998db7c12c4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -228,6 +228,10 @@ public JavaConstant readValue(AnalysisField field, JavaConstant receiver, boolea } } + if (receiver instanceof ImageHeapInstance imageHeapInstance && imageHeapInstance.isInBaseLayer() && imageHeapInstance.nullFieldValues()) { + return null; + } + VMError.guarantee(receiver == null || receiver instanceof ImageHeapConstant, "Expected ImageHeapConstant, found: %s", receiver); JavaConstant value = null; if (returnSimulatedValues) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisMethodHandleAccessProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisMethodHandleAccessProvider.java index ba9f242ee577..a86090a73088 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisMethodHandleAccessProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisMethodHandleAccessProvider.java @@ -30,6 +30,7 @@ import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; import com.oracle.graal.pointsto.meta.AnalysisUniverse; +import com.oracle.graal.pointsto.meta.BaseLayerMethod; import com.oracle.graal.pointsto.util.GraalAccess; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; @@ -53,6 +54,9 @@ final class AnalysisMethodHandleAccessProvider implements MethodHandleAccessProv @Override public IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method) { ResolvedJavaMethod original = OriginalMethodProvider.getOriginalMethod(method); + if (original instanceof BaseLayerMethod baseLayerMethod) { + return baseLayerMethod.getMethodHandleIntrinsic(); + } if (original == null) { return null; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java index 4109dd5787c6..ade3c618f7a8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java @@ -39,6 +39,7 @@ import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.meta.BaseLayerType; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.svm.core.BuildPhaseProvider; import com.oracle.svm.core.classinitialization.ClassInitializationInfo; @@ -94,7 +95,13 @@ public void initializeMetaData(ImageHeapScanner heapScanner, AnalysisType type) Class javaClass = type.getJavaClass(); DynamicHub hub = hostVM.dynamicHub(type); - registerPackage(heapScanner, javaClass, hub); + /* + * Since the javaClass is java.lang.Object for BaseLayerTypes, the java.lang package would + * be registered in the wrong class loader. + */ + if (!(type.getWrapped() instanceof BaseLayerType)) { + registerPackage(heapScanner, javaClass, hub); + } boolean rescan = true; /* diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationSupport.java index 9a2f6ec9e276..57a1e64d746d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationSupport.java @@ -50,6 +50,8 @@ import org.graalvm.nativeimage.impl.clinit.ClassInitializationTracking; import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.meta.BaseLayerType; import com.oracle.graal.pointsto.reports.ReportUtils; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.option.AccumulatingLocatableMultiOptionValue; @@ -164,6 +166,9 @@ Set> classesWithKind(InitKind kind) { * arbitrary user code. */ public boolean maybeInitializeAtBuildTime(ResolvedJavaType type) { + if (type instanceof AnalysisType analysisType && analysisType.getWrapped() instanceof BaseLayerType baseLayerType) { + return baseLayerType.initializedAtBuildTime(); + } return maybeInitializeAtBuildTime(OriginalClassProvider.getJavaClass(type)); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerSupport.java index 86c6dfe289b6..06fb72a952f8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerSupport.java @@ -472,6 +472,10 @@ private StructuredGraph decodeGraph(SimulateClassInitializerClusterMember cluste .recordInlinedMethods(analysisParsedGraph.getEncodedGraph().isRecordingInlinedMethods()) .build(); + if (classInitializer.isInBaseLayer()) { + throw SimulateClassInitializerAbortException.doAbort(clusterMember, result, "The class initializer was already simulated in the base layer."); + } + try (var scope = debug.scope("SimulateClassInitializerGraphDecoder", result)) { var decoder = createGraphDecoder(clusterMember, bb, result); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java index 7b6c3de537d7..52adf8b68dae 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java @@ -637,7 +637,7 @@ private void parseAheadOfTimeCompiledMethods() { */ continue; } - if (layeredForceCompilation) { + if (layeredForceCompilation || layeredForceCompilation(hMethod)) { // when layered force compilation is enabled we try to parse all graphs if (method.wrapped.getAnalyzedGraph() != null) { ensureParsed(method, null, new EntryPointReason()); @@ -925,7 +925,7 @@ public void scheduleEntryPoints() { continue; } - if (layeredForceCompilation) { + if (layeredForceCompilation || layeredForceCompilation(hMethod)) { /* * when layeredForceCompilation is enabled we try to parse all graphs. */ @@ -951,6 +951,16 @@ public void scheduleEntryPoints() { } } + private static boolean layeredForceCompilation(HostedMethod hMethod) { + /* + * If a method from a base layer interface is not compiled in a prior layer but is in the + * vtable of a type from a new layer, the method needs to be compiled as there would be a + * missing symbol otherwise. + */ + return hMethod.wrapped.isInBaseLayer() && !hMethod.isCompiledInPriorLayer() && hMethod.getDeclaringClass().isInterface() && + Arrays.stream(hMethod.getDeclaringClass().getSubTypes()).anyMatch(t -> !t.getWrapped().isInBaseLayer() && hMethod.isInVirtualMethodTable(t)); + } + public void scheduleDeoptTargets() { for (HostedMethod method : universe.getMethods()) { HostedMethod deoptTarget = method.getMultiMethod(DEOPT_TARGET_METHOD); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerSnapshotUtil.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerSnapshotUtil.java index 571dbcd6387d..ffc17a12b6f6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerSnapshotUtil.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerSnapshotUtil.java @@ -226,8 +226,8 @@ public GraphEncoder getGraphEncoder(ImageLayerWriter imageLayerWriter) { } @Override - public GraphDecoder getGraphDecoder(ImageLayerLoader imageLayerLoader, SnippetReflectionProvider snippetReflectionProvider) { - return new SVMGraphDecoder(EncodedGraph.class.getClassLoader(), (SVMImageLayerLoader) imageLayerLoader, snippetReflectionProvider); + public GraphDecoder getGraphDecoder(ImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { + return new SVMGraphDecoder(EncodedGraph.class.getClassLoader(), (SVMImageLayerLoader) imageLayerLoader, analysisMethod, snippetReflectionProvider); } public static class SVMGraphEncoder extends GraphEncoder { @@ -245,8 +245,8 @@ public SVMGraphEncoder(List externalValues, ImageLayerWriter imageLayerWr public static class SVMGraphDecoder extends GraphDecoder { @SuppressWarnings("this-escape") - public SVMGraphDecoder(ClassLoader classLoader, SVMImageLayerLoader svmImageLayerLoader, SnippetReflectionProvider snippetReflectionProvider) { - super(classLoader, svmImageLayerLoader); + public SVMGraphDecoder(ClassLoader classLoader, SVMImageLayerLoader svmImageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { + super(classLoader, svmImageLayerLoader, analysisMethod); addBuiltin(new HostedTypeBuiltIn(svmImageLayerLoader)); addBuiltin(new HostedMethodBuiltIn(svmImageLayerLoader)); addBuiltin(new HostedOptionValuesBuiltIn()); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java index 40d246777f57..7dc1ee7f6327 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java @@ -29,6 +29,7 @@ import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.HUB_IDENTITY_HASH_CODE_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IMAGE_SINGLETON_KEYS; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IMAGE_SINGLETON_OBJECTS; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INITIALIZED_AT_BUILD_TIME_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.LOCATION_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.METHOD_POINTER_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.OBJECT_OFFSET_TAG; @@ -63,6 +64,7 @@ import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.SVMHost; +import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.image.NativeImageHeap; import com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo; import com.oracle.svm.hosted.lambda.LambdaSubstitutionType; @@ -113,6 +115,8 @@ protected void persistType(AnalysisType type, EconomicMap typeMa DynamicHub hub = svmHost.dynamicHub(type); typeMap.put(HUB_IDENTITY_HASH_CODE_TAG, System.identityHashCode(hub)); + typeMap.put(IS_INITIALIZED_AT_BUILD_TIME_TAG, ClassInitializationSupport.singleton().maybeInitializeAtBuildTime(type)); + super.persistType(type, typeMap); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java index fbc2f82d0b31..b5acf4afe2fd 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java @@ -429,9 +429,13 @@ public void registerHeapMemberName(Member memberName) { @Override public void duringAnalysis(DuringAnalysisAccess a) { DuringAnalysisAccessImpl access = (DuringAnalysisAccessImpl) a; + int numTypes = access.getUniverse().getTypes().size(); access.rescanRoot(typedAccessors); access.rescanRoot(typedCollectors); access.rescanObject(runtimeMethodTypeInternTable); + if (numTypes != access.getUniverse().getTypes().size()) { + access.requireAnalysisIteration(); + } } private static void scanBoundMethodHandle(DuringAnalysisAccess a, Class bmhSubtype) {