From 62f5ab0f4da5e86dd3194499ebf9ada999130197 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Fri, 20 Dec 2024 07:55:15 +0100 Subject: [PATCH] Refactor ImageLayerWriter/Loader --- substratevm/mx.substratevm/mx_substratevm.py | 2 +- .../pointsto/standalone/PointsToAnalyzer.java | 12 - .../heap/StandaloneImageHeapScanner.java | 2 +- .../graal/pointsto/api/ImageLayerLoader.java | 132 ++ .../ImageLayerWriter.java} | 22 +- .../pointsto/heap/ImageHeapInstance.java | 17 +- .../pointsto/heap/ImageHeapObjectArray.java | 4 +- .../heap/ImageHeapPrimitiveArray.java | 2 +- .../graal/pointsto/heap/ImageHeapScanner.java | 3 +- .../pointsto/heap/ImageLayerSnapshotUtil.java | 307 ----- .../graal/pointsto/heap/ImageLayerWriter.java | 729 ----------- .../pointsto/heap/ImageLayerWriterHelper.java | 52 - .../graal/pointsto/meta/AnalysisMethod.java | 2 +- .../graal/pointsto/meta/AnalysisUniverse.java | 8 +- .../ImageSingletonLoader.java | 2 - .../SharedLayerSnapshotCapnProtoSchema.capnp | 2 +- .../svm/hosted/HostedConfiguration.java | 15 +- .../hosted/ImageSingletonsSupportImpl.java | 8 +- .../svm/hosted/NativeImageGenerator.java | 30 +- .../src/com/oracle/svm/hosted/SVMHost.java | 15 +- .../analysis/NativeImagePointsToAnalysis.java | 3 +- .../oracle/svm/hosted/code/CompileQueue.java | 6 +- .../svm/hosted/heap/SVMImageLayerLoader.java | 475 ------- .../heap/SVMImageLayerLoaderHelper.java | 207 --- .../svm/hosted/heap/SVMImageLayerWriter.java | 506 -------- .../heap/SVMImageLayerWriterHelper.java | 123 -- .../svm/hosted/image/NativeImageHeap.java | 4 +- .../CrossLayerConstantRegistryFeature.java | 5 +- .../HostedImageLayerBuildingSupport.java | 116 +- .../LayeredDispatchTableSupport.java | 6 +- .../imagelayer/LoadImageSingletonFeature.java | 3 +- .../imagelayer/LoadLayerArchiveSupport.java | 5 +- .../imagelayer/SVMImageLayerLoader.java} | 1097 ++++++++++------ .../SVMImageLayerSingletonLoader.java | 165 +++ .../SVMImageLayerSnapshotUtil.java | 316 ++++- .../imagelayer/SVMImageLayerWriter.java | 1127 +++++++++++++++++ ...redLayerSnapshotCapnProtoSchemaHolder.java | 322 ++--- .../oracle/svm/hosted/meta/HostedField.java | 5 +- .../svm/hosted/meta/UniverseBuilder.java | 4 +- 39 files changed, 2722 insertions(+), 3139 deletions(-) create mode 100644 substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/ImageLayerLoader.java rename substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/{heap/ImageLayerLoaderHelper.java => api/ImageLayerWriter.java} (63%) delete mode 100644 substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java delete mode 100644 substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java delete mode 100644 substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriterHelper.java delete mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoader.java delete mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoaderHelper.java delete mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java delete mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriterHelper.java rename substratevm/src/{com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java => com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java} (64%) create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerSingletonLoader.java rename substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/{heap => imagelayer}/SVMImageLayerSnapshotUtil.java (64%) create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java rename substratevm/src/{com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap => com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer}/SharedLayerSnapshotCapnProtoSchemaHolder.java (89%) diff --git a/substratevm/mx.substratevm/mx_substratevm.py b/substratevm/mx.substratevm/mx_substratevm.py index 9c24fef71581..6f7238f60a35 100644 --- a/substratevm/mx.substratevm/mx_substratevm.py +++ b/substratevm/mx.substratevm/mx_substratevm.py @@ -2478,7 +2478,7 @@ def capnp_compile(args): if capnpcjava_home is None or not exists(capnpcjava_home + '/capnpc-java'): mx.abort('Clone and build capnproto/capnproto-java from GitHub and point CAPNPROTOJAVA_HOME to its path.') srcdir = 'src/com.oracle.svm.hosted/resources/' - outdir = 'src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/' + outdir = 'src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/' command = ['capnp', 'compile', '--import-path=' + capnpcjava_home + '/compiler/src/main/schema/', '--output=' + capnpcjava_home + '/capnpc-java:' + outdir, diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java index ffe6248157bf..515a90e107fb 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/PointsToAnalyzer.java @@ -48,9 +48,6 @@ import com.oracle.graal.pointsto.heap.HeapSnapshotVerifier; import com.oracle.graal.pointsto.heap.HostedValuesProvider; import com.oracle.graal.pointsto.heap.ImageHeap; -import com.oracle.graal.pointsto.heap.ImageLayerLoader; -import com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil; -import com.oracle.graal.pointsto.heap.ImageLayerWriter; import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMetaAccessExtensionProvider; @@ -163,18 +160,9 @@ private PointsToAnalyzer(String mainEntryClass, OptionValues options) { aUniverse.setBigBang(bigbang); ImageHeap heap = new ImageHeap(); HostedValuesProvider hostedValuesProvider = new HostedValuesProvider(aMetaAccess, aUniverse); - ImageLayerSnapshotUtil imageLayerSnapshotUtil = new ImageLayerSnapshotUtil(false); - ImageLayerLoader imageLayerLoader = new ImageLayerLoader(); - imageLayerLoader.setImageLayerSnapshotUtil(imageLayerSnapshotUtil); - imageLayerLoader.setUniverse(aUniverse); - aUniverse.setImageLayerLoader(imageLayerLoader); StandaloneImageHeapScanner heapScanner = new StandaloneImageHeapScanner(bigbang, heap, aMetaAccess, snippetReflection, aConstantReflection, new AnalysisObjectScanningObserver(bigbang), analysisClassLoader, hostedValuesProvider); aUniverse.setHeapScanner(heapScanner); - imageLayerLoader.executeHeapScannerTasks(); - ImageLayerWriter imageLayerWriter = new ImageLayerWriter(true, true); - imageLayerWriter.setImageLayerSnapshotUtil(imageLayerSnapshotUtil); - imageLayerWriter.setImageHeap(heap); HeapSnapshotVerifier heapVerifier = new StandaloneHeapSnapshotVerifier(bigbang, heap, heapScanner); aUniverse.setHeapVerifier(heapVerifier); /* Register already created types as assignable. */ diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/heap/StandaloneImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/heap/StandaloneImageHeapScanner.java index 4e1674a84469..aa8fc1affaf2 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/heap/StandaloneImageHeapScanner.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/heap/StandaloneImageHeapScanner.java @@ -68,7 +68,7 @@ protected Class getClass(String className) { } @Override - protected ValueSupplier readHostedFieldValue(AnalysisField field, JavaConstant receiver) { + public ValueSupplier readHostedFieldValue(AnalysisField field, JavaConstant receiver) { ValueSupplier ret = super.readHostedFieldValue(field, receiver); if (ret.get() == null && field.isStatic()) { ResolvedJavaField wrappedField = field.getWrapped(); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/ImageLayerLoader.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/ImageLayerLoader.java new file mode 100644 index 000000000000..17b71f5515f9 --- /dev/null +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/ImageLayerLoader.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.pointsto.api; + +import java.util.Set; + +import com.oracle.graal.pointsto.flow.AnalysisParsedGraph; +import com.oracle.graal.pointsto.heap.ImageHeapConstant; +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.util.AnalysisError; + +import jdk.vm.ci.meta.JavaConstant; + +public class ImageLayerLoader { + /** + * Returns the type id of the given type in the base layer if it exists. This makes the link + * between the base layer and the extension layer as the id is used to determine which constant + * should be linked to this type. + */ + @SuppressWarnings("unused") + public int lookupHostedTypeInBaseLayer(AnalysisType type) { + throw AnalysisError.shouldNotReachHere("This method should not be called"); + } + + @SuppressWarnings("unused") + public void initializeBaseLayerType(AnalysisType type) { + throw AnalysisError.shouldNotReachHere("This method should not be called"); + } + + /** + * Returns the method id of the given method in the base layer if it exists. This makes the link + * between the base layer and the extension layer as the id is used to determine the method used + * in RelocatableConstants. + */ + @SuppressWarnings("unused") + public int lookupHostedMethodInBaseLayer(AnalysisMethod analysisMethod) { + throw AnalysisError.shouldNotReachHere("This method should not be called"); + } + + @SuppressWarnings("unused") + public void addBaseLayerMethod(AnalysisMethod analysisMethod) { + throw AnalysisError.shouldNotReachHere("This method should not be called"); + } + + /** + * We save analysis parsed graphs for methods considered + * {@link AnalysisMethod#isTrackedAcrossLayers()}. + */ + @SuppressWarnings("unused") + public boolean hasAnalysisParsedGraph(AnalysisMethod analysisMethod) { + throw AnalysisError.shouldNotReachHere("This method should not be called"); + } + + @SuppressWarnings("unused") + public AnalysisParsedGraph getAnalysisParsedGraph(AnalysisMethod analysisMethod) { + throw AnalysisError.shouldNotReachHere("This method should not be called"); + } + + @SuppressWarnings("unused") + public void loadPriorStrengthenedGraphAnalysisElements(AnalysisMethod analysisMethod) { + throw AnalysisError.shouldNotReachHere("This method should not be called"); + } + + /** + * Returns the field id of the given field in the base layer if it exists. This makes the link + * between the base layer and the extension image as the id allows to set the flags of the + * fields in the extension image. + */ + @SuppressWarnings("unused") + public int lookupHostedFieldInBaseLayer(AnalysisField analysisField) { + throw AnalysisError.shouldNotReachHere("This method should not be called"); + } + + @SuppressWarnings("unused") + public void addBaseLayerField(AnalysisField analysisField) { + throw AnalysisError.shouldNotReachHere("This method should not be called"); + } + + @SuppressWarnings("unused") + public void initializeBaseLayerField(AnalysisField analysisField) { + throw AnalysisError.shouldNotReachHere("This method should not be called"); + } + + @SuppressWarnings("unused") + public boolean hasValueForConstant(JavaConstant javaConstant) { + throw AnalysisError.shouldNotReachHere("This method should not be called"); + } + + @SuppressWarnings("unused") + public ImageHeapConstant getValueForConstant(JavaConstant javaConstant) { + throw AnalysisError.shouldNotReachHere("This method should not be called"); + } + + @SuppressWarnings("unused") + public Set getRelinkedFields(AnalysisType type) { + throw AnalysisError.shouldNotReachHere("This method should not be called"); + } + + @SuppressWarnings("unused") + public boolean hasDynamicHubIdentityHashCode(int tid) { + throw AnalysisError.shouldNotReachHere("This method should not be called"); + } + + @SuppressWarnings("unused") + public int getDynamicHubIdentityHashCode(int tid) { + throw AnalysisError.shouldNotReachHere("This method should not be called"); + } +} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoaderHelper.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/ImageLayerWriter.java similarity index 63% rename from substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoaderHelper.java rename to substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/ImageLayerWriter.java index 67f577b4f985..63898e56abc4 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoaderHelper.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/ImageLayerWriter.java @@ -22,25 +22,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.graal.pointsto.heap; +package com.oracle.graal.pointsto.api; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.util.AnalysisError; -public class ImageLayerLoaderHelper { - protected ImageLayerLoader imageLayerLoader; - - public ImageLayerLoaderHelper(ImageLayerLoader imageLayerLoader) { - this.imageLayerLoader = imageLayerLoader; - } - - @SuppressWarnings("unused") - protected boolean loadType(PersistedAnalysisType.Reader typeData, int tid) { - return false; - } +public class ImageLayerWriter { @SuppressWarnings("unused") - protected boolean loadMethod(PersistedAnalysisMethod.Reader methodData, int mid) { - return false; + public void onTrackedAcrossLayer(AnalysisMethod method, Object reason) { + throw AnalysisError.shouldNotReachHere("This method should not be called"); } } 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 ce2a2eac840f..a4b777b90d17 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 @@ -81,7 +81,7 @@ private InstanceData(AnalysisType type, JavaConstant hostedObject, Object[] fiel this(type, hostedObject, -1, -1); } - ImageHeapInstance(AnalysisType type, JavaConstant hostedObject, int identityHashCode, int id) { + public ImageHeapInstance(AnalysisType type, JavaConstant hostedObject, int identityHashCode, int id) { super(new InstanceData(type, hostedObject, null, identityHashCode, id), false); } @@ -98,7 +98,7 @@ public InstanceData getConstantData() { return (InstanceData) super.getConstantData(); } - void setFieldValues(Object[] fieldValues) { + public void setFieldValues(Object[] fieldValues) { boolean success = valuesHandle.compareAndSet(constantData, null, fieldValues); AnalysisError.guarantee(success, "Unexpected field values reference for constant %s", this); } @@ -149,7 +149,18 @@ public Object getFieldValue(AnalysisField field) { /* Base layer constants that are not relinked might not have field positions computed */ field.getType().getInstanceFields(true); } - return arrayHandle.getVolatile(getFieldValues(), field.getPosition()); + return getFieldValue(field.getPosition()); + } + + public Object getFieldValue(int fieldPosition) { + return arrayHandle.getVolatile(getFieldValues(), fieldPosition); + } + + public int getFieldValuesSize() { + if (isReaderInstalled()) { + return getConstantData().fieldValues.length; + } + return 0; } /** diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java index 108555de0b9f..311085fc1889 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapObjectArray.java @@ -71,7 +71,7 @@ private ObjectArrayData(AnalysisType type, JavaConstant hostedObject, Object[] a this(type, hostedObject, length, -1, -1); } - ImageHeapObjectArray(AnalysisType type, JavaConstant hostedObject, int length, int identityHashCode, int id) { + public ImageHeapObjectArray(AnalysisType type, JavaConstant hostedObject, int length, int identityHashCode, int id) { super(new ObjectArrayData(type, hostedObject, null, length, identityHashCode, id), false); } @@ -92,7 +92,7 @@ public ObjectArrayData getConstantData() { return (ObjectArrayData) super.getConstantData(); } - void setElementValues(Object[] elementValues) { + public void setElementValues(Object[] elementValues) { boolean success = elementsHandle.compareAndSet(constantData, null, elementValues); AnalysisError.guarantee(success, "Unexpected field values reference for constant %s", this); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapPrimitiveArray.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapPrimitiveArray.java index e664bb1c10e9..e021ca04fa24 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapPrimitiveArray.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapPrimitiveArray.java @@ -60,7 +60,7 @@ private PrimitiveArrayData(AnalysisType type, JavaConstant hostedObject, Object this(type, hostedObject, array, length, -1, -1); } - ImageHeapPrimitiveArray(AnalysisType type, JavaConstant hostedObject, Object array, int length, int identityHashCode, int id) { + public ImageHeapPrimitiveArray(AnalysisType type, JavaConstant hostedObject, Object array, int length, int identityHashCode, int id) { super(new PrimitiveArrayData(type, hostedObject, /* We need a clone of the hosted array so that we have a stable snapshot. */ getClone(type.getComponentType().getJavaKind(), array), 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 2edafcb27ebc..aba8d82bc991 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 @@ -44,6 +44,7 @@ import com.oracle.graal.pointsto.ObjectScanner.ScanReason; import com.oracle.graal.pointsto.ObjectScanningObserver; import com.oracle.graal.pointsto.api.HostVM; +import com.oracle.graal.pointsto.api.ImageLayerLoader; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.heap.HeapSnapshotVerifier.ScanningObserver; import com.oracle.graal.pointsto.heap.value.ValueSupplier; @@ -830,7 +831,7 @@ protected void rescanEconomicMap(EconomicMap object) { } } - void doScan(JavaConstant constant) { + public void doScan(JavaConstant constant) { doScan(constant, OtherReason.RESCAN); } 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 deleted file mode 100644 index 26a84079e363..000000000000 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.pointsto.heap; - -import java.io.IOException; -import java.lang.reflect.Executable; -import java.lang.reflect.Field; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; -import com.oracle.graal.pointsto.meta.AnalysisField; -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.PointsToAnalysisField; -import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; -import com.oracle.graal.pointsto.meta.PointsToAnalysisType; -import com.oracle.graal.pointsto.util.AnalysisError; - -import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.nodes.EncodedGraph; -import jdk.graal.compiler.nodes.FieldLocationIdentity; -import jdk.graal.compiler.util.ObjectCopier; -import jdk.graal.compiler.util.ObjectCopierInputStream; -import jdk.graal.compiler.util.ObjectCopierOutputStream; - -public class ImageLayerSnapshotUtil { - public static final String FILE_NAME_PREFIX = "layer-snapshot-"; - public static final String FILE_EXTENSION = ".lsb"; - public static final String GRAPHS_FILE_NAME_PREFIX = "layer-snapshot-graphs-"; - public static final String GRAPHS_FILE_EXTENSION = ".big"; - - public static final String CONSTRUCTOR_NAME = ""; - public static final String CLASS_INIT_NAME = ""; - - public static final String PERSISTED = "persisted"; - - public static final int UNDEFINED_CONSTANT_ID = -1; - public static final int UNDEFINED_FIELD_INDEX = -1; - - private static final String TRACKED_REASON = "reachable from a graph"; - - protected final List externalValueFields; - /** This needs to be initialized after analysis, as some fields are not available before. */ - protected Map externalValues; - - public ImageLayerSnapshotUtil(boolean computeExternalValues) { - if (computeExternalValues) { - try { - this.externalValueFields = ObjectCopier.getExternalValueFields(); - } catch (IOException e) { - throw AnalysisError.shouldNotReachHere("Unexpected exception when creating external value fields list", e); - } - } else { - this.externalValueFields = List.of(); - } - } - - /** - * Compute and cache the final {@code externalValues} map in - * {@link ImageLayerSnapshotUtil#externalValues} to avoid computing it for each graph. - *

- * A single {@code ObjectCopier.Encoder} instance could alternatively be used for all graphs, - * but it would then be impossible to process multiple graphs concurrently. - */ - public void initializeExternalValues() { - assert externalValues == null : "The external values should be computed only once."; - externalValues = ObjectCopier.Encoder.gatherExternalValues(externalValueFields); - } - - public static String snapshotFileName(String imageName) { - return FILE_NAME_PREFIX + imageName + FILE_EXTENSION; - } - - public static String snapshotGraphsFileName(String imageName) { - return GRAPHS_FILE_NAME_PREFIX + imageName + GRAPHS_FILE_EXTENSION; - } - - public String getTypeDescriptor(AnalysisType type) { - String javaName = type.toJavaName(true); - return addModuleName(javaName, type.getJavaClass().getModule().getName()); - } - - public String getMethodDescriptor(AnalysisMethod method) { - AnalysisType declaringClass = method.getDeclaringClass(); - Executable originalMethod = OriginalMethodProvider.getJavaMethod(method); - String moduleName = declaringClass.getJavaClass().getModule().getName(); - if (originalMethod != null) { - return addModuleName(originalMethod.toString(), moduleName); - } - return addModuleName(getQualifiedName(method), moduleName); - } - - protected static String addModuleName(String elementName, String moduleName) { - return moduleName + ":" + elementName; - } - - protected static String getQualifiedName(AnalysisMethod method) { - return method.getSignature().getReturnType().toJavaName(true) + " " + method.getQualifiedName(); - } - - /** - * Get all the field indexes that should be relinked using the hosted value of a constant from - * the given type. - */ - @SuppressWarnings("unused") - public Set getRelinkedFields(AnalysisType type, AnalysisMetaAccess metaAccess) { - return Set.of(); - } - - public GraphEncoder getGraphEncoder(ImageLayerWriter imageLayerWriter) { - return new GraphEncoder(externalValues, imageLayerWriter); - } - - @SuppressWarnings("unused") - public GraphDecoder getGraphAnalysisElementsDecoder(ImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { - return new GraphDecoder(EncodedGraph.class.getClassLoader(), imageLayerLoader, analysisMethod); - } - - @SuppressWarnings("unused") - public GraphDecoder getGraphDecoder(ImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { - return new GraphDecoder(EncodedGraph.class.getClassLoader(), imageLayerLoader, analysisMethod); - } - - public static class GraphEncoder extends ObjectCopier.Encoder { - @SuppressWarnings("this-escape") - public GraphEncoder(Map externalValues, ImageLayerWriter imageLayerWriter) { - super(externalValues); - addBuiltin(new ImageHeapConstantBuiltIn(imageLayerWriter, null)); - addBuiltin(new AnalysisTypeBuiltIn(null)); - addBuiltin(new AnalysisMethodBuiltIn(null, null)); - addBuiltin(new AnalysisFieldBuiltIn(null)); - addBuiltin(new FieldLocationIdentityBuiltIn(null)); - } - } - - public static class GraphDecoder extends ObjectCopier.Decoder { - private final ImageLayerLoader imageLayerLoader; - - @SuppressWarnings("this-escape") - public GraphDecoder(ClassLoader classLoader, ImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod) { - super(classLoader); - this.imageLayerLoader = imageLayerLoader; - addBuiltin(new ImageHeapConstantBuiltIn(null, imageLayerLoader)); - addBuiltin(new AnalysisTypeBuiltIn(imageLayerLoader)); - addBuiltin(new AnalysisMethodBuiltIn(imageLayerLoader, analysisMethod)); - addBuiltin(new AnalysisFieldBuiltIn(imageLayerLoader)); - addBuiltin(new FieldLocationIdentityBuiltIn(imageLayerLoader)); - } - - @Override - public Class loadClass(String className) { - return imageLayerLoader.lookupClass(false, className); - } - } - - public static class ImageHeapConstantBuiltIn extends ObjectCopier.Builtin { - private final ImageLayerWriter imageLayerWriter; - private final ImageLayerLoader imageLayerLoader; - - protected ImageHeapConstantBuiltIn(ImageLayerWriter imageLayerWriter, ImageLayerLoader imageLayerLoader) { - super(ImageHeapConstant.class, ImageHeapInstance.class, ImageHeapObjectArray.class, ImageHeapPrimitiveArray.class); - this.imageLayerWriter = imageLayerWriter; - this.imageLayerLoader = imageLayerLoader; - } - - @Override - public void encode(ObjectCopier.Encoder encoder, ObjectCopierOutputStream stream, Object obj) throws IOException { - ImageHeapConstant imageHeapConstant = (ImageHeapConstant) obj; - imageLayerWriter.ensureConstantPersisted(imageHeapConstant); - stream.writePackedUnsignedInt(imageHeapConstant.getConstantData().id); - } - - @Override - protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, ObjectCopierInputStream stream) throws IOException { - int id = stream.readPackedUnsignedInt(); - return imageLayerLoader.getOrCreateConstant(id); - } - } - - public static class AnalysisTypeBuiltIn extends ObjectCopier.Builtin { - private final ImageLayerLoader imageLayerLoader; - - protected AnalysisTypeBuiltIn(ImageLayerLoader imageLayerLoader) { - super(AnalysisType.class, PointsToAnalysisType.class); - this.imageLayerLoader = imageLayerLoader; - } - - @Override - public void encode(ObjectCopier.Encoder encoder, ObjectCopierOutputStream stream, Object obj) throws IOException { - AnalysisType type = (AnalysisType) obj; - type.registerAsTrackedAcrossLayers(TRACKED_REASON); - stream.writePackedUnsignedInt(type.getId()); - } - - @Override - protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, ObjectCopierInputStream stream) throws IOException { - int id = stream.readPackedUnsignedInt(); - return imageLayerLoader.getAnalysisTypeForBaseLayerId(id); - } - } - - public static class AnalysisMethodBuiltIn extends ObjectCopier.Builtin { - private final ImageLayerLoader imageLayerLoader; - private final AnalysisMethod analysisMethod; - - protected AnalysisMethodBuiltIn(ImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod) { - super(AnalysisMethod.class, PointsToAnalysisMethod.class); - this.imageLayerLoader = imageLayerLoader; - this.analysisMethod = analysisMethod; - } - - @Override - public void encode(ObjectCopier.Encoder encoder, ObjectCopierOutputStream stream, Object obj) throws IOException { - AnalysisMethod method = (AnalysisMethod) obj; - method.registerAsTrackedAcrossLayers(TRACKED_REASON); - stream.writePackedUnsignedInt(method.getId()); - } - - @Override - protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, ObjectCopierInputStream stream) throws IOException { - int id = stream.readPackedUnsignedInt(); - if (id == analysisMethod.getId()) { - return analysisMethod; - } - return imageLayerLoader.getAnalysisMethodForBaseLayerId(id); - } - } - - public static class AnalysisFieldBuiltIn extends ObjectCopier.Builtin { - private final ImageLayerLoader imageLayerLoader; - - protected AnalysisFieldBuiltIn(ImageLayerLoader imageLayerLoader) { - super(AnalysisField.class, PointsToAnalysisField.class); - this.imageLayerLoader = imageLayerLoader; - } - - @Override - public void encode(ObjectCopier.Encoder encoder, ObjectCopierOutputStream stream, Object obj) throws IOException { - AnalysisField field = (AnalysisField) obj; - int id = encodeField(field); - stream.writePackedUnsignedInt(id); - } - - @Override - protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, ObjectCopierInputStream stream) throws IOException { - int id = stream.readPackedUnsignedInt(); - return decodeField(imageLayerLoader, id); - } - } - - public static class FieldLocationIdentityBuiltIn extends ObjectCopier.Builtin { - private final ImageLayerLoader imageLayerLoader; - - protected FieldLocationIdentityBuiltIn(ImageLayerLoader imageLayerLoader) { - super(FieldLocationIdentity.class); - this.imageLayerLoader = imageLayerLoader; - } - - @Override - public void encode(ObjectCopier.Encoder encoder, ObjectCopierOutputStream stream, Object obj) throws IOException { - FieldLocationIdentity fieldLocationIdentity = (FieldLocationIdentity) obj; - AnalysisField field = (AnalysisField) fieldLocationIdentity.getField(); - int id = encodeField(field); - stream.writePackedUnsignedInt(id); - } - - @Override - protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, ObjectCopierInputStream stream) throws IOException { - int id = stream.readPackedUnsignedInt(); - return new FieldLocationIdentity(decodeField(imageLayerLoader, id)); - } - } - - private static int encodeField(AnalysisField field) { - field.registerAsTrackedAcrossLayers(TRACKED_REASON); - return field.getId(); - } - - private static AnalysisField decodeField(ImageLayerLoader imageLayerLoader, int id) { - return imageLayerLoader.getAnalysisFieldForBaseLayerId(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 deleted file mode 100644 index 72a84ca9b28d..000000000000 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java +++ /dev/null @@ -1,729 +0,0 @@ -/* - * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.pointsto.heap; - -import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.UNDEFINED_CONSTANT_ID; -import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.UNDEFINED_FIELD_INDEX; - -import java.io.IOException; -import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Array; -import java.lang.reflect.Executable; -import java.lang.reflect.Field; -import java.nio.ByteBuffer; -import java.nio.channels.Channels; -import java.nio.channels.FileChannel; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Comparator; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.BiConsumer; -import java.util.function.IntFunction; -import java.util.function.ObjIntConsumer; -import java.util.function.Supplier; -import java.util.stream.IntStream; -import java.util.stream.Stream; - -import org.capnproto.ListBuilder; -import org.capnproto.MessageBuilder; -import org.capnproto.PrimitiveList; -import org.capnproto.Serialize; -import org.capnproto.StructBuilder; -import org.capnproto.StructList; -import org.capnproto.Text; -import org.capnproto.TextList; -import org.capnproto.Void; -import org.graalvm.nativeimage.AnnotationAccess; - -import com.oracle.graal.pointsto.BigBang; -import com.oracle.graal.pointsto.flow.AnalysisParsedGraph; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisField; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant.Object.Relinking.EnumConstant; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant.Object.Relinking.StringConstant; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.SharedLayerSnapshot; -import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; -import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.meta.AnalysisUniverse; -import com.oracle.graal.pointsto.util.AnalysisError; -import com.oracle.graal.pointsto.util.AnalysisFuture; -import com.oracle.svm.util.FileDumpingUtil; - -import jdk.graal.compiler.core.common.NumUtil; -import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.java.LambdaUtils; -import jdk.graal.compiler.nodes.EncodedGraph; -import jdk.graal.compiler.nodes.spi.IdentityHashCodeProvider; -import jdk.graal.compiler.util.ObjectCopier; -import jdk.vm.ci.meta.ConstantReflectionProvider; -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; - -public class ImageLayerWriter { - protected ImageLayerSnapshotUtil imageLayerSnapshotUtil; - private ImageLayerWriterHelper imageLayerWriterHelper; - private ImageHeap imageHeap; - protected AnalysisUniverse aUniverse; - private IdentityHashMap internedStringsIdentityMap; - - private final MessageBuilder snapshotFileBuilder = new MessageBuilder(); - protected final SharedLayerSnapshot.Builder snapshotBuilder = this.snapshotFileBuilder.initRoot(SharedLayerSnapshot.factory); - private Map constantsMap; - private final Map methodsMap = new ConcurrentHashMap<>(); - private FileInfo fileInfo; - private GraphsOutput graphsOutput; - private final boolean useSharedLayerGraphs; - private final boolean useSharedLayerStrengthenedGraphs; - - private final Set constantsToPersist = ConcurrentHashMap.newKeySet(); - - public void ensureConstantPersisted(ImageHeapConstant constant) { - constantsToPersist.add(constant); - afterConstantAdded(constant); - } - - protected record ConstantParent(int constantId, int index) { - static ConstantParent NONE = new ConstantParent(UNDEFINED_CONSTANT_ID, UNDEFINED_FIELD_INDEX); - } - - private record FileInfo(Path layerFilePath, String fileName, String suffix) { - } - - protected record MethodGraphsInfo(String analysisGraphLocation, boolean analysisGraphIsIntrinsic, - String strengthenedGraphLocation) { - - static final MethodGraphsInfo NO_GRAPHS = new MethodGraphsInfo(null, false, null); - - MethodGraphsInfo withAnalysisGraph(String location, boolean isIntrinsic) { - assert analysisGraphLocation == null && !analysisGraphIsIntrinsic; - return new MethodGraphsInfo(location, isIntrinsic, strengthenedGraphLocation); - } - - MethodGraphsInfo withStrengthenedGraph(String location) { - assert strengthenedGraphLocation == null; - return new MethodGraphsInfo(analysisGraphLocation, analysisGraphIsIntrinsic, location); - } - } - - private static class GraphsOutput { - private final Path path; - private final Path tempPath; - private final FileChannel tempChannel; - - private final AtomicLong currentOffset = new AtomicLong(0); - - GraphsOutput(Path path, String fileName, String suffix) { - this.path = path; - this.tempPath = FileDumpingUtil.createTempFile(path.getParent(), fileName, suffix); - try { - this.tempChannel = FileChannel.open(this.tempPath, EnumSet.of(StandardOpenOption.WRITE)); - } catch (IOException e) { - throw GraalError.shouldNotReachHere(e, "Error opening temporary graphs file."); - } - } - - String add(byte[] encodedGraph) { - long offset = currentOffset.getAndAdd(encodedGraph.length); - try { - tempChannel.write(ByteBuffer.wrap(encodedGraph), offset); - } catch (Exception e) { - throw GraalError.shouldNotReachHere(e, "Error during graphs file dumping."); - } - return new StringBuilder("@").append(offset).append("[").append(encodedGraph.length).append("]").toString(); - } - - void finish() { - try { - tempChannel.close(); - FileDumpingUtil.moveTryAtomically(tempPath, path); - } catch (Exception e) { - throw GraalError.shouldNotReachHere(e, "Error during graphs file dumping."); - } - } - } - - public ImageLayerWriter(boolean useSharedLayerGraphs, boolean useSharedLayerStrengthenedGraphs) { - this.useSharedLayerGraphs = useSharedLayerGraphs; - this.useSharedLayerStrengthenedGraphs = useSharedLayerStrengthenedGraphs; - } - - public void setImageLayerSnapshotUtil(ImageLayerSnapshotUtil imageLayerSnapshotUtil) { - this.imageLayerSnapshotUtil = imageLayerSnapshotUtil; - } - - public void setInternedStringsIdentityMap(IdentityHashMap map) { - this.internedStringsIdentityMap = map; - } - - public void setImageHeap(ImageHeap heap) { - this.imageHeap = heap; - } - - public void setImageLayerWriterHelper(ImageLayerWriterHelper imageLayerWriterHelper) { - this.imageLayerWriterHelper = imageLayerWriterHelper; - } - - public void setSnapshotFileInfo(Path layerSnapshotPath, String fileName, String suffix) { - fileInfo = new FileInfo(layerSnapshotPath, fileName, suffix); - } - - public void openGraphsOutput(Path layerGraphsPath, String fileName, String suffix) { - AnalysisError.guarantee(graphsOutput == null, "Graphs file has already been opened"); - graphsOutput = new GraphsOutput(layerGraphsPath, fileName, suffix); - } - - public void setAnalysisUniverse(AnalysisUniverse aUniverse) { - this.aUniverse = aUniverse; - } - - @SuppressWarnings("unused") - public void onTrackedAcrossLayer(AnalysisMethod method, Object reason) { - imageLayerWriterHelper.onTrackedAcrossLayer(method, reason); - } - - public void dumpFiles() { - graphsOutput.finish(); - - FileDumpingUtil.dumpFile(fileInfo.layerFilePath, fileInfo.fileName, fileInfo.suffix, outputStream -> { - try { - Serialize.write(Channels.newChannel(outputStream), snapshotFileBuilder); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - } - - public void initializeExternalValues() { - imageLayerSnapshotUtil.initializeExternalValues(); - } - - public void setImageHeapSize(long imageHeapSize) { - snapshotBuilder.setImageHeapSize(imageHeapSize); - } - - public void persistAnalysisInfo() { - persistHook(); - - // Late constant scan so all of them are known with values available (readers installed) - List constantsToScan = new ArrayList<>(constantsToPersist); - imageHeap.getReachableObjects().values().forEach(constantsToScan::addAll); - constantsMap = HashMap.newHashMap(constantsToScan.size()); - constantsToScan.forEach(c -> constantsMap.put(c, ConstantParent.NONE)); - while (!constantsToScan.isEmpty()) { - List discoveredConstants = new ArrayList<>(); - constantsToScan.forEach(con -> scanConstantReferencedObjects(con, discoveredConstants)); - constantsToScan = discoveredConstants; - } - - snapshotBuilder.setNextTypeId(aUniverse.getNextTypeId()); - snapshotBuilder.setNextMethodId(aUniverse.getNextMethodId()); - snapshotBuilder.setNextFieldId(aUniverse.getNextFieldId()); - snapshotBuilder.setNextConstantId(ImageHeapConstant.getCurrentId()); - - List typesToPersist = aUniverse.getTypes().stream().filter(AnalysisType::isTrackedAcrossLayers).toList(); - List methodsToPersist = aUniverse.getMethods().stream().filter(AnalysisMethod::isTrackedAcrossLayers).toList(); - List fieldsToPersist = aUniverse.getFields().stream().filter(AnalysisField::isTrackedAcrossLayers).toList(); - - initSortedList(snapshotBuilder::initTypes, typesToPersist, Comparator.comparingInt(AnalysisType::getId), this::persistType); - initSortedList(snapshotBuilder::initMethods, methodsToPersist, Comparator.comparingInt(AnalysisMethod::getId), this::persistMethod); - initSortedList(snapshotBuilder::initFields, fieldsToPersist, Comparator.comparingInt(AnalysisField::getId), this::persistField); - - Set constantsToRelink = new HashSet<>(); - initSortedList(snapshotBuilder::initConstants, constantsMap.entrySet(), - (a, b) -> Integer.compare(getConstantId(a.getKey()), getConstantId(b.getKey())), - (entry, bsupplier) -> persistConstant(entry.getKey(), entry.getValue(), bsupplier.get(), constantsToRelink)); - initInts(snapshotBuilder::initConstantsToRelink, constantsToRelink.stream().mapToInt(i -> i).sorted()); - } - - protected static void initSortedList(IntFunction> init, Collection objects, Comparator comparator, BiConsumer> action) { - @SuppressWarnings("unchecked") - T[] array = (T[]) objects.toArray(); - Arrays.sort(array, comparator); - - StructList.Builder builder = init.apply(objects.size()); - Iterator iterator = builder.iterator(); - for (T t : array) { - action.accept(t, iterator::next); - } - AnalysisError.guarantee(!iterator.hasNext(), "all created struct builders must have been used"); - } - - private void persistAnnotations(AnnotatedElement annotatedElement, IntFunction> builder) { - Class[] annotationTypes = AnnotationAccess.getAnnotationTypes(annotatedElement); - persistAnnotations(annotatedElement, annotationTypes, builder); - } - - @SuppressWarnings("unused") - protected void persistAnnotations(AnnotatedElement annotatedElement, Class[] annotationTypes, - IntFunction> builder) { - var b = builder.apply(annotationTypes.length); - for (int i = 0; i < annotationTypes.length; i++) { - b.get(i).setTypeName(annotationTypes[i].getName()); - persistAnnotationValues(annotatedElement, annotationTypes[i], b.get(i)::initValues); - } - } - - @SuppressWarnings("unused") - protected void persistAnnotationValues(AnnotatedElement annotatedElement, Class annotationType, - IntFunction> builder) { - } - - /** - * A hook used to persist more general information about the base layer not accessible in - * pointsto. - */ - @SuppressWarnings("unused") - protected void persistHook() { - - } - - public boolean isTypePersisted(AnalysisType type) { - return type.isTrackedAcrossLayers(); - } - - private void persistType(AnalysisType type, Supplier builderSupplier) { - String typeDescriptor = imageLayerSnapshotUtil.getTypeDescriptor(type); - persistType(type, typeDescriptor, builderSupplier.get()); - } - - protected void persistType(AnalysisType type, String typeDescriptor, PersistedAnalysisType.Builder builder) { - builder.setId(type.getId()); - builder.setDescriptor(typeDescriptor); - - initInts(builder::initFields, Arrays.stream(type.getInstanceFields(true)).mapToInt(f -> ((AnalysisField) f).getId())); - builder.setClassJavaName(type.toJavaName()); - builder.setClassName(type.getName()); - builder.setModifiers(type.getModifiers()); - builder.setIsInterface(type.isInterface()); - builder.setIsEnum(type.isEnum()); - builder.setIsInitialized(type.isInitialized()); - builder.setIsLinked(type.isLinked()); - if (type.getSourceFileName() != null) { - builder.setSourceFileName(type.getSourceFileName()); - } - try { - AnalysisType enclosingType = type.getEnclosingType(); - if (enclosingType != null) { - builder.setEnclosingTypeId(enclosingType.getId()); - } - } catch (InternalError | TypeNotPresentException | LinkageError e) { - /* Ignore missing type errors. */ - } - if (type.isArray()) { - builder.setComponentTypeId(type.getComponentType().getId()); - } - if (type.getSuperclass() != null) { - builder.setSuperClassTypeId(type.getSuperclass().getId()); - } - initInts(builder::initInterfaces, Arrays.stream(type.getInterfaces()).mapToInt(AnalysisType::getId)); - initInts(builder::initInstanceFieldIds, Arrays.stream(type.getInstanceFields(false)).mapToInt(f -> ((AnalysisField) f).getId())); - initInts(builder::initInstanceFieldIdsWithSuper, Arrays.stream(type.getInstanceFields(true)).mapToInt(f -> ((AnalysisField) f).getId())); - initInts(builder::initStaticFieldIds, Arrays.stream(type.getStaticFields()).mapToInt(f -> ((AnalysisField) f).getId())); - persistAnnotations(type, builder::initAnnotationList); - - builder.setIsInstantiated(type.isInstantiated()); - builder.setIsUnsafeAllocated(type.isUnsafeAllocated()); - builder.setIsReachable(type.isReachable()); - - imageLayerWriterHelper.persistType(type, builder); - - afterTypeAdded(type); - } - - protected static void initInts(IntFunction builderSupplier, IntStream ids) { - int[] values = ids.toArray(); - PrimitiveList.Int.Builder builder = builderSupplier.apply(values.length); - for (int i = 0; i < values.length; i++) { - builder.set(i, values[i]); - } - } - - protected static void initStringList(IntFunction builderSupplier, Stream strings) { - Object[] array = strings.toArray(); - TextList.Builder builder = builderSupplier.apply(array.length); - for (int i = 0; i < array.length; i++) { - builder.set(i, new Text.Reader(array[i].toString())); - } - } - - @SuppressWarnings("unused") - protected void afterTypeAdded(AnalysisType type) { - } - - private void afterConstantAdded(ImageHeapConstant constant) { - constant.getType().registerAsTrackedAcrossLayers(constant); - /* If this is a Class constant persist the corresponding type. */ - ConstantReflectionProvider constantReflection = aUniverse.getBigbang().getConstantReflectionProvider(); - AnalysisType typeFromClassConstant = (AnalysisType) constantReflection.asJavaType(constant); - if (typeFromClassConstant != null) { - typeFromClassConstant.registerAsTrackedAcrossLayers(constant); - } - } - - private void scanConstantReferencedObjects(ImageHeapConstant constant, Collection discoveredConstants) { - if (Objects.requireNonNull(constant) instanceof ImageHeapInstance instance) { - if (instance.isReaderInstalled()) { - scanConstantReferencedObjects(constant, instance.getFieldValues(), discoveredConstants); - } - } else if (constant instanceof ImageHeapObjectArray objArray) { - scanConstantReferencedObjects(constant, objArray.getElementValues(), discoveredConstants); - } - } - - protected void scanConstantReferencedObjects(ImageHeapConstant constant, Object[] referencedObjects, Collection discoveredConstants) { - if (referencedObjects != null) { - for (int i = 0; i < referencedObjects.length; i++) { - AnalysisType parentType = constant.getType(); - if (referencedObjects[i] instanceof ImageHeapConstant con && !constantsMap.containsKey(con)) { - /* - * Some constants are not in imageHeap#reachableObjects, but are still created - * in reachable constants. They can be created in the extension image, but - * should not be used. - */ - Set relinkedFields = imageLayerSnapshotUtil.getRelinkedFields(parentType, aUniverse.getBigbang().getMetaAccess()); - ConstantParent parent = relinkedFields.contains(i) ? new ConstantParent(getConstantId(constant), i) : ConstantParent.NONE; - - discoveredConstants.add(con); - constantsMap.put(con, parent); - } - } - } - } - - private void persistMethod(AnalysisMethod method, Supplier builderSupplier) { - persistMethod(method, builderSupplier.get()); - } - - protected void persistMethod(AnalysisMethod method, PersistedAnalysisMethod.Builder builder) { - MethodGraphsInfo graphsInfo = methodsMap.putIfAbsent(imageLayerSnapshotUtil.getMethodDescriptor(method), MethodGraphsInfo.NO_GRAPHS); - Executable executable = method.getJavaMethod(); - - if (builder.getId() != 0) { - throw GraalError.shouldNotReachHere("The method descriptor should be unique, but " + imageLayerSnapshotUtil.getMethodDescriptor(method) + " got added twice."); - } - if (executable != null) { - initStringList(builder::initArgumentClassNames, Arrays.stream(executable.getParameterTypes()).map(Class::getName)); - builder.setClassName(executable.getDeclaringClass().getName()); - } - - builder.setDescriptor(imageLayerSnapshotUtil.getMethodDescriptor(method)); - builder.setDeclaringTypeId(method.getDeclaringClass().getId()); - initInts(builder::initArgumentTypeIds, method.getSignature().toParameterList(null).stream().mapToInt(AnalysisType::getId)); - builder.setId(method.getId()); - builder.setName(method.getName()); - builder.setReturnTypeId(method.getSignature().getReturnType().getId()); - builder.setIsVarArgs(method.isVarArgs()); - builder.setCanBeStaticallyBound(method.canBeStaticallyBound()); - builder.setModifiers(method.getModifiers()); - builder.setIsConstructor(method.isConstructor()); - builder.setIsSynthetic(method.isSynthetic()); - byte[] code = method.getCode(); - if (code != null) { - builder.setCode(code); - } - builder.setCodeSize(method.getCodeSize()); - IntrinsicMethod intrinsicMethod = aUniverse.getBigbang().getConstantReflectionProvider().getMethodHandleAccess().lookupMethodHandleIntrinsic(method); - if (intrinsicMethod != null) { - builder.setMethodHandleIntrinsicName(intrinsicMethod.name()); - } - persistAnnotations(method, builder::initAnnotationList); - - builder.setIsVirtualRootMethod(method.isVirtualRootMethod()); - builder.setIsDirectRootMethod(method.isDirectRootMethod()); - builder.setIsInvoked(method.isSimplyInvoked()); - builder.setIsImplementationInvoked(method.isSimplyImplementationInvoked()); - builder.setIsIntrinsicMethod(method.isIntrinsicMethod()); - - if (graphsInfo != null && graphsInfo.analysisGraphLocation != null) { - builder.setAnalysisGraphLocation(graphsInfo.analysisGraphLocation); - builder.setAnalysisGraphIsIntrinsic(graphsInfo.analysisGraphIsIntrinsic); - } - if (graphsInfo != null && graphsInfo.strengthenedGraphLocation != null) { - builder.setStrengthenedGraphLocation(graphsInfo.strengthenedGraphLocation); - } - - imageLayerWriterHelper.persistMethod(method, builder); - } - - public boolean isMethodPersisted(AnalysisMethod method) { - String name = imageLayerSnapshotUtil.getMethodDescriptor(method); - return methodsMap.containsKey(name); - } - - public void persistAnalysisParsedGraphs() { - // Persisting graphs discovers additional types, members and constants that need persisting - Set persistedGraphMethods = new HashSet<>(); - boolean modified; - do { - modified = false; - /* - * GR-60503: It would be better to mark all the elements as trackedAcrossLayers before - * the end of the analysis and only iterate only once over all methods. - */ - for (AnalysisMethod method : aUniverse.getMethods().stream().filter(AnalysisMethod::isTrackedAcrossLayers).toList()) { - if (persistedGraphMethods.add(method)) { - modified = true; - persistAnalysisParsedGraph(method); - } - } - } while (modified); - - // Note that constants are scanned late so all values are available. - } - - private void persistAnalysisParsedGraph(AnalysisMethod method) { - Object analyzedGraph = method.getGraph(); - if (analyzedGraph instanceof AnalysisParsedGraph analysisParsedGraph) { - String name = imageLayerSnapshotUtil.getMethodDescriptor(method); - MethodGraphsInfo graphsInfo = methodsMap.get(name); - if (graphsInfo == null || graphsInfo.analysisGraphLocation == null) { - String location = persistGraph(method, analysisParsedGraph.getEncodedGraph()); - if (location != null) { - methodsMap.compute(name, (n, mgi) -> (mgi != null ? mgi : MethodGraphsInfo.NO_GRAPHS) - .withAnalysisGraph(location, analysisParsedGraph.isIntrinsic())); - } - } - } - } - - public void persistMethodStrengthenedGraph(AnalysisMethod method) { - if (!useSharedLayerStrengthenedGraphs) { - return; - } - - String name = imageLayerSnapshotUtil.getMethodDescriptor(method); - MethodGraphsInfo graphsInfo = methodsMap.get(name); - - if (graphsInfo == null || graphsInfo.strengthenedGraphLocation == null) { - EncodedGraph analyzedGraph = method.getAnalyzedGraph(); - String location = persistGraph(method, analyzedGraph); - methodsMap.compute(name, (n, mgi) -> (mgi != null ? mgi : MethodGraphsInfo.NO_GRAPHS).withStrengthenedGraph(location)); - } - } - - private String persistGraph(AnalysisMethod method, EncodedGraph analyzedGraph) { - if (!useSharedLayerGraphs) { - return null; - } - byte[] encodedGraph = ObjectCopier.encode(imageLayerSnapshotUtil.getGraphEncoder(this), analyzedGraph); - if (contains(encodedGraph, LambdaUtils.LAMBDA_CLASS_NAME_SUBSTRING.getBytes(StandardCharsets.UTF_8))) { - throw AnalysisError.shouldNotReachHere("The graph for the method %s contains a reference to a lambda type, which cannot be decoded: %s".formatted(method, encodedGraph)); - } - return graphsOutput.add(encodedGraph); - } - - private static boolean contains(byte[] data, byte[] seq) { - outer: for (int i = 0; i <= data.length - seq.length; i++) { - for (int j = 0; j < seq.length; j++) { - if (data[i + j] != seq[j]) { - continue outer; - } - } - return true; - } - return false; - } - - private void persistField(AnalysisField field, Supplier fieldBuilderSupplier) { - PersistedAnalysisField.Builder builder = fieldBuilderSupplier.get(); - - persistField(field, builder); - - Field originalField = OriginalFieldProvider.getJavaField(field); - if (originalField != null && !originalField.getDeclaringClass().equals(field.getDeclaringClass().getJavaClass())) { - builder.setClassName(originalField.getDeclaringClass().getName()); - } - builder.setIsStatic(field.isStatic()); - builder.setIsInternal(field.isInternal()); - builder.setIsSynthetic(field.isSynthetic()); - builder.setTypeId(field.getType().getId()); - builder.setModifiers(field.getModifiers()); - builder.setPosition(field.getPosition()); - - persistAnnotations(field, builder::initAnnotationList); - } - - protected void persistField(AnalysisField field, PersistedAnalysisField.Builder builder) { - builder.setId(field.getId()); - builder.setDeclaringTypeId(field.getDeclaringClass().getId()); - builder.setName(field.getName()); - builder.setIsAccessed(field.getAccessedReason() != null); - builder.setIsRead(field.getReadReason() != null); - builder.setIsWritten(field.getWrittenReason() != null); - builder.setIsFolded(field.getFoldedReason() != null); - } - - protected void persistConstant(ImageHeapConstant imageHeapConstant, ConstantParent parent, PersistedConstant.Builder builder, Set constantsToRelink) { - int id = getConstantId(imageHeapConstant); - builder.setId(id); - AnalysisType type = imageHeapConstant.getType(); - AnalysisError.guarantee(type.isTrackedAcrossLayers(), "Type %s from constant %s should have been marked as trackedAcrossLayers, but was not", type, imageHeapConstant); - builder.setTypeId(type.getId()); - - IdentityHashCodeProvider identityHashCodeProvider = (IdentityHashCodeProvider) aUniverse.getBigbang().getConstantReflectionProvider(); - int identityHashCode = identityHashCodeProvider.identityHashCode(imageHeapConstant); - builder.setIdentityHashCode(identityHashCode); - - switch (imageHeapConstant) { - case ImageHeapInstance imageHeapInstance -> { - builder.initObject().setInstance(Void.VOID); - Object[] fieldValues = imageHeapInstance.isReaderInstalled() ? imageHeapInstance.getFieldValues() : null; - persistConstantObjectData(builder.getObject(), fieldValues); - persistConstantRelinkingInfo(builder, imageHeapConstant, constantsToRelink, aUniverse.getBigbang()); - } - case ImageHeapObjectArray imageHeapObjectArray -> { - builder.initObject().setObjectArray(Void.VOID); - persistConstantObjectData(builder.getObject(), imageHeapObjectArray.getElementValues()); - } - case ImageHeapPrimitiveArray imageHeapPrimitiveArray -> - persistConstantPrimitiveArray(builder.initPrimitiveData(), imageHeapPrimitiveArray.getType().getComponentType().getJavaKind(), imageHeapPrimitiveArray.getArray()); - case ImageHeapRelocatableConstant relocatableConstant -> { - builder.initRelocatable().setKey(relocatableConstant.getConstantData().key); - } - default -> throw AnalysisError.shouldNotReachHere("Unexpected constant type " + imageHeapConstant); - } - - if (!constantsToRelink.contains(id) && parent != ConstantParent.NONE) { - builder.setParentConstantId(parent.constantId); - assert parent.index != UNDEFINED_FIELD_INDEX : "Tried to persist child constant %s from parent constant %d, but got index %d".formatted(imageHeapConstant, parent.constantId, parent.index); - builder.setParentIndex(parent.index); - } - } - - protected int getConstantId(ImageHeapConstant imageHeapConstant) { - return imageHeapConstant.constantData.id; - } - - private void persistConstantRelinkingInfo(PersistedConstant.Builder builder, ImageHeapConstant imageHeapConstant, Set constantsToRelink, BigBang bb) { - Class clazz = imageHeapConstant.getType().getJavaClass(); - JavaConstant hostedObject = imageHeapConstant.getHostedObject(); - boolean simulated = hostedObject == null; - builder.setIsSimulated(simulated); - if (!simulated) { - persistConstantRelinkingInfo(builder.getObject().getRelinking(), bb, clazz, hostedObject, imageHeapConstant.constantData.id, constantsToRelink); - } - } - - protected void persistConstantRelinkingInfo(PersistedConstant.Object.Relinking.Builder builder, BigBang bb, Class clazz, JavaConstant hostedObject, int id, Set constantsToRelink) { - if (clazz.equals(String.class)) { - StringConstant.Builder stringConstantBuilder = builder.initStringConstant(); - String value = bb.getSnippetReflectionProvider().asObject(String.class, hostedObject); - if (internedStringsIdentityMap.containsKey(value)) { - /* - * Interned strings must be relinked. - */ - stringConstantBuilder.setValue(value); - constantsToRelink.add(id); - } - } else if (Enum.class.isAssignableFrom(clazz)) { - EnumConstant.Builder enumBuilder = builder.initEnumConstant(); - Enum value = bb.getSnippetReflectionProvider().asObject(Enum.class, hostedObject); - enumBuilder.setEnumClass(value.getDeclaringClass().getName()); - enumBuilder.setEnumName(value.name()); - constantsToRelink.add(id); - } - } - - protected static void persistConstantPrimitiveArray(PrimitiveArray.Builder builder, JavaKind componentKind, Object array) { - assert componentKind.toJavaClass().equals(array.getClass().getComponentType()); - switch (array) { - case boolean[] a -> persistArray(a, builder::initZ, (b, i) -> b.set(i, a[i])); - case byte[] a -> persistArray(a, builder::initB, (b, i) -> b.set(i, a[i])); - case short[] a -> persistArray(a, builder::initS, (b, i) -> b.set(i, a[i])); - case char[] a -> persistArray(a, builder::initC, (b, i) -> b.set(i, (short) a[i])); - case int[] a -> persistArray(a, builder::initI, (b, i) -> b.set(i, a[i])); - case long[] a -> persistArray(a, builder::initJ, (b, i) -> b.set(i, a[i])); - case float[] a -> persistArray(a, builder::initF, (b, i) -> b.set(i, a[i])); - case double[] a -> persistArray(a, builder::initD, (b, i) -> b.set(i, a[i])); - default -> throw new IllegalArgumentException("Unsupported kind: " + componentKind); - } - } - - /** Enables concise one-liners in {@link #persistConstantPrimitiveArray}. */ - private static void persistArray(A array, IntFunction init, ObjIntConsumer setter) { - int length = Array.getLength(array); - T builder = init.apply(length); - for (int i = 0; i < length; i++) { - setter.accept(builder, i); - } - } - - private void persistConstantObjectData(PersistedConstant.Object.Builder builder, Object[] values) { - if (values != null) { - StructList.Builder refsBuilder = builder.initData(values.length); - for (int i = 0; i < values.length; ++i) { - Object object = values[i]; - 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(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); - } - } - } - } - - /** - * Hook for subclasses to do their own processing. - */ - @SuppressWarnings("unused") - protected boolean delegateProcessing(ConstantReference.Builder builder, Object constant) { - return false; - } -} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriterHelper.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriterHelper.java deleted file mode 100644 index cc26c326c49d..000000000000 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriterHelper.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.pointsto.heap; - -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.AnalysisType; - -public class ImageLayerWriterHelper { - protected final ImageLayerWriter imageLayerWriter; - - public ImageLayerWriterHelper(ImageLayerWriter imageLayerWriter) { - this.imageLayerWriter = imageLayerWriter; - } - - @SuppressWarnings("unused") - protected void persistType(AnalysisType type, PersistedAnalysisType.Builder builder) { - /* No additional information to persist */ - } - - @SuppressWarnings("unused") - protected void persistMethod(AnalysisMethod method, PersistedAnalysisMethod.Builder builder) { - /* No additional information to persist */ - } - - @SuppressWarnings("unused") - protected void onTrackedAcrossLayer(AnalysisMethod method, Object reason) { - } -} 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 140204eb4f70..b38ed1d63c7f 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 @@ -50,10 +50,10 @@ import org.graalvm.nativeimage.hosted.Feature.DuringAnalysisAccess; import com.oracle.graal.pointsto.BigBang; +import com.oracle.graal.pointsto.api.ImageLayerLoader; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.flow.AnalysisParsedGraph; -import com.oracle.graal.pointsto.heap.ImageLayerLoader; import com.oracle.graal.pointsto.infrastructure.GraphProvider; import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; 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 a616e7e6f729..02070692e3cf 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 @@ -44,13 +44,13 @@ import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.ObjectScanner; import com.oracle.graal.pointsto.api.HostVM; +import com.oracle.graal.pointsto.api.ImageLayerLoader; +import com.oracle.graal.pointsto.api.ImageLayerWriter; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.heap.HeapSnapshotVerifier; import com.oracle.graal.pointsto.heap.HostedValuesProvider; import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.heap.ImageHeapScanner; -import com.oracle.graal.pointsto.heap.ImageLayerLoader; -import com.oracle.graal.pointsto.heap.ImageLayerWriter; import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; @@ -438,10 +438,6 @@ private AnalysisMethod createMethod(ResolvedJavaMethod method) { }); if (result.equals(newValue)) { - if (newValue.isInBaseLayer()) { - getImageLayerLoader().initializeBaseLayerMethod(newValue); - } - prepareMethodImplementations(newValue); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/ImageSingletonLoader.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/ImageSingletonLoader.java index 3d8ed02c18dd..7f423f31645d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/ImageSingletonLoader.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/ImageSingletonLoader.java @@ -39,6 +39,4 @@ public interface ImageSingletonLoader { String readString(String keyName); List readStringList(String keyName); - - Class lookupClass(String className); } diff --git a/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp b/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp index ea188e7d1aaf..0ddb683ca041 100644 --- a/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp +++ b/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp @@ -1,6 +1,6 @@ @0x9eb32e19f86ee174; using Java = import "/capnp/java.capnp"; -$Java.package("com.oracle.graal.pointsto.heap"); +$Java.package("com.oracle.svm.hosted.imagelayer"); $Java.outerClassname("SharedLayerSnapshotCapnProtoSchemaHolder"); using TypeId = Int32; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java index 8cbf457b5aad..20c86542b765 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java @@ -39,7 +39,6 @@ import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.flow.MethodFlowsGraph; import com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder; -import com.oracle.graal.pointsto.heap.ImageLayerWriter; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccessExtensionProvider; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -64,15 +63,15 @@ import com.oracle.svm.hosted.config.DynamicHubLayout; import com.oracle.svm.hosted.config.HybridLayout; import com.oracle.svm.hosted.config.HybridLayoutSupport; -import com.oracle.svm.hosted.heap.SVMImageLayerLoaderHelper; -import com.oracle.svm.hosted.heap.SVMImageLayerSnapshotUtil; -import com.oracle.svm.hosted.heap.SVMImageLayerWriterHelper; import com.oracle.svm.hosted.image.LIRNativeImageCodeCache; import com.oracle.svm.hosted.image.NativeImageCodeCache; import com.oracle.svm.hosted.image.NativeImageCodeCacheFactory; import com.oracle.svm.hosted.image.NativeImageHeap; import com.oracle.svm.hosted.image.ObjectFileFactory; import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerLoader; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerSnapshotUtil; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerWriter; import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedInstanceClass; import com.oracle.svm.hosted.meta.HostedMetaAccess; @@ -234,12 +233,12 @@ public SVMHost createHostVM(OptionValues options, ImageClassLoader loader, Class return new SVMHost(options, loader, classInitializationSupport, annotationSubstitutions, missingRegistrationSupport); } - public SVMImageLayerWriterHelper createSVMImageLayerWriterHelper(ImageLayerWriter imageLayerWriter) { - return new SVMImageLayerWriterHelper(imageLayerWriter); + public SVMImageLayerWriter createSVMImageLayerWriter(SVMImageLayerSnapshotUtil imageLayerSnapshotUtil, boolean useSharedLayerGraphs, boolean useSharedLayerStrengthenedGraphs) { + return new SVMImageLayerWriter(imageLayerSnapshotUtil, useSharedLayerGraphs, useSharedLayerStrengthenedGraphs); } - public SVMImageLayerLoaderHelper createSVMImageLayerLoaderHelper() { - return new SVMImageLayerLoaderHelper(HostedImageLayerBuildingSupport.singleton().getLoader()); + public SVMImageLayerLoader createSVMImageLayerLoader(SVMImageLayerSnapshotUtil imageLayerSnapshotUtil, HostedImageLayerBuildingSupport imageLayerBuildingSupport, boolean useSharedLayerGraphs) { + return new SVMImageLayerLoader(imageLayerSnapshotUtil, imageLayerBuildingSupport, imageLayerBuildingSupport.getSnapshot(), imageLayerBuildingSupport.getGraphsChannel(), useSharedLayerGraphs); } public SVMImageLayerSnapshotUtil createSVMImageLayerSnapshotUtil(ImageClassLoader imageClassLoader) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageSingletonsSupportImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageSingletonsSupportImpl.java index 6d3f71ff82b3..2cb9a59b6476 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageSingletonsSupportImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageSingletonsSupportImpl.java @@ -44,8 +44,8 @@ import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton; import com.oracle.svm.core.layeredimagesingleton.RuntimeOnlyWrapper; import com.oracle.svm.core.util.UserError; -import com.oracle.svm.hosted.heap.SVMImageLayerLoader; import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerSingletonLoader; public final class ImageSingletonsSupportImpl extends ImageSingletonsSupport implements LayeredImageSingletonSupport { @@ -141,18 +141,18 @@ public static void install(HostedManagement vmConfig, HostedImageLayerBuildingSu singletonDuringImageBuild.doAddInternal(ImageLayerBuildingSupport.class, new ImageLayerBuildingSupport(false, false, false) { }); } - if (support != null && support.getLoader() != null) { + if (support != null && support.getSingletonLoader() != null) { /* * Note eventually this may need to be moved to a later point after the Options * Image Singleton is installed. */ - singletonDuringImageBuild.installPriorSingletonInfo(support.getLoader()); + singletonDuringImageBuild.installPriorSingletonInfo(support.getSingletonLoader()); } else { singletonDuringImageBuild.doAddInternal(LoadedLayeredImageSingletonInfo.class, new LoadedLayeredImageSingletonInfo(Set.of())); } } - private void installPriorSingletonInfo(SVMImageLayerLoader info) { + private void installPriorSingletonInfo(SVMImageLayerSingletonLoader info) { var result = info.loadImageSingletons(SINGLETON_INSTALLATION_FORBIDDEN); Set> installedKeys = new HashSet<>(); for (var entry : result.entrySet()) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index 4790067887f0..e73c3eb1ac3d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -52,7 +52,6 @@ import java.util.function.BooleanSupplier; import java.util.function.Function; -import com.oracle.svm.hosted.substitute.DynamicHubPlugin; import org.graalvm.collections.EconomicSet; import org.graalvm.collections.Pair; import org.graalvm.nativeimage.ImageInfo; @@ -90,8 +89,6 @@ import com.oracle.graal.pointsto.heap.HostedValuesProvider; import com.oracle.graal.pointsto.heap.ImageHeap; import com.oracle.graal.pointsto.heap.ImageHeapScanner; -import com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil; -import com.oracle.graal.pointsto.heap.ImageLayerWriter; import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; import com.oracle.graal.pointsto.infrastructure.WrappedJavaMethod; import com.oracle.graal.pointsto.meta.AnalysisFactory; @@ -224,8 +221,6 @@ import com.oracle.svm.hosted.heap.ObservableImageHeapMapProviderImpl; import com.oracle.svm.hosted.heap.SVMImageHeapScanner; import com.oracle.svm.hosted.heap.SVMImageHeapVerifier; -import com.oracle.svm.hosted.heap.SVMImageLayerLoader; -import com.oracle.svm.hosted.heap.SVMImageLayerWriter; import com.oracle.svm.hosted.image.AbstractImage; import com.oracle.svm.hosted.image.AbstractImage.NativeImageKind; import com.oracle.svm.hosted.image.NativeImageCodeCache; @@ -233,6 +228,9 @@ import com.oracle.svm.hosted.image.NativeImageHeap; import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport; import com.oracle.svm.hosted.imagelayer.LoadImageSingletonFeature; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerLoader; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerSnapshotUtil; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerWriter; import com.oracle.svm.hosted.jdk.localization.LocalizationFeature; import com.oracle.svm.hosted.meta.HostedConstantReflectionProvider; import com.oracle.svm.hosted.meta.HostedMetaAccess; @@ -253,6 +251,7 @@ import com.oracle.svm.hosted.snippets.SubstrateGraphBuilderPlugins; import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor; import com.oracle.svm.hosted.substitute.DeletedFieldsPlugin; +import com.oracle.svm.hosted.substitute.DynamicHubPlugin; import com.oracle.svm.hosted.substitute.SubstitutionInvocationPlugins; import com.oracle.svm.hosted.util.CPUTypeAArch64; import com.oracle.svm.hosted.util.CPUTypeAMD64; @@ -899,9 +898,6 @@ protected void setupNativeImage(String imageName, OptionValues options, Map - *

  • We have a strengthened graph available. See {@link ImageLayerLoader#hasStrengthenedGraph} - * for which strengthened graphs are persisted. Having an analysis parsed graph (see - * {@link ImageLayerLoader#hasAnalysisParsedGraph}) is not enough because methods with only an - * analysis parsed graph are inlined before analysis, but not analyzed. Additionally, having a - * strengthened graph implies also having an analysis parsed graph.
  • + *
  • We have a strengthened graph available. See + * {@link SVMImageLayerLoader#hasStrengthenedGraph} for which strengthened graphs are persisted. + * Having an analysis parsed graph (see {@link SVMImageLayerLoader#hasAnalysisParsedGraph}) is + * not enough because methods with only an analysis parsed graph are inlined before analysis, + * but not analyzed. Additionally, having a strengthened graph implies also having an analysis + * parsed graph.
  • *
  • A compile target exists this layer can call.
  • * * @@ -277,7 +278,7 @@ public boolean useBaseLayer() { */ @Override public boolean analyzedInPriorLayer(AnalysisMethod method) { - ImageLayerLoader imageLayerLoader = HostedImageLayerBuildingSupport.singleton().getLoader(); + SVMImageLayerLoader imageLayerLoader = HostedImageLayerBuildingSupport.singleton().getLoader(); return imageLayerLoader.hasStrengthenedGraph(method) || HostedDynamicLayerInfo.singleton().compiledInPriorLayer(method); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java index a408db4dc8ea..d5b5abe52f89 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java @@ -50,6 +50,7 @@ import com.oracle.svm.hosted.ameta.CustomTypeFieldHandler; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.code.IncompatibleClassChangeFallbackMethod; +import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport; import com.oracle.svm.hosted.meta.HostedType; import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor; @@ -144,7 +145,7 @@ public void onTypeReachable(AnalysisType type) { * avoid deadlocks, the hub needs to be rescanned manually after the metadata is * initialized. */ - universe.getImageLayerLoader().rescanHub(type, ((SVMHost) hostVM).dynamicHub(type)); + HostedImageLayerBuildingSupport.singleton().getLoader().rescanHub(type, ((SVMHost) hostVM).dynamicHub(type)); } if (SubstrateOptions.includeAll()) { /* 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 01dea65fcaf7..7a1971234edb 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 @@ -42,7 +42,6 @@ import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.flow.AnalysisParsedGraph; -import com.oracle.graal.pointsto.heap.ImageLayerLoader; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.graal.pointsto.util.CompletionExecutor; import com.oracle.graal.pointsto.util.CompletionExecutor.DebugContextRunnable; @@ -73,6 +72,7 @@ import com.oracle.svm.hosted.diagnostic.HostedHeapDumpFeature; import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport; import com.oracle.svm.hosted.imagelayer.LayeredDispatchTableSupport; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerLoader; import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.HostedUniverse; import com.oracle.svm.hosted.phases.ImageBuildStatisticsCounterPhase; @@ -987,7 +987,7 @@ public void scheduleDeoptTargets() { private static boolean parseInCurrentLayer(HostedMethod method) { var hasAnalyzedGraph = method.wrapped.getAnalyzedGraph() != null; if (!hasAnalyzedGraph && method.wrapped.reachableInCurrentLayer()) { - ImageLayerLoader imageLayerLoader = HostedImageLayerBuildingSupport.singleton().getLoader(); + SVMImageLayerLoader imageLayerLoader = HostedImageLayerBuildingSupport.singleton().getLoader(); hasAnalyzedGraph = imageLayerLoader.hasStrengthenedGraph(method.wrapped); } assert hasAnalyzedGraph || method.isCompiledInPriorLayer() || method.compilationInfo.inParseQueue.get() : method; @@ -1035,7 +1035,7 @@ private static void loadPriorStrengthenedGraph(HostedMethod method) { * Only the strengthened graphs of methods that need to be analyzed in the current layer * are loaded. */ - ImageLayerLoader imageLayerLoader = HostedImageLayerBuildingSupport.singleton().getLoader(); + SVMImageLayerLoader imageLayerLoader = HostedImageLayerBuildingSupport.singleton().getLoader(); boolean hasStrengthenedGraph = imageLayerLoader.hasStrengthenedGraph(method.wrapped); assert method.isCompiledInPriorLayer() || method.compilationInfo.inParseQueue.get() || hasStrengthenedGraph : method; if (hasStrengthenedGraph) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoader.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoader.java deleted file mode 100644 index 06e5853ef30e..000000000000 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoader.java +++ /dev/null @@ -1,475 +0,0 @@ -/* - * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.hosted.heap; - -import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.PERSISTED; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Array; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.IntStream; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -import org.capnproto.StructList; -import org.capnproto.Text; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.UnmodifiableEconomicMap; -import org.graalvm.nativeimage.impl.CEntryPointLiteralCodePointer; - -import com.oracle.graal.pointsto.heap.ImageHeapConstant; -import com.oracle.graal.pointsto.heap.ImageHeapInstance; -import com.oracle.graal.pointsto.heap.ImageLayerLoader; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonKey; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonObject; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.KeyStoreEntry; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisField; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant; -import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.util.AnalysisError; -import com.oracle.graal.pointsto.util.AnalysisFuture; -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.TypeResult; -import com.oracle.svm.core.classinitialization.ClassInitializationInfo; -import com.oracle.svm.core.graal.code.CGlobalDataInfo; -import com.oracle.svm.core.hub.DynamicHub; -import com.oracle.svm.core.layeredimagesingleton.ImageSingletonLoader; -import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton.PersistFlags; -import com.oracle.svm.core.meta.MethodPointer; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.hosted.ImageClassLoader; -import com.oracle.svm.hosted.SVMHost; -import com.oracle.svm.hosted.c.CGlobalDataFeature; -import com.oracle.svm.hosted.fieldfolding.StaticFinalFieldFoldingFeature; -import com.oracle.svm.hosted.meta.HostedUniverse; -import com.oracle.svm.hosted.meta.RelocatableConstant; -import com.oracle.svm.hosted.util.IdentityHashCodeUtil; -import com.oracle.svm.util.LogUtils; -import com.oracle.svm.util.ReflectionUtil; - -import jdk.graal.compiler.nodes.EncodedGraph; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaKind; -import sun.reflect.annotation.AnnotationParser; - -public class SVMImageLayerLoader extends ImageLayerLoader { - - private final Field dynamicHubArrayHubField; - private final boolean useSharedLayerGraphs; - - private HostedUniverse hostedUniverse; - private final ImageClassLoader imageClassLoader; - - public SVMImageLayerLoader(List loadPaths, ImageClassLoader imageClassLoader, boolean useSharedLayerGraphs) { - super(loadPaths); - dynamicHubArrayHubField = ReflectionUtil.lookupField(DynamicHub.class, "arrayHub"); - this.imageClassLoader = imageClassLoader; - this.useSharedLayerGraphs = useSharedLayerGraphs; - } - - public void setHostedUniverse(HostedUniverse hostedUniverse) { - this.hostedUniverse = hostedUniverse; - } - - public HostedUniverse getHostedUniverse() { - return hostedUniverse; - } - - @Override - public boolean hasAnalysisParsedGraph(AnalysisMethod analysisMethod) { - if (!useSharedLayerGraphs) { - return false; - } - return super.hasAnalysisParsedGraph(analysisMethod); - } - - public ClassInitializationInfo getClassInitializationInfo(AnalysisType type) { - PersistedAnalysisType.Reader typeMap = findType(type.getId()); - - var initInfo = typeMap.getClassInitializationInfo(); - if (initInfo.getIsNoInitializerNoTracking()) { - return ClassInitializationInfo.forNoInitializerInfo(false); - } else if (initInfo.getIsInitializedNoTracking()) { - return ClassInitializationInfo.forInitializedInfo(false); - } else if (initInfo.getIsFailedNoTracking()) { - return ClassInitializationInfo.forFailedInfo(false); - } else { - boolean isTracked = initInfo.getIsTracked(); - - ClassInitializationInfo.InitState initState; - if (initInfo.getIsInitialized()) { - initState = ClassInitializationInfo.InitState.FullyInitialized; - } else if (initInfo.getIsInErrorState()) { - initState = ClassInitializationInfo.InitState.InitializationError; - } else { - assert initInfo.getIsLinked() : "Invalid state"; - int classInitializerId = initInfo.getInitializerMethodId(); - MethodPointer classInitializer = (classInitializerId == 0) ? null : new MethodPointer(getAnalysisMethodForBaseLayerId(classInitializerId)); - return new ClassInitializationInfo(classInitializer, isTracked); - } - - return new ClassInitializationInfo(initState, initInfo.getHasInitializer(), initInfo.getIsBuildTimeInitialized(), isTracked); - } - } - - @Override - public Class lookupClass(boolean optional, String className) { - TypeResult> typeResult = imageClassLoader.findClass(className); - if (!typeResult.isPresent()) { - if (optional) { - return null; - } else { - throw AnalysisError.shouldNotReachHere("Class not found: " + className); - } - } - return typeResult.get(); - } - - @Override - protected Annotation[] getAnnotations(StructList.Reader reader) { - return IntStream.range(0, reader.size()).mapToObj(reader::get).map(this::getAnnotation).toArray(Annotation[]::new); - } - - private Annotation getAnnotation(SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.Reader a) { - String typeName = a.getTypeName().toString(); - Class annotationType = lookupBaseLayerTypeInHostVM(typeName).asSubclass(Annotation.class); - Map annotationValuesMap = new HashMap<>(); - a.getValues().forEach(v -> { - Object value = getAnnotationValue(v); - annotationValuesMap.put(v.getName().toString(), value); - }); - return AnnotationParser.annotationForMap(annotationType, annotationValuesMap); - } - - private Object getAnnotationValue(SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue.Reader v) { - return switch (v.which()) { - case STRING -> v.getString().toString(); - case ENUM -> getEnumValue(v.getEnum().getClassName(), v.getEnum().getName()); - case PRIMITIVE -> { - var p = v.getPrimitive(); - long rawValue = p.getRawValue(); - char typeChar = (char) p.getTypeChar(); - yield switch (JavaKind.fromPrimitiveOrVoidTypeChar(typeChar)) { - case Boolean -> rawValue != 0; - case Byte -> (byte) rawValue; - case Char -> (char) rawValue; - case Short -> (short) rawValue; - case Int -> (int) rawValue; - case Long -> rawValue; - case Float -> Float.intBitsToFloat((int) rawValue); - case Double -> Double.longBitsToDouble(rawValue); - default -> throw AnalysisError.shouldNotReachHere("Unknown annotation value type: " + typeChar); - }; - } - case PRIMITIVE_ARRAY -> getArray(v.getPrimitiveArray()); - case CLASS_NAME -> lookupClass(false, v.getClassName().toString()); - case ANNOTATION -> getAnnotation(v.getAnnotation()); - case MEMBERS -> { - var m = v.getMembers(); - var mv = m.getMemberValues(); - Class membersClass = lookupClass(false, m.getClassName().toString()); - var array = Array.newInstance(membersClass, mv.size()); - for (int i = 0; i < mv.size(); ++i) { - Array.set(array, i, getAnnotationValue(mv.get(i))); - } - yield array; - } - case _NOT_IN_SCHEMA -> throw AnalysisError.shouldNotReachHere("Unknown annotation value kind: " + v.which()); - }; - } - - @Override - protected EncodedGraph getEncodedGraph(AnalysisMethod analysisMethod, Text.Reader location) { - EncodedGraph encodedGraph = super.getEncodedGraph(analysisMethod, location); - for (int i = 0; i < encodedGraph.getNumObjects(); ++i) { - if (encodedGraph.getObject(i) instanceof CGlobalDataInfo cGlobalDataInfo) { - encodedGraph.setObject(i, CGlobalDataFeature.singleton().registerAsAccessedOrGet(cGlobalDataInfo.getData())); - } - } - return encodedGraph; - } - - @Override - public void initializeBaseLayerField(AnalysisField analysisField) { - PersistedAnalysisField.Reader fieldData = getFieldData(analysisField); - - int fieldCheckIndex = fieldData.getFieldCheckIndex(); - if (fieldCheckIndex != -1) { - StaticFinalFieldFoldingFeature.singleton().putBaseLayerFieldCheckIndex(analysisField.getId(), fieldCheckIndex); - } - - super.initializeBaseLayerField(analysisField); - } - - @Override - protected void prepareConstantRelinking(PersistedConstant.Reader constantData, int identityHashCode, int id) { - if (constantData.isObject() && constantData.getObject().getRelinking().isClassConstant()) { - int typeId = constantData.getObject().getRelinking().getClassConstant().getTypeId(); - typeToConstant.put(typeId, id); - } else { - super.prepareConstantRelinking(constantData, identityHashCode, id); - } - } - - @Override - protected boolean delegateProcessing(ConstantReference.Reader constantRef, Object[] values, int i) { - if (constantRef.isMethodPointer()) { - AnalysisFuture task = new AnalysisFuture<>(() -> { - AnalysisType methodPointerType = metaAccess.lookupJavaType(MethodPointer.class); - int mid = constantRef.getMethodPointer().getMethodId(); - AnalysisMethod method = getAnalysisMethodForBaseLayerId(mid); - RelocatableConstant constant = new RelocatableConstant(new MethodPointer(method), methodPointerType); - values[i] = constant; - return constant; - }); - values[i] = task; - return true; - } else if (constantRef.isCEntryPointLiteralCodePointer()) { - AnalysisType cEntryPointerLiteralPointerType = metaAccess.lookupJavaType(CEntryPointLiteralCodePointer.class); - CEntryPointLiteralReference.Reader ref = constantRef.getCEntryPointLiteralCodePointer(); - String methodName = ref.getMethodName().toString(); - Class definingClass = lookupBaseLayerTypeInHostVM(ref.getDefiningClass().toString()); - Class[] parameterTypes = IntStream.range(0, ref.getParameterNames().size()) - .mapToObj(j -> ref.getParameterNames().get(j).toString()) - .map(this::lookupBaseLayerTypeInHostVM).toArray(Class[]::new); - values[i] = new RelocatableConstant(new CEntryPointLiteralCodePointer(definingClass, methodName, parameterTypes), cEntryPointerLiteralPointerType); - return true; - } - return super.delegateProcessing(constantRef, values, i); - } - - @Override - protected JavaConstant lookupHostedObject(PersistedConstant.Reader baseLayerConstant, Class clazz) { - if (clazz.equals(Class.class)) { - /* DynamicHub corresponding to $$TypeSwitch classes are not relinked */ - if (baseLayerConstant.isObject() && baseLayerConstant.getObject().getRelinking().isClassConstant()) { - int typeId = baseLayerConstant.getObject().getRelinking().getClassConstant().getTypeId(); - return getDynamicHub(typeId); - } - } - return super.lookupHostedObject(baseLayerConstant, clazz); - } - - private JavaConstant getDynamicHub(int tid) { - AnalysisType type = getAnalysisTypeForBaseLayerId(tid); - DynamicHub hub = ((SVMHost) universe.hostVM()).dynamicHub(type); - return hostedValuesProvider.forObject(hub); - } - - @Override - protected void injectIdentityHashCode(Object object, Integer identityHashCode) { - if (object == null || identityHashCode == null) { - return; - } - boolean result = IdentityHashCodeUtil.injectIdentityHashCode(object, identityHashCode); - if (!result) { - if (SubstrateOptions.LoggingHashCodeInjection.getValue()) { - LogUtils.warning("Object of type %s already had an hash code: %s", object.getClass(), object); - } - } - } - - @Override - public void ensureHubInitialized(ImageHeapConstant constant) { - JavaConstant javaConstant = constant.getHostedObject(); - if (constant.getType().getJavaClass().equals(Class.class)) { - DynamicHub hub = universe.getHostedValuesProvider().asObject(DynamicHub.class, javaConstant); - AnalysisType type = ((SVMHost) universe.hostVM()).lookupType(hub); - ensureHubInitialized(type); - /* - * If the persisted constant contains a non-null arrayHub, the corresponding DynamicHub - * must be created and the initializeMetaDataTask needs to be executed to ensure the - * hosted object matches the persisted constant. - */ - if (((ImageHeapInstance) constant).getFieldValue(metaAccess.lookupJavaField(dynamicHubArrayHubField)) != JavaConstant.NULL_POINTER && hub.getArrayHub() == null) { - AnalysisType arrayClass = type.getArrayClass(); - ensureHubInitialized(arrayClass); - } - } - } - - private static void ensureHubInitialized(AnalysisType type) { - type.registerAsReachable(PERSISTED); - type.getInitializeMetaDataTask().ensureDone(); - } - - @Override - public void rescanHub(AnalysisType type, Object hubObject) { - DynamicHub hub = (DynamicHub) hubObject; - universe.getHeapScanner().rescanObject(hub); - universe.getHeapScanner().rescanField(hub, SVMImageLayerSnapshotUtil.classInitializationInfo); - if (type.getJavaKind() == JavaKind.Object) { - if (type.isArray()) { - universe.getHeapScanner().rescanField(hub.getComponentHub(), SVMImageLayerSnapshotUtil.arrayHub); - } - universe.getHeapScanner().rescanField(hub, SVMImageLayerSnapshotUtil.interfacesEncoding); - if (type.isEnum()) { - universe.getHeapScanner().rescanField(hub, SVMImageLayerSnapshotUtil.enumConstantsReference); - } - } - } - - @Override - protected boolean hasValueForObject(Object object) { - if (object instanceof DynamicHub dynamicHub) { - AnalysisType type = ((SVMHost) universe.hostVM()).lookupType(dynamicHub); - return typeToConstant.containsKey(type.getId()); - } - return super.hasValueForObject(object); - } - - @Override - protected ImageHeapConstant getValueForObject(Object object) { - if (object instanceof DynamicHub dynamicHub) { - AnalysisType type = ((SVMHost) universe.hostVM()).lookupType(dynamicHub); - int id = typeToConstant.get(type.getId()); - return getOrCreateConstant(id); - } - return super.getValueForObject(object); - } - - public Map>> loadImageSingletons(Object forbiddenObject) { - openFilesAndLoadJsonMap(); - return loadImageSingletons0(forbiddenObject); - } - - private Map>> loadImageSingletons0(Object forbiddenObject) { - Map idToObjectMap = new HashMap<>(); - for (ImageSingletonObject.Reader obj : snapshot.getSingletonObjects()) { - String className = obj.getClassName().toString(); - - EconomicMap keyStore = EconomicMap.create(); - for (KeyStoreEntry.Reader entry : obj.getStore()) { - KeyStoreEntry.Value.Reader v = entry.getValue(); - Object value = switch (v.which()) { - case I -> v.getI(); - case J -> v.getJ(); - case STR -> v.getStr().toString(); - case IL -> Stream.of(v.getIl()).flatMapToInt(r -> IntStream.range(0, r.size()).map(r::get)).toArray(); - case ZL -> getBooleans(v.getZl()); - case STRL -> StreamSupport.stream(v.getStrl().spliterator(), false).map(Text.Reader::toString).toArray(String[]::new); - case _NOT_IN_SCHEMA -> throw new IllegalStateException("Unexpected value: " + v.which()); - }; - keyStore.put(entry.getKey().toString(), value); - } - - // create singleton object instance - Object result; - try { - Class clazz = lookupClass(false, className); - Method createMethod = ReflectionUtil.lookupMethod(clazz, "createFromLoader", ImageSingletonLoader.class); - result = createMethod.invoke(null, new ImageSingletonLoaderImpl(keyStore, imageClassLoader)); - } catch (Throwable t) { - throw VMError.shouldNotReachHere("Failed to recreate image singleton", t); - } - - idToObjectMap.put(obj.getId(), result); - } - - Map>> singletonInitializationMap = new HashMap<>(); - for (ImageSingletonKey.Reader entry : snapshot.getSingletonKeys()) { - String className = entry.getKeyClassName().toString(); - PersistFlags persistInfo = PersistFlags.values()[entry.getPersistFlag()]; - int id = entry.getObjectId(); - if (persistInfo == PersistFlags.CREATE) { - assert id != -1 : "Create image singletons should be linked to an object"; - Object singletonObject = idToObjectMap.get(id); - Class clazz = lookupClass(false, className); - singletonInitializationMap.computeIfAbsent(singletonObject, (k) -> new HashSet<>()); - singletonInitializationMap.get(singletonObject).add(clazz); - } else if (persistInfo == PersistFlags.FORBIDDEN) { - assert id == -1 : "Unrestored image singleton should not be linked to an object"; - Class clazz = lookupClass(false, className); - singletonInitializationMap.computeIfAbsent(forbiddenObject, (k) -> new HashSet<>()); - singletonInitializationMap.get(forbiddenObject).add(clazz); - } else { - assert persistInfo == PersistFlags.NOTHING : "Unexpected PersistFlags value: " + persistInfo; - assert id == -1 : "Unrestored image singleton should not be linked to an object"; - } - } - - return singletonInitializationMap; - } - -} - -class ImageSingletonLoaderImpl implements ImageSingletonLoader { - private final UnmodifiableEconomicMap keyStore; - private final ImageClassLoader imageClassLoader; - - ImageSingletonLoaderImpl(UnmodifiableEconomicMap keyStore, ImageClassLoader imageClassLoader) { - this.keyStore = keyStore; - this.imageClassLoader = imageClassLoader; - } - - @Override - public List readBoolList(String keyName) { - boolean[] l = (boolean[]) keyStore.get(keyName); - return IntStream.range(0, l.length).mapToObj(i -> l[i]).toList(); - } - - @Override - public int readInt(String keyName) { - return (int) keyStore.get(keyName); - } - - @Override - public List readIntList(String keyName) { - int[] l = (int[]) keyStore.get(keyName); - return IntStream.of(l).boxed().toList(); - } - - @Override - public long readLong(String keyName) { - return (long) keyStore.get(keyName); - } - - @Override - public String readString(String keyName) { - return (String) keyStore.get(keyName); - } - - @Override - public List readStringList(String keyName) { - return List.of((String[]) keyStore.get(keyName)); - } - - @Override - public Class lookupClass(String className) { - return imageClassLoader.findClass(className).get(); - } -} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoaderHelper.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoaderHelper.java deleted file mode 100644 index d868915dea98..000000000000 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerLoaderHelper.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.hosted.heap; - -import static com.oracle.svm.hosted.lambda.LambdaParser.createMethodGraph; -import static com.oracle.svm.hosted.lambda.LambdaParser.getLambdaClassFromConstantNode; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Executable; -import java.lang.reflect.Proxy; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.IntStream; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -import org.capnproto.Text; -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.c.function.CEntryPoint; - -import com.oracle.graal.pointsto.BigBang; -import com.oracle.graal.pointsto.heap.ImageLayerLoader; -import com.oracle.graal.pointsto.heap.ImageLayerLoaderHelper; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod.WrappedMethod; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod.WrappedMethod.WrappedMember; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType.WrappedType; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType.WrappedType.SerializationGenerated; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.meta.AnalysisUniverse; -import com.oracle.graal.pointsto.meta.BaseLayerMethod; -import com.oracle.svm.core.reflect.serialize.SerializationSupport; -import com.oracle.svm.hosted.FeatureImpl; -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.jni.JNIAccessFeature; -import com.oracle.svm.hosted.lambda.LambdaParser; -import com.oracle.svm.hosted.reflect.ReflectionFeature; -import com.oracle.svm.hosted.reflect.serialize.SerializationFeature; -import com.oracle.svm.util.ReflectionUtil; - -import jdk.graal.compiler.graph.iterators.NodeIterable; -import jdk.graal.compiler.java.BytecodeParser; -import jdk.graal.compiler.nodes.ConstantNode; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.options.OptionValues; -import jdk.internal.reflect.ReflectionFactory; -import jdk.vm.ci.meta.ResolvedJavaMethod; - -public class SVMImageLayerLoaderHelper extends ImageLayerLoaderHelper { - private final Map, Boolean> capturingClasses = new ConcurrentHashMap<>(); - - public SVMImageLayerLoaderHelper(ImageLayerLoader imageLayerLoader) { - super(imageLayerLoader); - } - - @Override - @SuppressWarnings("deprecation") - protected boolean loadType(PersistedAnalysisType.Reader typeData, int tid) { - WrappedType.Reader wrappedType = typeData.getWrappedType(); - if (wrappedType.isNone()) { - return false; - } - if (wrappedType.isSerializationGenerated()) { - SerializationGenerated.Reader sg = wrappedType.getSerializationGenerated(); - String rawDeclaringClassName = sg.getRawDeclaringClass().toString(); - String rawTargetConstructorClassName = sg.getRawTargetConstructor().toString(); - Class rawDeclaringClass = imageLayerLoader.lookupClass(false, rawDeclaringClassName); - Class rawTargetConstructorClass = imageLayerLoader.lookupClass(false, rawTargetConstructorClassName); - SerializationSupport serializationSupport = SerializationSupport.singleton(); - Constructor rawTargetConstructor = ReflectionUtil.lookupConstructor(rawTargetConstructorClass); - Constructor constructor = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(rawDeclaringClass, rawTargetConstructor); - serializationSupport.addConstructorAccessor(rawDeclaringClass, rawTargetConstructorClass, SerializationFeature.getConstructorAccessor(constructor)); - Class constructorAccessor = serializationSupport.getSerializationConstructorAccessor(rawDeclaringClass, rawTargetConstructorClass).getClass(); - imageLayerLoader.getMetaAccess().lookupJavaType(constructorAccessor); - return true; - } else if (wrappedType.isLambda()) { - String capturingClassName = wrappedType.getLambda().getCapturingClass().toString(); - Class capturingClass = imageLayerLoader.lookupClass(false, capturingClassName); - loadLambdaTypes(capturingClass); - } else if (wrappedType.isProxyType()) { - Class[] interfaces = Stream.of(typeData.getInterfaces()).flatMapToInt(r -> IntStream.range(0, r.size()).map(r::get)) - .mapToObj(i -> imageLayerLoader.getAnalysisTypeForBaseLayerId(i).getJavaClass()).toArray(Class[]::new); - /* GR-59854: The deprecation warning comes from this call to Proxy.getProxyClass. */ - Class proxy = Proxy.getProxyClass(interfaces[0].getClassLoader(), interfaces); - imageLayerLoader.getMetaAccess().lookupJavaType(proxy); - return true; - } - - return super.loadType(typeData, tid); - } - - /** - * Load all lambda types of the given capturing class. Each method of the capturing class is - * parsed (see {@link LambdaParser#createMethodGraph(ResolvedJavaMethod, OptionValues)}). The - * lambda types can then be found in the constant nodes of the graphs. - */ - private void loadLambdaTypes(Class capturingClass) { - AnalysisUniverse universe = imageLayerLoader.getUniverse(); - capturingClasses.computeIfAbsent(capturingClass, key -> { - LambdaParser.allExecutablesDeclaredInClass(universe.getOriginalMetaAccess().lookupJavaType(capturingClass)) - .filter(m -> m.getCode() != null) - .forEach(m -> loadLambdaTypes(m, universe.getBigbang())); - return true; - }); - } - - private static void loadLambdaTypes(ResolvedJavaMethod m, BigBang bigBang) { - StructuredGraph graph; - try { - graph = createMethodGraph(m, bigBang.getOptions()); - } catch (NoClassDefFoundError | BytecodeParser.BytecodeParserError e) { - /* Skip the method if it refers to a missing class */ - return; - } - - NodeIterable constantNodes = ConstantNode.getConstantNodes(graph); - - for (ConstantNode cNode : constantNodes) { - Class lambdaClass = getLambdaClassFromConstantNode(cNode); - - if (lambdaClass != null) { - bigBang.getMetaAccess().lookupJavaType(lambdaClass); - } - } - } - - @Override - protected boolean loadMethod(PersistedAnalysisMethod.Reader methodData, int mid) { - WrappedMethod.Reader wrappedMethod = methodData.getWrappedMethod(); - if (wrappedMethod.isNone()) { - return false; - } - if (wrappedMethod.isFactoryMethod()) { - WrappedMethod.FactoryMethod.Reader fm = wrappedMethod.getFactoryMethod(); - AnalysisMethod analysisMethod = imageLayerLoader.getAnalysisMethodForBaseLayerId(fm.getTargetConstructorId()); - if (analysisMethod.wrapped instanceof BaseLayerMethod) { - return false; - } - AnalysisType instantiatedType = imageLayerLoader.getAnalysisTypeForBaseLayerId(fm.getInstantiatedTypeId()); - FactoryMethodSupport.singleton().lookup(imageLayerLoader.getMetaAccess(), analysisMethod, instantiatedType, fm.getThrowAllocatedObject()); - return true; - } else if (wrappedMethod.isCEntryPointCallStub()) { - WrappedMethod.CEntryPointCallStub.Reader stub = wrappedMethod.getCEntryPointCallStub(); - boolean asNotPublished = stub.getNotPublished(); - AnalysisMethod originalMethod = imageLayerLoader.getAnalysisMethodForBaseLayerId(stub.getOriginalMethodId()); - CEntryPointCallStubSupport.singleton().registerStubForMethod(originalMethod, () -> { - CEntryPointData data = CEntryPointData.create(originalMethod); - if (asNotPublished) { - data = data.copyWithPublishAs(CEntryPoint.Publish.NotPublished); - } - return data; - }); - return true; - } else if (wrappedMethod.isWrappedMember()) { - WrappedMember.Reader wm = wrappedMethod.getWrappedMember(); - Executable member = getWrappedMember(wm); - if (member == null) { - return false; - } - if (wm.isReflectionExpandSignature()) { - ImageSingletons.lookup(ReflectionFeature.class).getOrCreateAccessor(member); - } else if (wm.isJavaCallVariantWrapper()) { - JNIAccessFeature.singleton().addMethod(member, (FeatureImpl.DuringAnalysisAccessImpl) imageLayerLoader.getUniverse().getConcurrentAnalysisAccess()); - } - return true; - } - return super.loadMethod(methodData, mid); - } - - private Executable getWrappedMember(WrappedMember.Reader memberData) { - String className = memberData.getDeclaringClassName().toString(); - Class declaringClass = imageLayerLoader.lookupClass(true, className); - if (declaringClass == null) { - return null; - } - String name = memberData.getName().toString(); - Class[] parameters = StreamSupport.stream(memberData.getArgumentTypeNames().spliterator(), false).map(Text.Reader::toString) - .map(c -> imageLayerLoader.lookupClass(false, c)).toArray(Class[]::new); - return ImageLayerLoader.lookupMethodByReflection(name, declaringClass, parameters); - } -} 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 deleted file mode 100644 index 3624a610eb3e..000000000000 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java +++ /dev/null @@ -1,506 +0,0 @@ -/* - * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.hosted.heap; - -import static com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ClassInitializationInfo.Builder; - -import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; -import java.util.Collection; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.IntFunction; - -import org.capnproto.PrimitiveList; -import org.capnproto.StructList; -import org.capnproto.Text; -import org.capnproto.TextList; -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.MapCursor; -import org.graalvm.nativeimage.AnnotationAccess; -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.c.function.RelocatedPointer; -import org.graalvm.nativeimage.impl.CEntryPointLiteralCodePointer; - -import com.oracle.graal.pointsto.BigBang; -import com.oracle.graal.pointsto.api.HostVM; -import com.oracle.graal.pointsto.heap.ImageHeapConstant; -import com.oracle.graal.pointsto.heap.ImageLayerWriter; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonKey; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonObject; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.KeyStoreEntry; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisField; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant; -import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.util.AnalysisError; -import com.oracle.svm.core.FunctionPointerHolder; -import com.oracle.svm.core.StaticFieldsSupport; -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.classinitialization.ClassInitializationInfo; -import com.oracle.svm.core.hub.DynamicHub; -import com.oracle.svm.core.layeredimagesingleton.ImageSingletonWriter; -import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton; -import com.oracle.svm.core.layeredimagesingleton.RuntimeOnlyWrapper; -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.annotation.AnnotationMemberValue; -import com.oracle.svm.hosted.annotation.AnnotationMetadata; -import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; -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.HostedDynamicLayerInfo; -import com.oracle.svm.hosted.lambda.LambdaSubstitutionType; -import com.oracle.svm.hosted.lambda.StableLambdaProxyNameFeature; -import com.oracle.svm.hosted.meta.HostedField; -import com.oracle.svm.hosted.meta.HostedMethod; -import com.oracle.svm.hosted.meta.HostedUniverse; -import com.oracle.svm.hosted.meta.RelocatableConstant; -import com.oracle.svm.hosted.methodhandles.MethodHandleFeature; -import com.oracle.svm.hosted.methodhandles.MethodHandleInvokerSubstitutionType; -import com.oracle.svm.hosted.reflect.proxy.ProxyRenamingSubstitutionProcessor; -import com.oracle.svm.hosted.reflect.proxy.ProxySubstitutionType; -import com.oracle.svm.util.LogUtils; -import com.oracle.svm.util.ModuleSupport; - -import jdk.graal.compiler.core.common.NumUtil; -import jdk.graal.compiler.debug.Assertions; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; -import sun.reflect.annotation.AnnotationType; - -public class SVMImageLayerWriter extends ImageLayerWriter { - private NativeImageHeap nativeImageHeap; - private HostedUniverse hUniverse; - - public SVMImageLayerWriter(boolean useSharedLayerGraphs, boolean useSharedLayerStrengthenedGraphs) { - super(useSharedLayerGraphs, useSharedLayerStrengthenedGraphs); - } - - public void setNativeImageHeap(NativeImageHeap nativeImageHeap) { - this.nativeImageHeap = nativeImageHeap; - } - - public void setHostedUniverse(HostedUniverse hUniverse) { - this.hUniverse = hUniverse; - } - - @Override - protected void persistAnnotationValues(AnnotatedElement annotatedElement, Class annotationClass, IntFunction> builder) { - Annotation annotation = AnnotationAccess.getAnnotation(annotatedElement, annotationClass); - persistAnnotationValues(annotation, annotationClass, builder); - } - - private void persistAnnotationValues(Annotation annotation, Class annotationClass, IntFunction> builder) { - AnnotationType annotationType = AnnotationType.getInstance(annotationClass); - EconomicMap members = EconomicMap.create(); - annotationType.members().forEach((memberName, memberAccessor) -> { - try { - String moduleName = memberAccessor.getDeclaringClass().getModule().getName(); - if (moduleName != null) { - ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, SVMImageLayerWriter.class, false, moduleName); - } - AnnotationMemberValue memberValue = AnnotationMemberValue.getMemberValue(annotation, memberName, memberAccessor, annotationType); - Object value = memberValue.get(annotationType.memberTypes().get(memberName)); - members.put(memberName, value); - } catch (AnnotationMetadata.AnnotationExtractionError e) { - /* We skip the incorrect annotation */ - } - }); - if (!members.isEmpty()) { - var list = builder.apply(members.size()); - MapCursor cursor = members.getEntries(); - for (int i = 0; cursor.advance(); i++) { - var b = list.get(i); - b.setName(cursor.getKey()); - Object v = cursor.getValue(); - persistAnnotationValue(v, b); - } - } - } - - private void persistAnnotationValue(Object v, AnnotationValue.Builder b) { - if (v.getClass().isArray()) { - if (v instanceof Object[] array) { - var ba = b.initMembers(); - ba.setClassName(v.getClass().getComponentType().getName()); - var bav = ba.initMemberValues(array.length); - for (int i = 0; i < array.length; ++i) { - persistAnnotationValue(array[i], bav.get(i)); - } - } else { - Class componentType = v.getClass().getComponentType(); - assert componentType.isPrimitive() : v + " should be a primitive array"; - persistConstantPrimitiveArray(b.initPrimitiveArray(), JavaKind.fromJavaClass(componentType), v); - } - } else { - switch (v) { - case Boolean z -> setAnnotationPrimitiveValue(b, JavaKind.Boolean, z ? 1L : 0L); - case Byte z -> setAnnotationPrimitiveValue(b, JavaKind.Byte, z); - case Short s -> setAnnotationPrimitiveValue(b, JavaKind.Short, s); - case Character c -> setAnnotationPrimitiveValue(b, JavaKind.Char, c); - case Integer i -> setAnnotationPrimitiveValue(b, JavaKind.Int, i); - case Float f -> setAnnotationPrimitiveValue(b, JavaKind.Float, Float.floatToRawIntBits(f)); - case Long j -> setAnnotationPrimitiveValue(b, JavaKind.Long, j); - case Double d -> setAnnotationPrimitiveValue(b, JavaKind.Double, Double.doubleToRawLongBits(d)); - case Class clazz -> b.setClassName(clazz.getName()); - case Annotation innerAnnotation -> - persistAnnotationValues(innerAnnotation, innerAnnotation.annotationType(), b.initAnnotation()::initValues); - case String s -> b.setString(s); - case Enum e -> { - var ba = b.initEnum(); - ba.setClassName(e.getDeclaringClass().getName()); - ba.setName(e.name()); - } - default -> throw AnalysisError.shouldNotReachHere("Unknown annotation value: " + v); - } - } - } - - private static void setAnnotationPrimitiveValue(AnnotationValue.Builder b, JavaKind kind, long rawValue) { - var pv = b.initPrimitive(); - pv.setTypeChar(NumUtil.safeToUByte(kind.getTypeChar())); - pv.setRawValue(rawValue); - } - - @Override - protected void persistHook() { - ImageHeapConstant staticPrimitiveFields = (ImageHeapConstant) hUniverse.getSnippetReflection().forObject(StaticFieldsSupport.getStaticPrimitiveFields()); - ImageHeapConstant staticObjectFields = (ImageHeapConstant) hUniverse.getSnippetReflection().forObject(StaticFieldsSupport.getStaticObjectFields()); - - snapshotBuilder.setStaticPrimitiveFieldsConstantId(getConstantId(staticPrimitiveFields)); - snapshotBuilder.setStaticObjectFieldsConstantId(getConstantId(staticObjectFields)); - } - - @Override - protected void persistType(AnalysisType type, String typeDescriptor, PersistedAnalysisType.Builder builder) { - HostVM hostVM = aUniverse.hostVM(); - SVMHost svmHost = (SVMHost) hostVM; - DynamicHub hub = svmHost.dynamicHub(type); - builder.setHubIdentityHashCode(System.identityHashCode(hub)); - - builder.setIsInitializedAtBuildTime(ClassInitializationSupport.singleton().maybeInitializeAtBuildTime(type)); - - ClassInitializationInfo info = hub.getClassInitializationInfo(); - if (info != null) { - Builder b = builder.initClassInitializationInfo(); - b.setIsNoInitializerNoTracking(info == ClassInitializationInfo.forNoInitializerInfo(false)); - b.setIsInitializedNoTracking(info == ClassInitializationInfo.forInitializedInfo(false)); - b.setIsFailedNoTracking(info == ClassInitializationInfo.forFailedInfo(false)); - b.setIsInitialized(info.isInitialized()); - b.setIsInErrorState(info.isInErrorState()); - b.setIsLinked(info.isLinked()); - b.setHasInitializer(info.hasInitializer()); - b.setIsBuildTimeInitialized(info.isBuildTimeInitialized()); - b.setIsTracked(info.isTracked()); - FunctionPointerHolder classInitializer = info.getClassInitializer(); - if (classInitializer != null) { - MethodPointer methodPointer = (MethodPointer) classInitializer.functionPointer; - AnalysisMethod classInitializerMethod = (AnalysisMethod) methodPointer.getMethod(); - b.setInitializerMethodId(classInitializerMethod.getId()); - } - } - - super.persistType(type, typeDescriptor, builder); - } - - /** - * Some types can have an unstable name between two different image builds. To avoid producing - * wrong results, a warning should be printed if such types exist in the resulting image. - */ - @Override - protected void afterTypeAdded(AnalysisType type) { - /* - * Lambda functions containing the same method invocations will return the same hash. They - * will still have a different name, but in a multi threading context, the names can be - * switched. - */ - if (type.getWrapped() instanceof LambdaSubstitutionType lambdaSubstitutionType) { - StableLambdaProxyNameFeature stableLambdaProxyNameFeature = ImageSingletons.lookup(StableLambdaProxyNameFeature.class); - if (!stableLambdaProxyNameFeature.getLambdaSubstitutionProcessor().isNameAlwaysStable(lambdaSubstitutionType.getName())) { - String message = "The lambda method " + lambdaSubstitutionType.getName() + " might not have a stable name in the extension image."; - handleNameConflict(message); - } - } - /* - * Method handle with the same inner method handles will return the same hash. They will - * still have a different name, but in a multi threading context, the names can be switched. - */ - if (type.getWrapped() instanceof MethodHandleInvokerSubstitutionType methodHandleSubstitutionType) { - MethodHandleFeature methodHandleFeature = ImageSingletons.lookup(MethodHandleFeature.class); - if (!methodHandleFeature.getMethodHandleSubstitutionProcessor().isNameAlwaysStable(methodHandleSubstitutionType.getName())) { - String message = "The method handle " + methodHandleSubstitutionType.getName() + " might not have a stable name in the extension image."; - handleNameConflict(message); - } - } - - if (type.getWrapped() instanceof ProxySubstitutionType proxySubstitutionType) { - if (!ProxyRenamingSubstitutionProcessor.isNameAlwaysStable(proxySubstitutionType.getName())) { - String message = "The Proxy type " + proxySubstitutionType.getName() + " might not have a stable name in the extension image."; - handleNameConflict(message); - } - } - - super.afterTypeAdded(type); - } - - private static void handleNameConflict(String message) { - if (SubstrateOptions.AbortOnNameConflict.getValue()) { - throw VMError.shouldNotReachHere(message); - } else { - LogUtils.warning(message); - } - } - - @Override - protected void scanConstantReferencedObjects(ImageHeapConstant constant, Object[] referencedObjects, Collection discoveredConstants) { - if (referencedObjects != null) { - for (Object obj : referencedObjects) { - if (obj instanceof MethodPointer mp) { - getRelocatableConstantMethod(mp).registerAsTrackedAcrossLayers("In method pointer"); - } - } - } - super.scanConstantReferencedObjects(constant, referencedObjects, discoveredConstants); - } - - @Override - protected void persistMethod(AnalysisMethod method, PersistedAnalysisMethod.Builder builder) { - super.persistMethod(method, builder); - - // register this method as persisted for name resolution - HostedDynamicLayerInfo.singleton().recordPersistedMethod(hUniverse.lookup(method)); - } - - @Override - protected void persistField(AnalysisField field, PersistedAnalysisField.Builder builder) { - HostedField hostedField = hUniverse.lookup(field); - int location = hostedField.getLocation(); - if (location > 0) { - builder.setLocation(location); - } - Integer fieldCheckIndex = StaticFinalFieldFoldingFeature.singleton().getFieldCheckIndex(field); - builder.setFieldCheckIndex((fieldCheckIndex != null) ? fieldCheckIndex : -1); - super.persistField(field, builder); - } - - @Override - protected void persistConstant(ImageHeapConstant imageHeapConstant, ConstantParent parent, PersistedConstant.Builder builder, Set constantsToRelink) { - ObjectInfo objectInfo = nativeImageHeap.getConstantInfo(imageHeapConstant); - builder.setObjectOffset((objectInfo == null) ? -1 : objectInfo.getOffset()); - super.persistConstant(imageHeapConstant, parent, builder, constantsToRelink); - } - - @Override - protected void persistConstantRelinkingInfo(PersistedConstant.Object.Relinking.Builder builder, BigBang bb, Class clazz, JavaConstant hostedObject, int id, Set constantsToRelink) { - ResolvedJavaType type = bb.getConstantReflectionProvider().asJavaType(hostedObject); - if (type instanceof AnalysisType analysisType) { - builder.initClassConstant().setTypeId(analysisType.getId()); - constantsToRelink.add(id); - } else { - super.persistConstantRelinkingInfo(builder, bb, clazz, hostedObject, id, constantsToRelink); - } - } - - @Override - protected boolean delegateProcessing(SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference.Builder builder, Object constant) { - if (constant instanceof RelocatableConstant relocatableConstant) { - RelocatedPointer pointer = relocatableConstant.getPointer(); - if (pointer instanceof MethodPointer methodPointer) { - AnalysisMethod method = getRelocatableConstantMethod(methodPointer); - builder.initMethodPointer().setMethodId(method.getId()); - return true; - } else if (pointer instanceof CEntryPointLiteralCodePointer cp) { - CEntryPointLiteralReference.Builder b = builder.initCEntryPointLiteralCodePointer(); - b.setMethodName(cp.methodName); - b.setDefiningClass(cp.definingClass.getName()); - b.initParameterNames(cp.parameterTypes.length); - for (int i = 0; i < cp.parameterTypes.length; i++) { - b.getParameterNames().set(i, new Text.Reader(cp.parameterTypes[i].getName())); - } - return true; - } - } - return super.delegateProcessing(builder, constant); - } - - private static AnalysisMethod getRelocatableConstantMethod(MethodPointer methodPointer) { - ResolvedJavaMethod method = methodPointer.getMethod(); - if (method instanceof HostedMethod hostedMethod) { - return hostedMethod.wrapped; - } else { - return (AnalysisMethod) method; - } - } - - record SingletonPersistInfo(LayeredImageSingleton.PersistFlags flags, int id, EconomicMap keyStore) { - } - - public void writeImageSingletonInfo(List, Object>> layeredImageSingletons) { - StructList.Builder singletonsBuilder = snapshotBuilder.initSingletonKeys(layeredImageSingletons.size()); - Map singletonInfoMap = new HashMap<>(); - int nextID = 1; - for (int i = 0; i < layeredImageSingletons.size(); i++) { - var singletonInfo = layeredImageSingletons.get(i); - LayeredImageSingleton singleton; - if (singletonInfo.getValue() instanceof RuntimeOnlyWrapper wrapper) { - singleton = wrapper.wrappedObject(); - } else { - singleton = (LayeredImageSingleton) singletonInfo.getValue(); - } - String key = singletonInfo.getKey().getName(); - if (!singletonInfoMap.containsKey(singleton)) { - var writer = new ImageSingletonWriterImpl(); - var flags = singleton.preparePersist(writer); - boolean persistData = flags == LayeredImageSingleton.PersistFlags.CREATE; - var info = new SingletonPersistInfo(flags, persistData ? nextID++ : -1, persistData ? writer.getKeyValueStore() : null); - singletonInfoMap.put(singleton, info); - } - var info = singletonInfoMap.get(singleton); - - ImageSingletonKey.Builder sb = singletonsBuilder.get(i); - sb.setKeyClassName(key); - sb.setObjectId(info.id); - sb.setPersistFlag(info.flags.ordinal()); - } - - var sortedByIDs = singletonInfoMap.entrySet().stream() - .filter(e -> e.getValue().flags == LayeredImageSingleton.PersistFlags.CREATE) - .sorted(Comparator.comparingInt(e -> e.getValue().id)) - .toList(); - StructList.Builder objectsBuilder = snapshotBuilder.initSingletonObjects(sortedByIDs.size()); - for (int i = 0; i < sortedByIDs.size(); i++) { - var entry = sortedByIDs.get(i); - var info = entry.getValue(); - - ImageSingletonObject.Builder ob = objectsBuilder.get(i); - ob.setId(info.id); - ob.setClassName(entry.getKey().getClass().getName()); - writeImageSingletonKeyStore(ob, info.keyStore); - } - } - - private static void writeImageSingletonKeyStore(ImageSingletonObject.Builder objectData, EconomicMap keyStore) { - StructList.Builder lb = objectData.initStore(keyStore.size()); - MapCursor cursor = keyStore.getEntries(); - for (int i = 0; cursor.advance(); i++) { - KeyStoreEntry.Builder b = lb.get(i); - b.setKey(cursor.getKey()); - switch (cursor.getValue()) { - case Integer iv -> b.getValue().setI(iv); - case Long jv -> b.getValue().setJ(jv); - case String str -> b.getValue().setStr(str); - case int[] il -> { - PrimitiveList.Int.Builder ilb = b.getValue().initIl(il.length); - for (int j = 0; j < il.length; j++) { - ilb.set(j, il[j]); - } - } - case String[] strl -> { - TextList.Builder strlb = b.getValue().initStrl(strl.length); - for (int j = 0; j < strl.length; j++) { - strlb.set(j, new Text.Reader(strl[j])); - } - } - case boolean[] zl -> { - PrimitiveList.Boolean.Builder zlb = b.getValue().initZl(zl.length); - for (int j = 0; j < zl.length; j++) { - zlb.set(j, zl[j]); - } - } - default -> throw new IllegalStateException("Unexpected type: " + cursor.getValue()); - } - } - } -} - -class ImageSingletonWriterImpl implements ImageSingletonWriter { - private final EconomicMap keyValueStore = EconomicMap.create(); - - EconomicMap getKeyValueStore() { - return keyValueStore; - } - - private static boolean nonNullEntries(List list) { - return list.stream().filter(Objects::isNull).findAny().isEmpty(); - } - - @Override - public void writeBoolList(String keyName, List value) { - assert nonNullEntries(value); - boolean[] b = new boolean[value.size()]; - for (int i = 0; i < value.size(); i++) { - b[i] = value.get(i); - } - var previous = keyValueStore.put(keyName, b); - assert previous == null : Assertions.errorMessage(keyName, previous); - } - - @Override - public void writeInt(String keyName, int value) { - var previous = keyValueStore.put(keyName, value); - assert previous == null : previous; - } - - @Override - public void writeIntList(String keyName, List value) { - assert nonNullEntries(value); - var previous = keyValueStore.put(keyName, value.stream().mapToInt(i -> i).toArray()); - assert previous == null : Assertions.errorMessage(keyName, previous); - } - - @Override - public void writeLong(String keyName, long value) { - var previous = keyValueStore.put(keyName, value); - assert previous == null : Assertions.errorMessage(keyName, previous); - } - - @Override - public void writeString(String keyName, String value) { - var previous = keyValueStore.put(keyName, value); - assert previous == null : Assertions.errorMessage(keyName, previous); - } - - @Override - public void writeStringList(String keyName, List value) { - assert nonNullEntries(value); - var previous = keyValueStore.put(keyName, value.toArray(String[]::new)); - assert previous == null : Assertions.errorMessage(keyName, previous); - } -} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriterHelper.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriterHelper.java deleted file mode 100644 index 9f02e89b8221..000000000000 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriterHelper.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.hosted.heap; - -import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CONSTRUCTOR_NAME; -import static com.oracle.svm.hosted.heap.SVMImageLayerSnapshotUtil.GENERATED_SERIALIZATION; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Executable; -import java.lang.reflect.Parameter; - -import org.capnproto.Text; -import org.capnproto.TextList; -import org.capnproto.Void; - -import com.oracle.graal.pointsto.heap.ImageLayerWriter; -import com.oracle.graal.pointsto.heap.ImageLayerWriterHelper; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod.WrappedMethod; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType.WrappedType; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.svm.core.reflect.serialize.SerializationSupport; -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.jni.JNIJavaCallVariantWrapperMethod; -import com.oracle.svm.hosted.reflect.ReflectionExpandSignatureMethod; -import com.oracle.svm.hosted.reflect.proxy.ProxyRenamingSubstitutionProcessor; - -import jdk.graal.compiler.java.LambdaUtils; - -public class SVMImageLayerWriterHelper extends ImageLayerWriterHelper { - public SVMImageLayerWriterHelper(ImageLayerWriter imageLayerWriter) { - super(imageLayerWriter); - } - - @Override - protected void persistType(AnalysisType type, PersistedAnalysisType.Builder builder) { - if (type.toJavaName(true).contains(GENERATED_SERIALIZATION)) { - WrappedType.SerializationGenerated.Builder b = builder.getWrappedType().initSerializationGenerated(); - var key = SerializationSupport.singleton().getKeyFromConstructorAccessorClass(type.getJavaClass()); - b.setRawDeclaringClass(key.getDeclaringClass().getName()); - b.setRawTargetConstructor(key.getTargetConstructorClass().getName()); - } else if (LambdaUtils.isLambdaType(type)) { - WrappedType.Lambda.Builder b = builder.getWrappedType().initLambda(); - b.setCapturingClass(LambdaUtils.capturingClass(type.toJavaName())); - } else if (ProxyRenamingSubstitutionProcessor.isProxyType(type)) { - builder.getWrappedType().setProxyType(Void.VOID); - } - super.persistType(type, builder); - } - - @Override - protected void persistMethod(AnalysisMethod method, PersistedAnalysisMethod.Builder builder) { - if (method.wrapped instanceof FactoryMethod factoryMethod) { - WrappedMethod.FactoryMethod.Builder b = builder.getWrappedMethod().initFactoryMethod(); - AnalysisMethod targetConstructor = method.getUniverse().lookup(factoryMethod.getTargetConstructor()); - b.setTargetConstructorId(targetConstructor.getId()); - b.setThrowAllocatedObject(factoryMethod.throwAllocatedObject()); - AnalysisType instantiatedType = method.getUniverse().lookup(factoryMethod.getInstantiatedType()); - b.setInstantiatedTypeId(instantiatedType.getId()); - } else if (method.wrapped instanceof CEntryPointCallStubMethod cEntryPointCallStubMethod) { - WrappedMethod.CEntryPointCallStub.Builder b = builder.getWrappedMethod().initCEntryPointCallStub(); - AnalysisMethod originalMethod = CEntryPointCallStubSupport.singleton().getMethodForStub(cEntryPointCallStubMethod); - b.setOriginalMethodId(originalMethod.getId()); - b.setNotPublished(cEntryPointCallStubMethod.isNotPublished()); - } else if (method.wrapped instanceof ReflectionExpandSignatureMethod reflectionExpandSignatureMethod) { - WrappedMethod.WrappedMember.Builder b = builder.getWrappedMethod().initWrappedMember(); - b.setReflectionExpandSignature(Void.VOID); - Executable member = reflectionExpandSignatureMethod.getMember(); - persistWrappedMember(b, member); - } else if (method.wrapped instanceof JNIJavaCallVariantWrapperMethod jniJavaCallVariantWrapperMethod) { - WrappedMethod.WrappedMember.Builder b = builder.getWrappedMethod().initWrappedMember(); - b.setJavaCallVariantWrapper(Void.VOID); - Executable executable = jniJavaCallVariantWrapperMethod.getMember(); - persistWrappedMember(b, executable); - } - super.persistMethod(method, builder); - } - - @Override - public void onTrackedAcrossLayer(AnalysisMethod method, Object reason) { - if (method.wrapped instanceof FactoryMethod factoryMethod) { - AnalysisMethod targetConstructor = method.getUniverse().lookup(factoryMethod.getTargetConstructor()); - targetConstructor.registerAsTrackedAcrossLayers(reason); - } - super.onTrackedAcrossLayer(method, reason); - } - - private static void persistWrappedMember(WrappedMethod.WrappedMember.Builder b, Executable member) { - b.setName(member instanceof Constructor ? CONSTRUCTOR_NAME : member.getName()); - b.setDeclaringClassName(member.getDeclaringClass().getName()); - Parameter[] params = member.getParameters(); - TextList.Builder atb = b.initArgumentTypeNames(params.length); - for (int i = 0; i < params.length; i++) { - atb.set(i, new Text.Reader(params[i].getName())); - } - } -} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java index 1791478301fd..873876286db0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java @@ -647,9 +647,9 @@ private void addObjectToImageHeap(final JavaConstant constant, boolean immutable * elements, we only want the JavaConstant -> ObjectInfo mapping for base layer constants that * are reachable from regular constants in this layer. */ - private boolean processBaseLayerConstant(JavaConstant constant, ObjectInfo info) { + private static boolean processBaseLayerConstant(JavaConstant constant, ObjectInfo info) { if (((ImageHeapConstant) constant).isInBaseLayer()) { - info.setOffsetInPartition(aUniverse.getImageLayerLoader().getObjectOffset(constant)); + info.setOffsetInPartition(HostedImageLayerBuildingSupport.singleton().getLoader().getObjectOffset(constant)); info.setHeapPartition(BASE_LAYER_PARTITION); return true; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/CrossLayerConstantRegistryFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/CrossLayerConstantRegistryFeature.java index 8fba477a5e67..bffef42ff9e0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/CrossLayerConstantRegistryFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/CrossLayerConstantRegistryFeature.java @@ -36,7 +36,6 @@ import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.heap.ImageHeapRelocatableConstant; -import com.oracle.graal.pointsto.heap.ImageLayerLoader; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; @@ -67,7 +66,7 @@ private record FutureConstantCandidateInfo(ImageHeapRelocatableConstant constant ImageLayerIdTrackingSingleton tracker; boolean candidateRegistrySealed = false; boolean patchingSealed = false; - ImageLayerLoader loader; + SVMImageLayerLoader loader; Map constantCandidates; Map requiredConstants; @@ -112,7 +111,7 @@ public void afterRegistration(AfterRegistrationAccess access) { @Override public void duringSetup(DuringSetupAccess access) { var config = (FeatureImpl.DuringSetupAccessImpl) access; - loader = config.getUniverse().getImageLayerLoader(); + loader = HostedImageLayerBuildingSupport.singleton().getLoader(); LayeredImageHeapObjectAdder.singleton().registerObjectAdder(this::addInitialObjects); var registry = CrossLayerConstantRegistry.singletonOrNull(); config.registerObjectToConstantReplacer(obj -> replacePriorMarkersWithConstant(registry, obj)); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java index def07cdba99d..faabe5269d9d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java @@ -25,16 +25,22 @@ package com.oracle.svm.hosted.imagelayer; import java.io.File; +import java.io.IOException; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; import java.nio.file.Path; +import java.util.ArrayList; import java.util.List; +import org.capnproto.ReaderOptions; +import org.capnproto.Serialize; import org.graalvm.collections.EconomicMap; import org.graalvm.nativeimage.ImageSingletons; -import com.oracle.graal.pointsto.heap.ImageLayerLoader; -import com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil; +import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.svm.core.BuildArtifacts; import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.TypeResult; import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; import com.oracle.svm.core.option.AccumulatingLocatableMultiOptionValue; import com.oracle.svm.core.option.HostedOptionKey; @@ -46,8 +52,6 @@ import com.oracle.svm.hosted.ImageClassLoader; import com.oracle.svm.hosted.NativeImageGenerator; import com.oracle.svm.hosted.c.NativeLibraries; -import com.oracle.svm.hosted.heap.SVMImageLayerLoader; -import com.oracle.svm.hosted.heap.SVMImageLayerWriter; import com.oracle.svm.hosted.imagelayer.LayerOptionsSupport.ExtendedOption; import com.oracle.svm.hosted.imagelayer.LayerOptionsSupport.LayerOption; @@ -56,16 +60,27 @@ import jdk.graal.compiler.options.OptionValues; public final class HostedImageLayerBuildingSupport extends ImageLayerBuildingSupport { - private final SVMImageLayerLoader loader; - private final SVMImageLayerWriter writer; + private SVMImageLayerLoader loader; + private SVMImageLayerWriter writer; + private SVMImageLayerSingletonLoader singletonLoader; + private final ImageClassLoader imageClassLoader; + private final List snapshots; + private final List graphsChannels; private final WriteLayerArchiveSupport writeLayerArchiveSupport; private final LoadLayerArchiveSupport loadLayerArchiveSupport; - private HostedImageLayerBuildingSupport(SVMImageLayerLoader loader, SVMImageLayerWriter writer, boolean buildingImageLayer, boolean buildingInitialLayer, boolean buildingApplicationLayer, + public record FilePaths(Path snapshot, Path snapshotGraphs) { + } + + private HostedImageLayerBuildingSupport(SVMImageLayerSingletonLoader singletonLoader, ImageClassLoader imageClassLoader, + List snapshots, List graphsChannels, boolean buildingImageLayer, boolean buildingInitialLayer, + boolean buildingApplicationLayer, WriteLayerArchiveSupport writeLayerArchiveSupport, LoadLayerArchiveSupport loadLayerArchiveSupport) { super(buildingImageLayer, buildingInitialLayer, buildingApplicationLayer); - this.loader = loader; - this.writer = writer; + this.singletonLoader = singletonLoader; + this.imageClassLoader = imageClassLoader; + this.snapshots = snapshots; + this.graphsChannels = graphsChannels; this.writeLayerArchiveSupport = writeLayerArchiveSupport; this.loadLayerArchiveSupport = loadLayerArchiveSupport; } @@ -74,14 +89,30 @@ public static HostedImageLayerBuildingSupport singleton() { return (HostedImageLayerBuildingSupport) ImageSingletons.lookup(ImageLayerBuildingSupport.class); } + public SVMImageLayerSingletonLoader getSingletonLoader() { + return singletonLoader; + } + + public void setSingletonLoader(SVMImageLayerSingletonLoader singletonLoader) { + this.singletonLoader = singletonLoader; + } + public SVMImageLayerLoader getLoader() { return loader; } + public void setLoader(SVMImageLayerLoader loader) { + this.loader = loader; + } + public SVMImageLayerWriter getWriter() { return writer; } + public void setWriter(SVMImageLayerWriter writer) { + this.writer = writer; + } + public LoadLayerArchiveSupport getLoadLayerArchiveSupport() { return loadLayerArchiveSupport; } @@ -91,6 +122,26 @@ public void archiveLayer(String imageName) { writeLayerArchiveSupport.write(imageName); } + public SharedLayerSnapshotCapnProtoSchemaHolder.SharedLayerSnapshot.Reader getSnapshot() { + return snapshots.get(0); + } + + public FileChannel getGraphsChannel() { + return graphsChannels.get(0); + } + + public Class lookupClass(boolean optional, String className) { + TypeResult> typeResult = imageClassLoader.findClass(className); + if (!typeResult.isPresent()) { + if (optional) { + return null; + } else { + throw AnalysisError.shouldNotReachHere("Class not found: " + className); + } + } + return typeResult.get(); + } + /** * Process layer-create and layer-use options. The semantics of these options allow a user to * specify them any number of times, only the last instance wins. This processing cannot be done @@ -173,25 +224,48 @@ public static HostedImageLayerBuildingSupport initialize(HostedOptionValues valu } WriteLayerArchiveSupport writeLayerArchiveSupport = null; - SVMImageLayerWriter writer = null; ArchiveSupport archiveSupport = new ArchiveSupport(false); - Boolean useSharedLayerGraphs = SubstrateOptions.UseSharedLayerGraphs.getValue(values); - Boolean useSharedLayerStrengthenedGraphs = SubstrateOptions.UseSharedLayerStrengthenedGraphs.getValue(values); if (buildingSharedLayer) { LayerOption layerOption = LayerOption.parse(SubstrateOptions.LayerCreate.getValue(values).lastValue().orElseThrow()); writeLayerArchiveSupport = new WriteLayerArchiveSupport(archiveSupport, layerOption.fileName()); - writer = new SVMImageLayerWriter(useSharedLayerGraphs, useSharedLayerStrengthenedGraphs); } - SVMImageLayerLoader loader = null; + SVMImageLayerSingletonLoader singletonLoader = null; LoadLayerArchiveSupport loadLayerArchiveSupport = null; + List snapshots = null; + List graphsChannels = null; if (buildingExtensionLayer) { Path layerFileName = SubstrateOptions.LayerUse.getValue(values).lastValue().orElseThrow(); loadLayerArchiveSupport = new LoadLayerArchiveSupport(layerFileName, archiveSupport); - ImageLayerLoader.FilePaths paths = new ImageLayerLoader.FilePaths(loadLayerArchiveSupport.getSnapshotPath(), loadLayerArchiveSupport.getSnapshotGraphsPath()); - loader = new SVMImageLayerLoader(List.of(paths), imageClassLoader, useSharedLayerGraphs); + FilePaths filePaths = new FilePaths(loadLayerArchiveSupport.getSnapshotPath(), loadLayerArchiveSupport.getSnapshotGraphsPath()); + List loadPaths = List.of(filePaths); + snapshots = new ArrayList<>(); + graphsChannels = new ArrayList<>(); + for (FilePaths paths : loadPaths) { + try { + graphsChannels.add(FileChannel.open(paths.snapshotGraphs)); + + try (FileChannel ch = FileChannel.open(paths.snapshot)) { + MappedByteBuffer bb = ch.map(FileChannel.MapMode.READ_ONLY, ch.position(), ch.size()); + ReaderOptions opt = new ReaderOptions(Long.MAX_VALUE, ReaderOptions.DEFAULT_READER_OPTIONS.nestingLimit); + snapshots.add(Serialize.read(bb, opt).getRoot(SharedLayerSnapshotCapnProtoSchemaHolder.SharedLayerSnapshot.factory)); + // NOTE: buffer is never unmapped, but is read-only and pages can be evicted + } + } catch (IOException e) { + throw AnalysisError.shouldNotReachHere("Error during image layer snapshot loading", e); + } + } + + assert loadPaths.size() == 1 : "Currently only one path is supported for image layer loading " + loadPaths; + } + + HostedImageLayerBuildingSupport imageLayerBuildingSupport = new HostedImageLayerBuildingSupport(singletonLoader, imageClassLoader, snapshots, graphsChannels, buildingImageLayer, + buildingInitialLayer, buildingFinalLayer, writeLayerArchiveSupport, loadLayerArchiveSupport); + + if (buildingExtensionLayer) { + imageLayerBuildingSupport.setSingletonLoader(new SVMImageLayerSingletonLoader(imageLayerBuildingSupport, snapshots.get(0))); } - return new HostedImageLayerBuildingSupport(loader, writer, buildingImageLayer, buildingInitialLayer, buildingFinalLayer, writeLayerArchiveSupport, loadLayerArchiveSupport); + return imageLayerBuildingSupport; } @SuppressFBWarnings(value = "NP", justification = "FB reports null pointer dereferencing because it doesn't see through UserError.guarantee.") @@ -212,14 +286,14 @@ public static void setupSharedLayerLibrary(NativeLibraries nativeLibs) { public static void setupImageLayerArtifacts(String imageName) { VMError.guarantee(!imageName.contains(File.separator), "Expected simple file name, found %s.", imageName); - Path snapshotFile = NativeImageGenerator.getOutputDirectory().resolve(ImageLayerSnapshotUtil.snapshotFileName(imageName)); + Path snapshotFile = NativeImageGenerator.getOutputDirectory().resolve(SVMImageLayerSnapshotUtil.snapshotFileName(imageName)); Path snapshotFileName = getFileName(snapshotFile); - HostedImageLayerBuildingSupport.singleton().getWriter().setSnapshotFileInfo(snapshotFile, snapshotFileName.toString(), ImageLayerSnapshotUtil.FILE_EXTENSION); + HostedImageLayerBuildingSupport.singleton().getWriter().setSnapshotFileInfo(snapshotFile, snapshotFileName.toString(), SVMImageLayerSnapshotUtil.FILE_EXTENSION); BuildArtifacts.singleton().add(BuildArtifacts.ArtifactType.LAYER_SNAPSHOT, snapshotFile); - Path graphsFile = NativeImageGenerator.getOutputDirectory().resolve(ImageLayerSnapshotUtil.snapshotGraphsFileName(imageName)); + Path graphsFile = NativeImageGenerator.getOutputDirectory().resolve(SVMImageLayerSnapshotUtil.snapshotGraphsFileName(imageName)); Path graphsFileName = getFileName(graphsFile); - HostedImageLayerBuildingSupport.singleton().getWriter().openGraphsOutput(graphsFile, graphsFileName.toString(), ImageLayerSnapshotUtil.FILE_EXTENSION); + HostedImageLayerBuildingSupport.singleton().getWriter().openGraphsOutput(graphsFile, graphsFileName.toString(), SVMImageLayerSnapshotUtil.FILE_EXTENSION); BuildArtifacts.singleton().add(BuildArtifacts.ArtifactType.LAYER_SNAPSHOT_GRAPHS, graphsFile); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredDispatchTableSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredDispatchTableSupport.java index b02bb0d2cfb7..4488e54e5c85 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredDispatchTableSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredDispatchTableSupport.java @@ -63,7 +63,6 @@ import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.OpenTypeWorldFeature; import com.oracle.svm.hosted.SVMHost; -import com.oracle.svm.hosted.heap.SVMImageLayerWriter; import com.oracle.svm.hosted.image.NativeImage; import com.oracle.svm.hosted.image.NativeImageCodeCache; import com.oracle.svm.hosted.meta.HostedMetaAccess; @@ -496,7 +495,6 @@ public PersistFlags preparePersist(ImageSingletonWriter writer) { * To reduce redundancy, we maintain a separate table of all methods we refer to within the * dispatch tables. */ - SVMImageLayerWriter layerWriter = HostedImageLayerBuildingSupport.singleton().getWriter(); Map methodToOffsetMap = new HashMap<>(); List methodBooleans = new ArrayList<>(); List methodInts = new ArrayList<>(); @@ -508,7 +506,7 @@ public PersistFlags preparePersist(ImageSingletonWriter writer) { } else { offset = methodToOffsetMap.size(); methodToOffsetMap.put(hMethod, offset); - methodInts.add(layerWriter.isMethodPersisted(hMethod.getWrapped()) ? hMethod.wrapped.getId() : PriorDispatchMethod.UNKNOWN_ID); + methodInts.add(hMethod.getWrapped().isTrackedAcrossLayers() ? hMethod.wrapped.getId() : PriorDispatchMethod.UNKNOWN_ID); methodInts.add(hMethod.hasVTableIndex() ? hMethod.getVTableIndex() : PriorDispatchMethod.UNKNOWN_VTABLE_IDX); methodBooleans.add(virtualCallTargets.contains(hMethod)); methodStrings.add(NativeImage.localSymbolNameForMethod(hMethod)); @@ -526,7 +524,7 @@ public PersistFlags preparePersist(ImageSingletonWriter writer) { List dispatchSlotStrings = new ArrayList<>(); int nextSlotIdx = 0; for (HostedDispatchTable info : typeToDispatchTable.values()) { - if (!layerWriter.isTypePersisted(info.type.getWrapped())) { + if (!info.type.getWrapped().isTrackedAcrossLayers()) { // if a type contains target of a virtual call, then it should be persisted assert Arrays.stream(info.locallyDeclaredSlots).noneMatch(virtualCallTargets::contains) : "Type should be persisted: " + info.type; continue; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadImageSingletonFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadImageSingletonFeature.java index a8e1b6d810a9..853fa32e6cdc 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadImageSingletonFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadImageSingletonFeature.java @@ -68,7 +68,6 @@ import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.c.CGlobalDataFeature; -import com.oracle.svm.hosted.heap.SVMImageLayerLoader; import com.oracle.svm.hosted.image.NativeImageHeap; import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.hosted.meta.HostedUniverse; @@ -602,7 +601,7 @@ public PersistFlags preparePersist(ImageSingletonWriter writer) { @SuppressWarnings("unused") public static Object createFromLoader(ImageSingletonLoader loader) { - SVMImageLayerLoader imageLayerLoader = HostedImageLayerBuildingSupport.singleton().getLoader(); + SVMImageLayerSingletonLoader imageLayerLoader = HostedImageLayerBuildingSupport.singleton().getSingletonLoader(); Iterator keyClasses = loader.readStringList("keyClasses").iterator(); Iterator slotAssignments = loader.readIntList("slotAssignments").iterator(); Iterator slotKinds = loader.readStringList("slotKinds").iterator(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadLayerArchiveSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadLayerArchiveSupport.java index 6431886058bd..527d44abab13 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadLayerArchiveSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadLayerArchiveSupport.java @@ -28,7 +28,6 @@ import java.nio.file.Path; import java.util.concurrent.atomic.AtomicBoolean; -import com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil; import com.oracle.svm.core.util.ArchiveSupport; import com.oracle.svm.core.util.UserError; @@ -52,11 +51,11 @@ public Path getSharedLibraryPath() { } public Path getSnapshotPath() { - return expandedInputLayerDir.resolve(ImageLayerSnapshotUtil.snapshotFileName(layerProperties.layerName())); + return expandedInputLayerDir.resolve(SVMImageLayerSnapshotUtil.snapshotFileName(layerProperties.layerName())); } public Path getSnapshotGraphsPath() { - return expandedInputLayerDir.resolve(ImageLayerSnapshotUtil.snapshotGraphsFileName(layerProperties.layerName())); + return expandedInputLayerDir.resolve(SVMImageLayerSnapshotUtil.snapshotGraphsFileName(layerProperties.layerName())); } private static Path validateLayerFile(Path layerFile) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java similarity index 64% rename from substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java rename to substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java index 2155922c9719..4e7e93915249 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java @@ -22,55 +22,57 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.graal.pointsto.heap; +package com.oracle.svm.hosted.imagelayer; -import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CLASS_INIT_NAME; -import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CONSTRUCTOR_NAME; -import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.PERSISTED; import static com.oracle.graal.pointsto.util.AnalysisError.guarantee; +import static com.oracle.svm.hosted.imagelayer.SVMImageLayerSnapshotUtil.CLASS_INIT_NAME; +import static com.oracle.svm.hosted.imagelayer.SVMImageLayerSnapshotUtil.CONSTRUCTOR_NAME; +import static com.oracle.svm.hosted.imagelayer.SVMImageLayerSnapshotUtil.PERSISTED; +import static com.oracle.svm.hosted.lambda.LambdaParser.createMethodGraph; +import static com.oracle.svm.hosted.lambda.LambdaParser.getLambdaClassFromConstantNode; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Array; +import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Field; +import java.lang.reflect.Proxy; import java.nio.ByteBuffer; -import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; -import java.nio.file.Path; import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiConsumer; import java.util.function.Function; +import java.util.function.IntFunction; import java.util.function.Supplier; import java.util.function.ToIntFunction; import java.util.stream.IntStream; import java.util.stream.Stream; +import java.util.stream.StreamSupport; import org.capnproto.ListReader; import org.capnproto.PrimitiveList; -import org.capnproto.ReaderOptions; -import org.capnproto.Serialize; import org.capnproto.StructList; import org.capnproto.StructReader; import org.capnproto.Text; import org.capnproto.TextList; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.c.function.CEntryPoint; +import org.graalvm.nativeimage.impl.CEntryPointLiteralCodePointer; +import com.oracle.graal.pointsto.BigBang; +import com.oracle.graal.pointsto.api.ImageLayerLoader; import com.oracle.graal.pointsto.flow.AnalysisParsedGraph; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisField; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant.Object.Relinking.EnumConstant; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant.Object.Relinking.StringConstant; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue; -import com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.SharedLayerSnapshot; +import com.oracle.graal.pointsto.heap.HostedValuesProvider; +import com.oracle.graal.pointsto.heap.ImageHeapConstant; +import com.oracle.graal.pointsto.heap.ImageHeapInstance; +import com.oracle.graal.pointsto.heap.ImageHeapObjectArray; +import com.oracle.graal.pointsto.heap.ImageHeapPrimitiveArray; +import com.oracle.graal.pointsto.heap.ImageHeapRelocatableConstant; import com.oracle.graal.pointsto.heap.value.ValueSupplier; import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; import com.oracle.graal.pointsto.meta.AnalysisField; @@ -83,117 +85,145 @@ import com.oracle.graal.pointsto.meta.BaseLayerType; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.AnalysisFuture; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.classinitialization.ClassInitializationInfo; +import com.oracle.svm.core.graal.code.CGlobalDataInfo; +import com.oracle.svm.core.hub.DynamicHub; +import com.oracle.svm.core.meta.MethodPointer; +import com.oracle.svm.core.reflect.serialize.SerializationSupport; +import com.oracle.svm.hosted.FeatureImpl; +import com.oracle.svm.hosted.SVMHost; +import com.oracle.svm.hosted.c.CGlobalDataFeature; +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; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisField; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant; +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.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod.WrappedMethod; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod.WrappedMethod.WrappedMember; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType.WrappedType; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType.WrappedType.SerializationGenerated; +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.jni.JNIAccessFeature; +import com.oracle.svm.hosted.lambda.LambdaParser; +import com.oracle.svm.hosted.meta.HostedUniverse; +import com.oracle.svm.hosted.meta.RelocatableConstant; +import com.oracle.svm.hosted.reflect.ReflectionFeature; +import com.oracle.svm.hosted.reflect.serialize.SerializationFeature; +import com.oracle.svm.hosted.util.IdentityHashCodeUtil; +import com.oracle.svm.util.LogUtils; import com.oracle.svm.util.ReflectionUtil; import jdk.graal.compiler.core.common.NumUtil; import jdk.graal.compiler.core.common.SuppressFBWarnings; import jdk.graal.compiler.debug.GraalError; +import jdk.graal.compiler.graph.iterators.NodeIterable; +import jdk.graal.compiler.java.BytecodeParser; +import jdk.graal.compiler.nodes.ConstantNode; import jdk.graal.compiler.nodes.EncodedGraph; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.util.ObjectCopier; +import jdk.internal.reflect.ReflectionFactory; import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaMethodProfile; import jdk.vm.ci.meta.MethodHandleAccessProvider.IntrinsicMethod; import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; +import sun.reflect.annotation.AnnotationParser; -public class ImageLayerLoader { - private final Map types = new ConcurrentHashMap<>(); +public class SVMImageLayerLoader extends ImageLayerLoader { + private final Field dynamicHubArrayHubField; + private final boolean useSharedLayerGraphs; + private final SVMImageLayerSnapshotUtil imageLayerSnapshotUtil; + private final HostedImageLayerBuildingSupport imageLayerBuildingSupport; + private final SharedLayerSnapshot.Reader snapshot; + private final FileChannel graphsChannel; + + private HostedUniverse hostedUniverse; + + protected final Map types = new ConcurrentHashMap<>(); protected final Map methods = new ConcurrentHashMap<>(); protected final Map fields = new ConcurrentHashMap<>(); protected final Map constants = new ConcurrentHashMap<>(); - private final List loadPaths; + private final Map baseLayerTypes = new ConcurrentHashMap<>(); private final Map typeToHubIdentityHashCode = new ConcurrentHashMap<>(); private final Map baseLayerMethods = new ConcurrentHashMap<>(); private final Map baseLayerFields = new ConcurrentHashMap<>(); - /** Map from {@link ImageLayerSnapshotUtil#getTypeDescriptor} to base layer type ids. */ - private final Map typeDescriptorToBaseLayerId = new HashMap<>(); - /** Map from {@link ImageLayerSnapshotUtil#getMethodDescriptor} to base layer method ids. */ - private final Map methodDescriptorToBaseLayerId = new HashMap<>(); - protected final Set> heapScannerTasks = ConcurrentHashMap.newKeySet(); - private ImageLayerSnapshotUtil imageLayerSnapshotUtil; - private ImageLayerLoaderHelper imageLayerLoaderHelper; protected final Map typeToConstant = new ConcurrentHashMap<>(); protected final Map stringToConstant = new ConcurrentHashMap<>(); protected final Map, Integer> enumToConstant = new ConcurrentHashMap<>(); protected final Map objectOffsets = new ConcurrentHashMap<>(); protected final Map fieldLocations = new ConcurrentHashMap<>(); + private final Map, Boolean> capturingClasses = new ConcurrentHashMap<>(); + + /** Map from {@link SVMImageLayerSnapshotUtil#getTypeDescriptor} to base layer type ids. */ + private final Map typeDescriptorToBaseLayerId = new HashMap<>(); + /** Map from {@link SVMImageLayerSnapshotUtil#getMethodDescriptor} to base layer method ids. */ + private final Map methodDescriptorToBaseLayerId = new HashMap<>(); + protected AnalysisUniverse universe; protected AnalysisMetaAccess metaAccess; protected HostedValuesProvider hostedValuesProvider; - protected SharedLayerSnapshot.Reader snapshot; - protected FileChannel graphsChannel; - - public record FilePaths(Path snapshot, Path snapshotGraphs) { - } - - public ImageLayerLoader() { - this(List.of()); - } - - public ImageLayerLoader(List loadPaths) { - this.loadPaths = loadPaths; - } - - public void setImageLayerSnapshotUtil(ImageLayerSnapshotUtil imageLayerSnapshotUtil) { + public SVMImageLayerLoader(SVMImageLayerSnapshotUtil imageLayerSnapshotUtil, HostedImageLayerBuildingSupport imageLayerBuildingSupport, SharedLayerSnapshot.Reader snapshot, + FileChannel graphChannel, boolean useSharedLayerGraphs) { + dynamicHubArrayHubField = ReflectionUtil.lookupField(DynamicHub.class, "arrayHub"); this.imageLayerSnapshotUtil = imageLayerSnapshotUtil; + this.imageLayerBuildingSupport = imageLayerBuildingSupport; + this.snapshot = snapshot; + this.graphsChannel = graphChannel; + this.useSharedLayerGraphs = useSharedLayerGraphs; } public AnalysisUniverse getUniverse() { return universe; } - public void setUniverse(AnalysisUniverse newUniverse) { - this.universe = newUniverse; + public void setUniverse(AnalysisUniverse universe) { + this.universe = universe; } - public void setImageLayerLoaderHelper(ImageLayerLoaderHelper imageLayerLoaderHelper) { - this.imageLayerLoaderHelper = imageLayerLoaderHelper; + public AnalysisMetaAccess getMetaAccess() { + return metaAccess; } - /** This code is not thread safe. */ - protected void openFilesAndLoadJsonMap() { - assert loadPaths.size() == 1 : "Currently only one path is supported for image layer loading " + loadPaths; - if (snapshot == null) { - for (FilePaths paths : loadPaths) { - try { - graphsChannel = FileChannel.open(paths.snapshotGraphs); + public void setMetaAccess(AnalysisMetaAccess metaAccess) { + this.metaAccess = metaAccess; + } - try (FileChannel ch = FileChannel.open(paths.snapshot)) { - MappedByteBuffer bb = ch.map(FileChannel.MapMode.READ_ONLY, ch.position(), ch.size()); - ReaderOptions opt = new ReaderOptions(Long.MAX_VALUE, ReaderOptions.DEFAULT_READER_OPTIONS.nestingLimit); - snapshot = Serialize.read(bb, opt).getRoot(SharedLayerSnapshot.factory); - // NOTE: buffer is never unmapped, but is read-only and pages can be evicted - } - } catch (IOException e) { - throw AnalysisError.shouldNotReachHere("Error during image layer snapshot loading", e); - } - } - } + public void setHostedValuesProvider(HostedValuesProvider hostedValuesProvider) { + this.hostedValuesProvider = hostedValuesProvider; } - public void loadLayerAnalysis() { - openFilesAndLoadJsonMap(); - loadLayerAnalysis0(); + public HostedUniverse getHostedUniverse() { + return hostedUniverse; } - public void cleanupAfterCompilation() { - if (graphsChannel != null) { - try { - graphsChannel.close(); - } catch (IOException e) { - throw AnalysisError.shouldNotReachHere(e); - } - } + public void setHostedUniverse(HostedUniverse hostedUniverse) { + this.hostedUniverse = hostedUniverse; } - /** - * Initializes the {@link ImageLayerLoader}. - */ - private void loadLayerAnalysis0() { + public HostedImageLayerBuildingSupport getImageLayerBuildingSupport() { + return imageLayerBuildingSupport; + } + + public void loadLayerAnalysis() { /* * The new ids of the extension image need to be different from the ones from the base * layer. The start id is set to the next id of the base layer. @@ -217,6 +247,14 @@ private void loadLayerAnalysis0() { .forEach(c -> prepareConstantRelinking(c, c.getIdentityHashCode(), c.getId())); } + private static IntStream streamInts(PrimitiveList.Int.Reader reader) { + return IntStream.range(0, reader.size()).map(reader::get); + } + + private static Stream streamStrings(TextList.Reader reader) { + return IntStream.range(0, reader.size()).mapToObj(i -> reader.get(i).toString()); + } + private PersistedConstant.Reader findConstant(int id) { return binarySearchUnique(id, snapshot.getConstants(), PersistedConstant.Reader::getId); } @@ -248,13 +286,16 @@ private static T binarySearchUnique(int key, StructList return null; } - protected void prepareConstantRelinking(PersistedConstant.Reader constantData, int identityHashCode, int id) { + private void prepareConstantRelinking(PersistedConstant.Reader constantData, int identityHashCode, int id) { if (!constantData.isObject()) { return; } PersistedConstant.Object.Relinking.Reader relinking = constantData.getObject().getRelinking(); - if (relinking.isStringConstant()) { + if (relinking.isClassConstant()) { + int typeId = relinking.getClassConstant().getTypeId(); + typeToConstant.put(typeId, id); + } else if (relinking.isStringConstant()) { String value = relinking.getStringConstant().getValue().toString(); injectIdentityHashCode(value.intern(), identityHashCode); stringToConstant.put(value, id); @@ -266,10 +307,36 @@ protected void prepareConstantRelinking(PersistedConstant.Reader constantData, i } } + public void cleanupAfterCompilation() { + if (graphsChannel != null) { + try { + graphsChannel.close(); + } catch (IOException e) { + throw AnalysisError.shouldNotReachHere(e); + } + } + } + + public AnalysisType getAnalysisTypeForBaseLayerId(int tid) { + if (!types.containsKey(tid)) { + loadType(findType(tid)); + } + guarantee(types.containsKey(tid), "Type with id %d was not correctly loaded.", tid); + /* + * The type needs to be looked up because it ensures the type is completely created, as the + * types Map is populated before the type is created. + */ + return universe.lookup(types.get(tid).getWrapped()); + } + + private PersistedAnalysisType.Reader findType(int tid) { + return binarySearchUnique(tid, snapshot.getTypes(), PersistedAnalysisType.Reader::getId); + } + private void loadType(PersistedAnalysisType.Reader typeData) { int tid = typeData.getId(); - if (imageLayerLoaderHelper.loadType(typeData, tid)) { + if (delegateLoadType(typeData)) { return; } @@ -309,6 +376,123 @@ private void loadType(PersistedAnalysisType.Reader typeData) { } } + @SuppressWarnings("deprecation") + protected boolean delegateLoadType(PersistedAnalysisType.Reader typeData) { + WrappedType.Reader wrappedType = typeData.getWrappedType(); + if (wrappedType.isNone()) { + return false; + } + if (wrappedType.isSerializationGenerated()) { + SerializationGenerated.Reader sg = wrappedType.getSerializationGenerated(); + String rawDeclaringClassName = sg.getRawDeclaringClass().toString(); + String rawTargetConstructorClassName = sg.getRawTargetConstructor().toString(); + Class rawDeclaringClass = imageLayerBuildingSupport.lookupClass(false, rawDeclaringClassName); + Class rawTargetConstructorClass = imageLayerBuildingSupport.lookupClass(false, rawTargetConstructorClassName); + SerializationSupport serializationSupport = SerializationSupport.singleton(); + Constructor rawTargetConstructor = ReflectionUtil.lookupConstructor(rawTargetConstructorClass); + Constructor constructor = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(rawDeclaringClass, rawTargetConstructor); + serializationSupport.addConstructorAccessor(rawDeclaringClass, rawTargetConstructorClass, SerializationFeature.getConstructorAccessor(constructor)); + Class constructorAccessor = serializationSupport.getSerializationConstructorAccessor(rawDeclaringClass, rawTargetConstructorClass).getClass(); + metaAccess.lookupJavaType(constructorAccessor); + return true; + } else if (wrappedType.isLambda()) { + String capturingClassName = wrappedType.getLambda().getCapturingClass().toString(); + Class capturingClass = imageLayerBuildingSupport.lookupClass(false, capturingClassName); + loadLambdaTypes(capturingClass); + } else if (wrappedType.isProxyType()) { + Class[] interfaces = Stream.of(typeData.getInterfaces()).flatMapToInt(r -> IntStream.range(0, r.size()).map(r::get)) + .mapToObj(i -> getAnalysisTypeForBaseLayerId(i).getJavaClass()).toArray(Class[]::new); + /* GR-59854: The deprecation warning comes from this call to Proxy.getProxyClass. */ + Class proxy = Proxy.getProxyClass(interfaces[0].getClassLoader(), interfaces); + metaAccess.lookupJavaType(proxy); + return true; + } + return false; + } + + /** + * Load all lambda types of the given capturing class. Each method of the capturing class is + * parsed (see {@link LambdaParser#createMethodGraph(ResolvedJavaMethod, OptionValues)}). The + * lambda types can then be found in the constant nodes of the graphs. + */ + private void loadLambdaTypes(Class capturingClass) { + capturingClasses.computeIfAbsent(capturingClass, key -> { + LambdaParser.allExecutablesDeclaredInClass(universe.getOriginalMetaAccess().lookupJavaType(capturingClass)) + .filter(m -> m.getCode() != null) + .forEach(m -> loadLambdaTypes(m, universe.getBigbang())); + return true; + }); + } + + private static void loadLambdaTypes(ResolvedJavaMethod m, BigBang bigBang) { + StructuredGraph graph; + try { + graph = createMethodGraph(m, bigBang.getOptions()); + } catch (NoClassDefFoundError | BytecodeParser.BytecodeParserError e) { + /* Skip the method if it refers to a missing class */ + return; + } + + NodeIterable constantNodes = ConstantNode.getConstantNodes(graph); + + for (ConstantNode cNode : constantNodes) { + Class lambdaClass = getLambdaClassFromConstantNode(cNode); + + if (lambdaClass != null) { + bigBang.getMetaAccess().lookupJavaType(lambdaClass); + } + } + } + + private ResolvedJavaType getResolvedJavaTypeForBaseLayerId(int tid) { + return (tid == 0) ? null : getAnalysisTypeForBaseLayerId(tid).getWrapped(); + } + + /** + * 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. + */ + protected Class lookupBaseLayerTypeInHostVM(String type) { + int arrayType = 0; + String componentType = type; + /* + * We cannot look up an array type directly. We have to look up the component type and then + * go back to the array type. + */ + while (componentType.endsWith("[]")) { + componentType = componentType.substring(0, componentType.length() - 2); + arrayType++; + } + Class clazz = lookupPrimitiveClass(componentType); + if (clazz == null) { + clazz = imageLayerBuildingSupport.lookupClass(true, componentType); + } + if (clazz == null) { + return null; + } + while (arrayType > 0) { + assert clazz != null; + clazz = clazz.arrayType(); + arrayType--; + } + return clazz; + } + + private static Class lookupPrimitiveClass(String type) { + return switch (type) { + case "boolean" -> boolean.class; + case "byte" -> byte.class; + case "short" -> short.class; + case "char" -> char.class; + case "int" -> int.class; + case "long" -> long.class; + case "float" -> float.class; + case "double" -> double.class; + case "void" -> void.class; + default -> null; + }; + } + private BaseLayerType getBaseLayerType(int tid) { PersistedAnalysisType.Reader typeData = findType(tid); ResolvedJavaType superClass = getResolvedJavaTypeForBaseLayerId(typeData.getSuperClassTypeId()); @@ -330,43 +514,59 @@ private BaseLayerType getBaseLayerType(PersistedAnalysisType.Reader td, int tid, }); } - private static IntStream streamInts(PrimitiveList.Int.Reader reader) { - return IntStream.range(0, reader.size()).map(reader::get); - } - - private static Stream streamStrings(TextList.Reader reader) { - return IntStream.range(0, reader.size()).mapToObj(i -> reader.get(i).toString()); - } - - protected Annotation[] getAnnotations(@SuppressWarnings("unused") StructList.Reader elementData) { - return new Annotation[0]; - } - - private ResolvedJavaType getResolvedJavaTypeForBaseLayerId(int tid) { - return (tid == 0) ? null : getAnalysisTypeForBaseLayerId(tid).getWrapped(); - } - - public AnalysisType getAnalysisTypeForBaseLayerId(int tid) { - if (!types.containsKey(tid)) { - loadType(findType(tid)); - } - guarantee(types.containsKey(tid), "Type with id %d was not correctly loaded.", tid); - /* - * The type needs to be looked up because it ensures the type is completely created, as the - * types Map is populated before the type is created. - */ - return universe.lookup(types.get(tid).getWrapped()); + private Annotation[] getAnnotations(StructList.Reader reader) { + return IntStream.range(0, reader.size()).mapToObj(reader::get).map(this::getAnnotation).toArray(Annotation[]::new); } - protected PersistedAnalysisType.Reader findType(int tid) { - return binarySearchUnique(tid, snapshot.getTypes(), PersistedAnalysisType.Reader::getId); + private Annotation getAnnotation(SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.Reader a) { + String typeName = a.getTypeName().toString(); + Class annotationType = lookupBaseLayerTypeInHostVM(typeName).asSubclass(Annotation.class); + Map annotationValuesMap = new HashMap<>(); + a.getValues().forEach(v -> { + Object value = getAnnotationValue(v); + annotationValuesMap.put(v.getName().toString(), value); + }); + return AnnotationParser.annotationForMap(annotationType, annotationValuesMap); + } + + private Object getAnnotationValue(AnnotationValue.Reader v) { + return switch (v.which()) { + case STRING -> v.getString().toString(); + case ENUM -> getEnumValue(v.getEnum().getClassName(), v.getEnum().getName()); + case PRIMITIVE -> { + var p = v.getPrimitive(); + long rawValue = p.getRawValue(); + char typeChar = (char) p.getTypeChar(); + yield switch (JavaKind.fromPrimitiveOrVoidTypeChar(typeChar)) { + case Boolean -> rawValue != 0; + case Byte -> (byte) rawValue; + case Char -> (char) rawValue; + case Short -> (short) rawValue; + case Int -> (int) rawValue; + case Long -> rawValue; + case Float -> Float.intBitsToFloat((int) rawValue); + case Double -> Double.longBitsToDouble(rawValue); + default -> throw AnalysisError.shouldNotReachHere("Unknown annotation value type: " + typeChar); + }; + } + case PRIMITIVE_ARRAY -> getArray(v.getPrimitiveArray()); + case CLASS_NAME -> imageLayerBuildingSupport.lookupClass(false, v.getClassName().toString()); + case ANNOTATION -> getAnnotation(v.getAnnotation()); + case MEMBERS -> { + var m = v.getMembers(); + var mv = m.getMemberValues(); + Class membersClass = imageLayerBuildingSupport.lookupClass(false, m.getClassName().toString()); + var array = Array.newInstance(membersClass, mv.size()); + for (int i = 0; i < mv.size(); ++i) { + Array.set(array, i, getAnnotationValue(mv.get(i))); + } + yield array; + } + case _NOT_IN_SCHEMA -> throw AnalysisError.shouldNotReachHere("Unknown annotation value kind: " + v.which()); + }; } - /** - * Returns the type id of the given type in the base layer if it exists. This makes the link - * between the base layer and the extension layer as the id is used to determine which constant - * should be linked to this type. - */ + @Override public int lookupHostedTypeInBaseLayer(AnalysisType type) { int id = getBaseLayerTypeId(type); if (id == -1 || types.putIfAbsent(id, type) != null) { @@ -393,66 +593,47 @@ private int getBaseLayerTypeId(AnalysisType type) { return id; } + @Override public void initializeBaseLayerType(AnalysisType type) { int id = getBaseLayerTypeId(type); if (id == -1) { return; } PersistedAnalysisType.Reader td = findType(id); - registerFlag(td.getIsInstantiated(), true, () -> type.registerAsInstantiated(PERSISTED)); - registerFlag(td.getIsUnsafeAllocated(), true, () -> type.registerAsUnsafeAllocated(PERSISTED)); - registerFlag(td.getIsReachable(), true, () -> type.registerAsReachable(PERSISTED)); + registerFlag(td.getIsInstantiated(), () -> type.registerAsInstantiated(PERSISTED)); + registerFlag(td.getIsUnsafeAllocated(), () -> type.registerAsUnsafeAllocated(PERSISTED)); + registerFlag(td.getIsReachable(), () -> 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. - */ - public Class lookupBaseLayerTypeInHostVM(String type) { - int arrayType = 0; - String componentType = type; - /* - * We cannot look up an array type directly. We have to look up the component type and then - * go back to the array type. - */ - while (componentType.endsWith("[]")) { - componentType = componentType.substring(0, componentType.length() - 2); - arrayType++; - } - Class clazz = lookupPrimitiveClass(componentType); - if (clazz == null) { - clazz = lookupClass(true, componentType); - } - if (clazz == null) { - return null; + private void registerFlag(boolean flag, Runnable runnable) { + if (flag) { + if (universe.getBigbang() != null) { + universe.getBigbang().postTask(debug -> runnable.run()); + } else { + heapScannerTasks.add(new AnalysisFuture<>(runnable)); + } } - while (arrayType > 0) { - assert clazz != null; - clazz = clazz.arrayType(); - arrayType--; + } + + public AnalysisMethod getAnalysisMethodForBaseLayerId(int mid) { + if (!methods.containsKey(mid)) { + PersistedAnalysisMethod.Reader methodData = findMethod(mid); + loadMethod(methodData); } - return clazz; + + AnalysisMethod analysisMethod = methods.get(mid); + AnalysisError.guarantee(analysisMethod != null, "Method with id %d was not correctly loaded.", mid); + return analysisMethod; } - private static Class lookupPrimitiveClass(String type) { - return switch (type) { - case "boolean" -> boolean.class; - case "byte" -> byte.class; - case "short" -> short.class; - case "char" -> char.class; - case "int" -> int.class; - case "long" -> long.class; - case "float" -> float.class; - case "double" -> double.class; - case "void" -> void.class; - default -> null; - }; + private PersistedAnalysisMethod.Reader findMethod(int mid) { + return binarySearchUnique(mid, snapshot.getMethods(), PersistedAnalysisMethod.Reader::getId); } private void loadMethod(PersistedAnalysisMethod.Reader methodData) { int mid = methodData.getId(); - if (imageLayerLoaderHelper.loadMethod(methodData, mid)) { + if (delegateLoadMethod(methodData)) { return; } @@ -507,7 +688,61 @@ private void loadMethod(PersistedAnalysisMethod.Reader methodData) { } } - public static Executable lookupMethodByReflection(String name, Class clazz, Class[] argumentClasses) { + protected boolean delegateLoadMethod(PersistedAnalysisMethod.Reader methodData) { + WrappedMethod.Reader wrappedMethod = methodData.getWrappedMethod(); + if (wrappedMethod.isNone()) { + return false; + } + if (wrappedMethod.isFactoryMethod()) { + WrappedMethod.FactoryMethod.Reader fm = wrappedMethod.getFactoryMethod(); + AnalysisMethod analysisMethod = getAnalysisMethodForBaseLayerId(fm.getTargetConstructorId()); + if (analysisMethod.wrapped instanceof BaseLayerMethod) { + return false; + } + AnalysisType instantiatedType = getAnalysisTypeForBaseLayerId(fm.getInstantiatedTypeId()); + FactoryMethodSupport.singleton().lookup(metaAccess, analysisMethod, instantiatedType, fm.getThrowAllocatedObject()); + return true; + } else if (wrappedMethod.isCEntryPointCallStub()) { + WrappedMethod.CEntryPointCallStub.Reader stub = wrappedMethod.getCEntryPointCallStub(); + boolean asNotPublished = stub.getNotPublished(); + AnalysisMethod originalMethod = getAnalysisMethodForBaseLayerId(stub.getOriginalMethodId()); + CEntryPointCallStubSupport.singleton().registerStubForMethod(originalMethod, () -> { + CEntryPointData data = CEntryPointData.create(originalMethod); + if (asNotPublished) { + data = data.copyWithPublishAs(CEntryPoint.Publish.NotPublished); + } + return data; + }); + return true; + } else if (wrappedMethod.isWrappedMember()) { + WrappedMember.Reader wm = wrappedMethod.getWrappedMember(); + Executable member = getWrappedMember(wm); + if (member == null) { + return false; + } + if (wm.isReflectionExpandSignature()) { + ImageSingletons.lookup(ReflectionFeature.class).getOrCreateAccessor(member); + } else if (wm.isJavaCallVariantWrapper()) { + JNIAccessFeature.singleton().addMethod(member, (FeatureImpl.DuringAnalysisAccessImpl) universe.getConcurrentAnalysisAccess()); + } + return true; + } + return false; + } + + private Executable getWrappedMember(WrappedMethod.WrappedMember.Reader memberData) { + String className = memberData.getDeclaringClassName().toString(); + Class declaringClass = imageLayerBuildingSupport.lookupClass(true, className); + if (declaringClass == null) { + return null; + } + String name = memberData.getName().toString(); + Class[] parameters = StreamSupport.stream(memberData.getArgumentTypeNames().spliterator(), false).map(Text.Reader::toString) + .map(c -> imageLayerBuildingSupport.lookupClass(false, c)).toArray(Class[]::new); + return lookupMethodByReflection(name, declaringClass, parameters); + } + + private static Executable lookupMethodByReflection(String name, Class clazz, Class[] argumentClasses) { try { Executable method; if (name.equals(CONSTRUCTOR_NAME)) { @@ -537,28 +772,9 @@ private void createBaseLayerMethod(PersistedAnalysisMethod.Reader md, int mid, S universe.lookup(baseLayerMethod); } - public AnalysisMethod getAnalysisMethodForBaseLayerId(int mid) { - if (!methods.containsKey(mid)) { - PersistedAnalysisMethod.Reader methodData = findMethod(mid); - loadMethod(methodData); - } - - AnalysisMethod analysisMethod = methods.get(mid); - AnalysisError.guarantee(analysisMethod != null, "Method with id %d was not correctly loaded.", mid); - return analysisMethod; - } - - private PersistedAnalysisMethod.Reader findMethod(int mid) { - return binarySearchUnique(mid, snapshot.getMethods(), PersistedAnalysisMethod.Reader::getId); - } - - /** - * Returns the method id of the given method in the base layer if it exists. This makes the link - * between the base layer and the extension layer as the id is used to determine the method used - * in RelocatableConstants. - */ - public int lookupHostedMethodInBaseLayer(AnalysisMethod analysisMethod) { - return getBaseLayerMethodId(analysisMethod); + @Override + public int lookupHostedMethodInBaseLayer(AnalysisMethod analysisMethod) { + return getBaseLayerMethodId(analysisMethod); } private int getBaseLayerMethodId(AnalysisMethod analysisMethod) { @@ -576,28 +792,39 @@ private int getBaseLayerMethodId(AnalysisMethod analysisMethod) { return methodData.getId(); } + @Override public void addBaseLayerMethod(AnalysisMethod analysisMethod) { methods.putIfAbsent(analysisMethod.getId(), analysisMethod); - } - public void initializeBaseLayerMethod(AnalysisMethod analysisMethod) { PersistedAnalysisMethod.Reader md = getMethodData(analysisMethod); - registerFlag(md.getIsVirtualRootMethod(), true, () -> analysisMethod.registerAsVirtualRootMethod(PERSISTED)); - registerFlag(md.getIsDirectRootMethod(), true, () -> analysisMethod.registerAsDirectRootMethod(PERSISTED)); - registerFlag(md.getIsInvoked(), true, () -> analysisMethod.registerAsInvoked(PERSISTED)); - registerFlag(md.getIsImplementationInvoked(), true, () -> analysisMethod.registerAsImplementationInvoked(PERSISTED)); - registerFlag(md.getIsIntrinsicMethod(), true, () -> analysisMethod.registerAsIntrinsicMethod(PERSISTED)); + registerFlag(md.getIsVirtualRootMethod(), () -> analysisMethod.registerAsVirtualRootMethod(PERSISTED)); + registerFlag(md.getIsDirectRootMethod(), () -> analysisMethod.registerAsDirectRootMethod(PERSISTED)); + registerFlag(md.getIsInvoked(), () -> analysisMethod.registerAsInvoked(PERSISTED)); + registerFlag(md.getIsImplementationInvoked(), () -> analysisMethod.registerAsImplementationInvoked(PERSISTED)); + registerFlag(md.getIsIntrinsicMethod(), () -> analysisMethod.registerAsIntrinsicMethod(PERSISTED)); + } + + private PersistedAnalysisMethod.Reader getMethodData(AnalysisMethod analysisMethod) { + if (analysisMethod.getWrapped() instanceof BaseLayerMethod m) { + return findMethod(m.getBaseLayerId()); + } + String descriptor = imageLayerSnapshotUtil.getMethodDescriptor(analysisMethod); + Integer id = methodDescriptorToBaseLayerId.get(descriptor); + return (id != null) ? findMethod(id) : null; } /** - * Currently we save analysis parsed graphs for methods considered - * {@link AnalysisMethod#isTrackedAcrossLayers()}. See - * {@link ImageLayerWriter#persistAnalysisParsedGraph} for implementation. + * See {@link SVMImageLayerWriter#persistAnalysisParsedGraphs()} for implementation. */ + @Override public boolean hasAnalysisParsedGraph(AnalysisMethod analysisMethod) { + if (!useSharedLayerGraphs) { + return false; + } return hasGraph(analysisMethod, PersistedAnalysisMethod.Reader::hasAnalysisGraphLocation); } + @Override public AnalysisParsedGraph getAnalysisParsedGraph(AnalysisMethod analysisMethod) { PersistedAnalysisMethod.Reader methodData = getMethodData(analysisMethod); boolean intrinsic = methodData.getAnalysisGraphIsIntrinsic(); @@ -622,9 +849,15 @@ private boolean hasGraph(AnalysisMethod analysisMethod, Function valuesFunction, int size) { PersistedConstant.Reader baseLayerConstant = findConstant(ImageHeapConstant.getConstantID(constant)); if (baseLayerConstant != null) { StructList.Reader data = baseLayerConstant.getObject().getData(); + assert size == data.size() : "The size of the constant in the base layer does not match the size in the application: %d != %d".formatted(data.size(), size); for (int i = 0; i < data.size(); ++i) { ConstantReference.Reader childConstant = data.get(i); if (childConstant.isObjectConstant()) { if (childConstant.isNotMaterialized()) { continue; } - loadMaterializedChild(values[i]); + loadMaterializedChild(valuesFunction.apply(i)); } } } @@ -708,17 +943,18 @@ private void loadMaterializedChild(Object child) { } } - protected static int getId(String line) { - return Integer.parseInt(line.split(" = ")[1]); + public AnalysisField getAnalysisFieldForBaseLayerId(int fid) { + if (!fields.containsKey(fid)) { + loadField(findField(fid)); + } + + AnalysisField analysisField = fields.get(fid); + AnalysisError.guarantee(analysisField != null, "Field with id %d was not correctly loaded.", fid); + return analysisField; } - private PersistedAnalysisMethod.Reader getMethodData(AnalysisMethod analysisMethod) { - if (analysisMethod.getWrapped() instanceof BaseLayerMethod m) { - return findMethod(m.getBaseLayerId()); - } - String descriptor = imageLayerSnapshotUtil.getMethodDescriptor(analysisMethod); - Integer id = methodDescriptorToBaseLayerId.get(descriptor); - return (id != null) ? findMethod(id) : null; + private PersistedAnalysisField.Reader findField(int fid) { + return binarySearchUnique(fid, snapshot.getFields(), PersistedAnalysisField.Reader::getId); } private void loadField(PersistedAnalysisField.Reader fieldData) { @@ -774,25 +1010,7 @@ private BaseLayerField getBaseLayerField(PersistedAnalysisField.Reader fd, int i fd.getIsSynthetic(), fd.getModifiers(), getAnnotations(fd.getAnnotationList()))); } - public AnalysisField getAnalysisFieldForBaseLayerId(int fid) { - if (!fields.containsKey(fid)) { - loadField(findField(fid)); - } - - AnalysisField analysisField = fields.get(fid); - AnalysisError.guarantee(analysisField != null, "Field with id %d was not correctly loaded.", fid); - return analysisField; - } - - private PersistedAnalysisField.Reader findField(int fid) { - return binarySearchUnique(fid, snapshot.getFields(), PersistedAnalysisField.Reader::getId); - } - - /** - * Returns the field id of the given field in the base layer if it exists. This makes the link - * between the base layer and the extension image as the id allows to set the flags of the - * fields in the extension image. - */ + @Override public int lookupHostedFieldInBaseLayer(AnalysisField analysisField) { return getBaseLayerFieldId(analysisField); } @@ -809,13 +1027,20 @@ private int getBaseLayerFieldId(AnalysisField analysisField) { return fieldData.getId(); } + @Override public void addBaseLayerField(AnalysisField analysisField) { fields.putIfAbsent(analysisField.getId(), 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) { @@ -827,13 +1052,13 @@ public void initializeBaseLayerField(AnalysisField analysisField) { if (!analysisField.isStatic() && (isAccessed || isRead)) { analysisField.getDeclaringClass().getInstanceFields(true); } - registerFlag(isAccessed, true, () -> analysisField.registerAsAccessed(PERSISTED)); - registerFlag(isRead, true, () -> analysisField.registerAsRead(PERSISTED)); - registerFlag(fieldData.getIsWritten(), true, () -> analysisField.registerAsWritten(PERSISTED)); - registerFlag(fieldData.getIsFolded(), true, () -> analysisField.registerAsFolded(PERSISTED)); + registerFlag(isAccessed, () -> analysisField.registerAsAccessed(PERSISTED)); + registerFlag(isRead, () -> analysisField.registerAsRead(PERSISTED)); + registerFlag(fieldData.getIsWritten(), () -> analysisField.registerAsWritten(PERSISTED)); + registerFlag(fieldData.getIsFolded(), () -> analysisField.registerAsFolded(PERSISTED)); } - protected PersistedAnalysisField.Reader getFieldData(AnalysisField analysisField) { + private PersistedAnalysisField.Reader getFieldData(AnalysisField analysisField) { if (analysisField.wrapped instanceof BaseLayerField baseLayerField) { return findField(baseLayerField.getBaseLayerId()); } @@ -858,20 +1083,6 @@ protected PersistedAnalysisField.Reader getFieldData(AnalysisField analysisField return null; } - private void registerFlag(boolean flag, boolean post, Runnable runnable) { - if (flag) { - if (universe.getBigbang() != null) { - if (post) { - universe.getBigbang().postTask(debug -> runnable.run()); - } else { - runnable.run(); - } - } else { - heapScannerTasks.add(new AnalysisFuture<>(runnable)); - } - } - } - public void executeHeapScannerTasks() { guarantee(universe.getHeapScanner() != null, "Those tasks should only be executed when the bigbang is not null."); for (AnalysisFuture task : heapScannerTasks) { @@ -879,13 +1090,62 @@ public void executeHeapScannerTasks() { } } + @Override + public boolean hasValueForConstant(JavaConstant javaConstant) { + Object object = hostedValuesProvider.asObject(Object.class, javaConstant); + return hasValueForObject(object); + } + + @SuppressFBWarnings(value = "ES", justification = "Reference equality check needed to detect intern status") + private boolean hasValueForObject(Object object) { + if (object instanceof DynamicHub dynamicHub) { + AnalysisType type = ((SVMHost) universe.hostVM()).lookupType(dynamicHub); + return typeToConstant.containsKey(type.getId()); + } else if (object instanceof String string) { + return stringToConstant.containsKey(string) && string.intern() == string; + } else if (object instanceof Enum) { + return enumToConstant.containsKey(object); + } + return false; + } + + @Override + public ImageHeapConstant getValueForConstant(JavaConstant javaConstant) { + Object object = hostedValuesProvider.asObject(Object.class, javaConstant); + return getValueForObject(object); + } + + private ImageHeapConstant getValueForObject(Object object) { + if (object instanceof DynamicHub dynamicHub) { + AnalysisType type = ((SVMHost) universe.hostVM()).lookupType(dynamicHub); + int id = typeToConstant.get(type.getId()); + return getOrCreateConstant(id); + } else if (object instanceof String string) { + int id = stringToConstant.get(string); + return getOrCreateConstant(id); + } else if (object instanceof Enum) { + int id = enumToConstant.get(object); + return getOrCreateConstant(id); + } + throw AnalysisError.shouldNotReachHere("The constant was not in the persisted heap."); + } + + @Override + public Set getRelinkedFields(AnalysisType type) { + return imageLayerSnapshotUtil.getRelinkedFields(type, metaAccess); + } + + public ImageHeapConstant getOrCreateConstant(int id) { + return getOrCreateConstant(id, null); + } + /** * Get the {@link ImageHeapConstant} representation for a specific base layer constant id. If * known, the parentReachableHostedObject will point to the corresponding constant in the * underlying host VM, found by querying the parent object that made this constant reachable - * (see {@link ImageLayerLoader#getReachableHostedValue(ImageHeapConstant, int)}). + * (see {@link SVMImageLayerLoader#getReachableHostedValue(ImageHeapConstant, int)}). */ - protected ImageHeapConstant getOrCreateConstant(int id, JavaConstant parentReachableHostedObjectCandidate) { + private ImageHeapConstant getOrCreateConstant(int id, JavaConstant parentReachableHostedObjectCandidate) { if (constants.containsKey(id)) { return constants.get(id); } @@ -972,74 +1232,6 @@ protected ImageHeapConstant getOrCreateConstant(int id, JavaConstant parentReach return constants.get(id); } - /** - * Look up an object in current hosted VM based on the recipe serialized from the base layer. - */ - protected JavaConstant lookupHostedObject(PersistedConstant.Reader baseLayerConstant, AnalysisType analysisType) { - if (!baseLayerConstant.getIsSimulated()) { - Class clazz = analysisType.getJavaClass(); - return lookupHostedObject(baseLayerConstant, clazz); - } - return null; - } - - @SuppressWarnings("unchecked") - protected JavaConstant lookupHostedObject(PersistedConstant.Reader baseLayerConstant, Class clazz) { - if (!baseLayerConstant.isObject() || baseLayerConstant.getObject().getRelinking().isNotRelinked()) { - return null; - } - PersistedConstant.Object.Relinking.Reader relinking = baseLayerConstant.getObject().getRelinking(); - if (clazz.equals(String.class)) { - assert relinking.isStringConstant(); - StringConstant.Reader stringConstant = relinking.getStringConstant(); - if (stringConstant.hasValue()) { - String value = stringConstant.getValue().toString(); - Object object = value.intern(); - return hostedValuesProvider.forObject(object); - } - } else if (Enum.class.isAssignableFrom(clazz)) { - assert relinking.isEnumConstant(); - EnumConstant.Reader enumConstant = relinking.getEnumConstant(); - Enum enumValue = getEnumValue(enumConstant.getEnumClass(), enumConstant.getEnumName()); - return hostedValuesProvider.forObject(enumValue); - } - return null; - } - - @SuppressWarnings("unused") - protected void injectIdentityHashCode(Object object, Integer identityHashCode) { - /* The hash code can only be injected in the SVM context. */ - } - - protected static Object getArray(PrimitiveArray.Reader reader) { - return switch (reader.which()) { - case Z -> getBooleans(reader.getZ()); - case B -> toArray(reader.getB(), r -> IntStream.range(0, r.size()).collect(() -> new byte[r.size()], (a, i) -> a[i] = r.get(i), combineUnsupported())); - case S -> toArray(reader.getS(), r -> IntStream.range(0, r.size()).collect(() -> new short[r.size()], (a, i) -> a[i] = r.get(i), combineUnsupported())); - case C -> toArray(reader.getC(), r -> IntStream.range(0, r.size()).collect(() -> new char[r.size()], (a, i) -> a[i] = (char) r.get(i), combineUnsupported())); - case I -> toArray(reader.getI(), r -> IntStream.range(0, r.size()).collect(() -> new int[r.size()], (a, i) -> a[i] = r.get(i), combineUnsupported())); - case F -> toArray(reader.getF(), r -> IntStream.range(0, r.size()).collect(() -> new float[r.size()], (a, i) -> a[i] = r.get(i), combineUnsupported())); - case J -> toArray(reader.getJ(), r -> IntStream.range(0, r.size()).collect(() -> new long[r.size()], (a, i) -> a[i] = r.get(i), combineUnsupported())); - case D -> toArray(reader.getD(), r -> IntStream.range(0, r.size()).collect(() -> new double[r.size()], (a, i) -> a[i] = r.get(i), combineUnsupported())); - case _NOT_IN_SCHEMA -> throw new IllegalArgumentException("Unsupported kind: " + reader.which()); - }; - } - - protected static boolean[] getBooleans(PrimitiveList.Boolean.Reader r) { - return IntStream.range(0, r.size()).collect(() -> new boolean[r.size()], (a, i) -> a[i] = r.get(i), combineUnsupported()); - } - - /** Enables concise one-liners without explicit types in {@link #getArray}. */ - private static A toArray(T reader, Function fun) { - return fun.apply(reader); - } - - private static BiConsumer combineUnsupported() { - return (u, v) -> { - throw new UnsupportedOperationException("Combining partial results not supported, streams must be sequential"); - }; - } - private Object[] getReferencedValues(ImageHeapConstant parentConstant, StructList.Reader data, Set positionsToRelink) { Object[] values = new Object[data.size()]; for (int position = 0; position < data.size(); ++position) { @@ -1087,14 +1279,61 @@ private Object[] getReferencedValues(ImageHeapConstant parentConstant, StructLis return values; } - /** - * Hook for subclasses to do their own processing. - */ - @SuppressWarnings("unused") - protected boolean delegateProcessing(ConstantReference.Reader constantRef, Object[] values, int i) { + private boolean delegateProcessing(ConstantReference.Reader constantRef, Object[] values, int i) { + if (constantRef.isMethodPointer()) { + AnalysisFuture task = new AnalysisFuture<>(() -> { + AnalysisType methodPointerType = metaAccess.lookupJavaType(MethodPointer.class); + int mid = constantRef.getMethodPointer().getMethodId(); + AnalysisMethod method = getAnalysisMethodForBaseLayerId(mid); + RelocatableConstant constant = new RelocatableConstant(new MethodPointer(method), methodPointerType); + values[i] = constant; + return constant; + }); + values[i] = task; + return true; + } else if (constantRef.isCEntryPointLiteralCodePointer()) { + AnalysisType cEntryPointerLiteralPointerType = metaAccess.lookupJavaType(CEntryPointLiteralCodePointer.class); + CEntryPointLiteralReference.Reader ref = constantRef.getCEntryPointLiteralCodePointer(); + String methodName = ref.getMethodName().toString(); + Class definingClass = lookupBaseLayerTypeInHostVM(ref.getDefiningClass().toString()); + Class[] parameterTypes = IntStream.range(0, ref.getParameterNames().size()) + .mapToObj(j -> ref.getParameterNames().get(j).toString()) + .map(this::lookupBaseLayerTypeInHostVM).toArray(Class[]::new); + values[i] = new RelocatableConstant(new CEntryPointLiteralCodePointer(definingClass, methodName, parameterTypes), cEntryPointerLiteralPointerType); + return true; + } return false; } + private static Object getArray(PrimitiveArray.Reader reader) { + return switch (reader.which()) { + case Z -> getBooleans(reader.getZ()); + case B -> toArray(reader.getB(), r -> IntStream.range(0, r.size()).collect(() -> new byte[r.size()], (a, i) -> a[i] = r.get(i), combineUnsupported())); + case S -> toArray(reader.getS(), r -> IntStream.range(0, r.size()).collect(() -> new short[r.size()], (a, i) -> a[i] = r.get(i), combineUnsupported())); + case C -> toArray(reader.getC(), r -> IntStream.range(0, r.size()).collect(() -> new char[r.size()], (a, i) -> a[i] = (char) r.get(i), combineUnsupported())); + case I -> toArray(reader.getI(), r -> IntStream.range(0, r.size()).collect(() -> new int[r.size()], (a, i) -> a[i] = r.get(i), combineUnsupported())); + case F -> toArray(reader.getF(), r -> IntStream.range(0, r.size()).collect(() -> new float[r.size()], (a, i) -> a[i] = r.get(i), combineUnsupported())); + case J -> toArray(reader.getJ(), r -> IntStream.range(0, r.size()).collect(() -> new long[r.size()], (a, i) -> a[i] = r.get(i), combineUnsupported())); + case D -> toArray(reader.getD(), r -> IntStream.range(0, r.size()).collect(() -> new double[r.size()], (a, i) -> a[i] = r.get(i), combineUnsupported())); + case _NOT_IN_SCHEMA -> throw new IllegalArgumentException("Unsupported kind: " + reader.which()); + }; + } + + protected static boolean[] getBooleans(PrimitiveList.Boolean.Reader r) { + return IntStream.range(0, r.size()).collect(() -> new boolean[r.size()], (a, i) -> a[i] = r.get(i), combineUnsupported()); + } + + /** Enables concise one-liners without explicit types in {@link #getArray}. */ + private static A toArray(T reader, Function fun) { + return fun.apply(reader); + } + + private static BiConsumer combineUnsupported() { + return (u, v) -> { + throw new UnsupportedOperationException("Combining partial results not supported, streams must be sequential"); + }; + } + /** * For a parent constant return the referenced field-position or array-element-index value * corresponding to index. @@ -1110,10 +1349,6 @@ private JavaConstant getReachableHostedValue(ImageHeapConstant parentConstant, i } } - private static AnalysisField getFieldFromIndex(ImageHeapInstance instance, int i) { - return (AnalysisField) instance.getType().getInstanceFields(true)[i]; - } - private JavaConstant getHostedElementValue(ImageHeapObjectArray array, int idx) { JavaConstant hostedArray = array.getHostedObject(); JavaConstant rawElementValue = null; @@ -1128,7 +1363,7 @@ private JavaConstant getHostedFieldValue(ImageHeapInstance instance, AnalysisFie try { JavaConstant hostedInstance = instance.getHostedObject(); AnalysisError.guarantee(hostedInstance != null); - rawFieldValue = universe.getHeapScanner().readHostedFieldValue(field, hostedInstance); + rawFieldValue = hostedValuesProvider.readFieldValue(field, hostedInstance); } catch (InternalError | TypeNotPresentException | LinkageError e) { /* Ignore missing type errors. */ return null; @@ -1136,26 +1371,8 @@ private JavaConstant getHostedFieldValue(ImageHeapInstance instance, AnalysisFie return rawFieldValue.get(); } - public void addBaseLayerValueToImageHeap(ImageHeapConstant constant, ImageHeapConstant parentConstant, int i) { - if (parentConstant instanceof ImageHeapInstance imageHeapInstance) { - universe.getHeapScanner().registerBaseLayerValue(constant, getFieldFromIndex(imageHeapInstance, i)); - } else if (parentConstant instanceof ImageHeapObjectArray) { - universe.getHeapScanner().registerBaseLayerValue(constant, i); - } else { - throw AnalysisError.shouldNotReachHere("unexpected constant: " + constant); - } - } - - /** - * Ensures the DynamicHub is consistent with the base layer value. - */ - public void ensureHubInitialized(@SuppressWarnings("unused") ImageHeapConstant constant) { - /* DynamicHub only exists in SVM, so the method does not need to do anything here. */ - } - - @SuppressWarnings("unused") - public void rescanHub(AnalysisType type, Object hubObject) { - /* DynamicHub only exists in SVM, so the method does not need to do anything here. */ + private static AnalysisField getFieldFromIndex(ImageHeapInstance instance, int i) { + return (AnalysisField) instance.getType().getInstanceFields(true)[i]; } private void addBaseLayerObject(int id, long objectOffset, Supplier imageHeapConstantSupplier) { @@ -1171,77 +1388,97 @@ private void addBaseLayerObject(int id, long objectOffset, Supplier getEnumValue(Text.Reader className, Text.Reader name) { - Class enumClass = lookupClass(false, className.toString()); - /* asSubclass produces an "unchecked" warning */ - return Enum.valueOf(enumClass.asSubclass(Enum.class), name.toString()); - } - - public Class lookupClass(boolean optional, String className) { - return ReflectionUtil.lookupClass(optional, className); - } - - public boolean hasValueForConstant(JavaConstant javaConstant) { - Object object = hostedValuesProvider.asObject(Object.class, javaConstant); - return hasValueForObject(object); - } - - @SuppressFBWarnings(value = "ES", justification = "Reference equality check needed to detect intern status") - protected boolean hasValueForObject(Object object) { - if (object instanceof String string) { - return stringToConstant.containsKey(string) && string.intern() == string; - } else if (object instanceof Enum) { - return enumToConstant.containsKey(object); + /** + * Look up an object in current hosted VM based on the recipe serialized from the base layer. + */ + private JavaConstant lookupHostedObject(PersistedConstant.Reader baseLayerConstant, AnalysisType analysisType) { + if (!baseLayerConstant.getIsSimulated()) { + Class clazz = analysisType.getJavaClass(); + return lookupHostedObject(baseLayerConstant, clazz); } - return false; - } - - public ImageHeapConstant getValueForConstant(JavaConstant javaConstant) { - Object object = hostedValuesProvider.asObject(Object.class, javaConstant); - return getValueForObject(object); + return null; } - protected ImageHeapConstant getValueForObject(Object object) { - if (object instanceof String string) { - int id = stringToConstant.get(string); - return getOrCreateConstant(id); - } else if (object instanceof Enum) { - int id = enumToConstant.get(object); - return getOrCreateConstant(id); + private JavaConstant lookupHostedObject(PersistedConstant.Reader baseLayerConstant, Class clazz) { + if (!baseLayerConstant.isObject()) { + return null; } - throw AnalysisError.shouldNotReachHere("The constant was not in the persisted heap."); - } - - public ImageHeapConstant getOrCreateConstant(int id) { - return getOrCreateConstant(id, null); + PersistedConstant.Object.Relinking.Reader relinking = baseLayerConstant.getObject().getRelinking(); + if (relinking.isNotRelinked()) { + return null; + } + if (clazz.equals(Class.class)) { + /* DynamicHub corresponding to $$TypeSwitch classes are not relinked */ + if (baseLayerConstant.isObject() && relinking.isClassConstant()) { + int typeId = relinking.getClassConstant().getTypeId(); + return getDynamicHub(typeId); + } + } else if (clazz.equals(String.class)) { + assert relinking.isStringConstant(); + StringConstant.Reader stringConstant = relinking.getStringConstant(); + if (stringConstant.hasValue()) { + String value = stringConstant.getValue().toString(); + Object object = value.intern(); + return hostedValuesProvider.forObject(object); + } + } else if (Enum.class.isAssignableFrom(clazz)) { + assert relinking.isEnumConstant(); + EnumConstant.Reader enumConstant = relinking.getEnumConstant(); + Enum enumValue = getEnumValue(enumConstant.getEnumClass(), enumConstant.getEnumName()); + return hostedValuesProvider.forObject(enumValue); + } + return null; } - public AnalysisMetaAccess getMetaAccess() { - return metaAccess; + @SuppressWarnings("unchecked") + private Enum getEnumValue(Text.Reader className, Text.Reader name) { + Class enumClass = imageLayerBuildingSupport.lookupClass(false, className.toString()); + /* asSubclass produces an "unchecked" warning */ + return Enum.valueOf(enumClass.asSubclass(Enum.class), name.toString()); } - public void setMetaAccess(AnalysisMetaAccess metaAccess) { - this.metaAccess = metaAccess; + private void addBaseLayerValueToImageHeap(ImageHeapConstant constant, ImageHeapConstant parentConstant, int i) { + if (parentConstant instanceof ImageHeapInstance imageHeapInstance) { + universe.getHeapScanner().registerBaseLayerValue(constant, getFieldFromIndex(imageHeapInstance, i)); + } else if (parentConstant instanceof ImageHeapObjectArray) { + universe.getHeapScanner().registerBaseLayerValue(constant, i); + } else { + throw AnalysisError.shouldNotReachHere("unexpected constant: " + constant); + } } - public void setHostedValuesProvider(HostedValuesProvider hostedValuesProvider) { - this.hostedValuesProvider = hostedValuesProvider; + private void ensureHubInitialized(ImageHeapConstant constant) { + JavaConstant javaConstant = constant.getHostedObject(); + if (constant.getType().getJavaClass().equals(Class.class)) { + DynamicHub hub = universe.getHostedValuesProvider().asObject(DynamicHub.class, javaConstant); + AnalysisType type = ((SVMHost) universe.hostVM()).lookupType(hub); + ensureHubInitialized(type); + /* + * If the persisted constant contains a non-null arrayHub, the corresponding DynamicHub + * must be created and the initializeMetaDataTask needs to be executed to ensure the + * hosted object matches the persisted constant. + */ + if (((ImageHeapInstance) constant).getFieldValue(metaAccess.lookupJavaField(dynamicHubArrayHubField)) != JavaConstant.NULL_POINTER && hub.getArrayHub() == null) { + AnalysisType arrayClass = type.getArrayClass(); + ensureHubInitialized(arrayClass); + } + } } - public Set getRelinkedFields(AnalysisType type) { - return imageLayerSnapshotUtil.getRelinkedFields(type, metaAccess); + private static void ensureHubInitialized(AnalysisType type) { + type.registerAsReachable(PERSISTED); + type.getInitializeMetaDataTask().ensureDone(); } public Long getObjectOffset(JavaConstant javaConstant) { ImageHeapConstant imageHeapConstant = (ImageHeapConstant) javaConstant; - return objectOffsets.get(imageHeapConstant.constantData.id); + return objectOffsets.get(ImageHeapConstant.getConstantID(imageHeapConstant)); } public int getFieldLocation(AnalysisField field) { @@ -1260,11 +1497,75 @@ public long getImageHeapSize() { return snapshot.getImageHeapSize(); } + @Override public boolean hasDynamicHubIdentityHashCode(int tid) { return typeToHubIdentityHashCode.containsKey(tid); } + @Override public int getDynamicHubIdentityHashCode(int tid) { return typeToHubIdentityHashCode.get(tid); } + + private JavaConstant getDynamicHub(int tid) { + AnalysisType type = getAnalysisTypeForBaseLayerId(tid); + DynamicHub hub = ((SVMHost) universe.hostVM()).dynamicHub(type); + return hostedValuesProvider.forObject(hub); + } + + private static void injectIdentityHashCode(Object object, Integer identityHashCode) { + if (object == null || identityHashCode == null) { + return; + } + boolean result = IdentityHashCodeUtil.injectIdentityHashCode(object, identityHashCode); + if (!result) { + if (SubstrateOptions.LoggingHashCodeInjection.getValue()) { + LogUtils.warning("Object of type %s already had an hash code: %s", object.getClass(), object); + } + } + } + + public void rescanHub(AnalysisType type, Object hubObject) { + DynamicHub hub = (DynamicHub) hubObject; + universe.getHeapScanner().rescanObject(hub); + universe.getHeapScanner().rescanField(hub, SVMImageLayerSnapshotUtil.classInitializationInfo); + if (type.getJavaKind() == JavaKind.Object) { + if (type.isArray()) { + universe.getHeapScanner().rescanField(hub.getComponentHub(), SVMImageLayerSnapshotUtil.arrayHub); + } + universe.getHeapScanner().rescanField(hub, SVMImageLayerSnapshotUtil.interfacesEncoding); + if (type.isEnum()) { + universe.getHeapScanner().rescanField(hub, SVMImageLayerSnapshotUtil.enumConstantsReference); + } + } + } + + public ClassInitializationInfo getClassInitializationInfo(AnalysisType type) { + PersistedAnalysisType.Reader typeMap = findType(type.getId()); + + var initInfo = typeMap.getClassInitializationInfo(); + if (initInfo.getIsNoInitializerNoTracking()) { + return ClassInitializationInfo.forNoInitializerInfo(false); + } else if (initInfo.getIsInitializedNoTracking()) { + return ClassInitializationInfo.forInitializedInfo(false); + } else if (initInfo.getIsFailedNoTracking()) { + return ClassInitializationInfo.forFailedInfo(false); + } else { + boolean isTracked = initInfo.getIsTracked(); + + ClassInitializationInfo.InitState initState; + if (initInfo.getIsInitialized()) { + initState = ClassInitializationInfo.InitState.FullyInitialized; + } else if (initInfo.getIsInErrorState()) { + initState = ClassInitializationInfo.InitState.InitializationError; + } else { + assert initInfo.getIsLinked() : "Invalid state"; + int classInitializerId = initInfo.getInitializerMethodId(); + MethodPointer classInitializer = (classInitializerId == 0) ? null : new MethodPointer(getAnalysisMethodForBaseLayerId(classInitializerId)); + return new ClassInitializationInfo(classInitializer, isTracked); + } + + return new ClassInitializationInfo(initState, initInfo.getHasInitializer(), initInfo.getIsBuildTimeInitialized(), isTracked); + } + } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerSingletonLoader.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerSingletonLoader.java new file mode 100644 index 000000000000..a6516558ffb2 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerSingletonLoader.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.imagelayer; + +import static com.oracle.svm.hosted.imagelayer.SVMImageLayerLoader.getBooleans; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import org.capnproto.Text; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.UnmodifiableEconomicMap; + +import com.oracle.svm.core.layeredimagesingleton.ImageSingletonLoader; +import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton.PersistFlags; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonKey; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonObject; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.KeyStoreEntry; +import com.oracle.svm.util.ReflectionUtil; + +public class SVMImageLayerSingletonLoader { + private final HostedImageLayerBuildingSupport imageLayerBuildingSupport; + private final SharedLayerSnapshotCapnProtoSchemaHolder.SharedLayerSnapshot.Reader snapshot; + + public SVMImageLayerSingletonLoader(HostedImageLayerBuildingSupport imageLayerBuildingSupport, SharedLayerSnapshotCapnProtoSchemaHolder.SharedLayerSnapshot.Reader snapshot) { + this.imageLayerBuildingSupport = imageLayerBuildingSupport; + this.snapshot = snapshot; + } + + public Map>> loadImageSingletons(Object forbiddenObject) { + return loadImageSingletons0(forbiddenObject); + } + + private Map>> loadImageSingletons0(Object forbiddenObject) { + Map idToObjectMap = new HashMap<>(); + for (ImageSingletonObject.Reader obj : snapshot.getSingletonObjects()) { + String className = obj.getClassName().toString(); + + EconomicMap keyStore = EconomicMap.create(); + for (KeyStoreEntry.Reader entry : obj.getStore()) { + KeyStoreEntry.Value.Reader v = entry.getValue(); + Object value = switch (v.which()) { + case I -> v.getI(); + case J -> v.getJ(); + case STR -> v.getStr().toString(); + case IL -> Stream.of(v.getIl()).flatMapToInt(r -> IntStream.range(0, r.size()).map(r::get)).toArray(); + case ZL -> getBooleans(v.getZl()); + case STRL -> StreamSupport.stream(v.getStrl().spliterator(), false).map(Text.Reader::toString).toArray(String[]::new); + case _NOT_IN_SCHEMA -> throw new IllegalStateException("Unexpected value: " + v.which()); + }; + keyStore.put(entry.getKey().toString(), value); + } + + // create singleton object instance + Object result; + try { + Class clazz = imageLayerBuildingSupport.lookupClass(false, className); + Method createMethod = ReflectionUtil.lookupMethod(clazz, "createFromLoader", ImageSingletonLoader.class); + result = createMethod.invoke(null, new ImageSingletonLoaderImpl(keyStore)); + } catch (Throwable t) { + throw VMError.shouldNotReachHere("Failed to recreate image singleton", t); + } + + idToObjectMap.put(obj.getId(), result); + } + + Map>> singletonInitializationMap = new HashMap<>(); + for (ImageSingletonKey.Reader entry : snapshot.getSingletonKeys()) { + String className = entry.getKeyClassName().toString(); + PersistFlags persistInfo = PersistFlags.values()[entry.getPersistFlag()]; + int id = entry.getObjectId(); + if (persistInfo == PersistFlags.CREATE) { + assert id != -1 : "Create image singletons should be linked to an object"; + Object singletonObject = idToObjectMap.get(id); + Class clazz = imageLayerBuildingSupport.lookupClass(false, className); + singletonInitializationMap.computeIfAbsent(singletonObject, (k) -> new HashSet<>()); + singletonInitializationMap.get(singletonObject).add(clazz); + } else if (persistInfo == PersistFlags.FORBIDDEN) { + assert id == -1 : "Unrestored image singleton should not be linked to an object"; + Class clazz = imageLayerBuildingSupport.lookupClass(false, className); + singletonInitializationMap.computeIfAbsent(forbiddenObject, (k) -> new HashSet<>()); + singletonInitializationMap.get(forbiddenObject).add(clazz); + } else { + assert persistInfo == PersistFlags.NOTHING : "Unexpected PersistFlags value: " + persistInfo; + assert id == -1 : "Unrestored image singleton should not be linked to an object"; + } + } + + return singletonInitializationMap; + } + + public Class lookupClass(boolean optional, String className) { + return imageLayerBuildingSupport.lookupClass(optional, className); + } +} + +class ImageSingletonLoaderImpl implements ImageSingletonLoader { + private final UnmodifiableEconomicMap keyStore; + + ImageSingletonLoaderImpl(UnmodifiableEconomicMap keyStore) { + this.keyStore = keyStore; + } + + @Override + public List readBoolList(String keyName) { + boolean[] l = (boolean[]) keyStore.get(keyName); + return IntStream.range(0, l.length).mapToObj(i -> l[i]).toList(); + } + + @Override + public int readInt(String keyName) { + return (int) keyStore.get(keyName); + } + + @Override + public List readIntList(String keyName) { + int[] l = (int[]) keyStore.get(keyName); + return IntStream.of(l).boxed().toList(); + } + + @Override + public long readLong(String keyName) { + return (long) keyStore.get(keyName); + } + + @Override + public String readString(String keyName) { + return (String) keyStore.get(keyName); + } + + @Override + public List readStringList(String keyName) { + return List.of((String[]) keyStore.get(keyName)); + } +} 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/imagelayer/SVMImageLayerSnapshotUtil.java similarity index 64% rename from substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerSnapshotUtil.java rename to substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerSnapshotUtil.java index a62ff5e45693..5b78e478191f 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/imagelayer/SVMImageLayerSnapshotUtil.java @@ -22,7 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.hosted.heap; +package com.oracle.svm.hosted.imagelayer; import static com.oracle.svm.hosted.methodhandles.InjectedInvokerRenamingSubstitutionProcessor.isInjectedInvokerType; import static com.oracle.svm.hosted.methodhandles.MethodHandleInvokerRenamingSubstitutionProcessor.isMethodHandleType; @@ -35,19 +35,25 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import org.graalvm.nativeimage.ImageSingletons; -import com.oracle.graal.pointsto.heap.ImageLayerLoader; -import com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil; -import com.oracle.graal.pointsto.heap.ImageLayerWriter; +import com.oracle.graal.pointsto.heap.ImageHeapConstant; +import com.oracle.graal.pointsto.heap.ImageHeapInstance; +import com.oracle.graal.pointsto.heap.ImageHeapObjectArray; +import com.oracle.graal.pointsto.heap.ImageHeapPrimitiveArray; +import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; import com.oracle.graal.pointsto.meta.AnalysisField; 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.PointsToAnalysisField; +import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; +import com.oracle.graal.pointsto.meta.PointsToAnalysisType; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.svm.core.c.struct.CInterfaceLocationIdentity; import com.oracle.svm.core.hub.DynamicHub; @@ -72,12 +78,27 @@ import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.nodes.EncodedGraph; +import jdk.graal.compiler.nodes.FieldLocationIdentity; import jdk.graal.compiler.util.ObjectCopier; import jdk.graal.compiler.util.ObjectCopierInputStream; import jdk.graal.compiler.util.ObjectCopierOutputStream; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; -public class SVMImageLayerSnapshotUtil extends ImageLayerSnapshotUtil { +public class SVMImageLayerSnapshotUtil { + public static final String FILE_NAME_PREFIX = "layer-snapshot-"; + public static final String FILE_EXTENSION = ".lsb"; + public static final String GRAPHS_FILE_NAME_PREFIX = "layer-snapshot-graphs-"; + public static final String GRAPHS_FILE_EXTENSION = ".big"; + + public static final String CONSTRUCTOR_NAME = ""; + public static final String CLASS_INIT_NAME = ""; + + public static final String PERSISTED = "persisted"; + public static final String TRACKED_REASON = "reachable from a graph"; + + public static final int UNDEFINED_CONSTANT_ID = -1; + public static final int UNDEFINED_FIELD_INDEX = -1; + public static final String GENERATED_SERIALIZATION = "jdk.internal.reflect.GeneratedSerializationConstructorAccessor"; public static final Field companion = ReflectionUtil.lookupField(DynamicHub.class, "companion"); @@ -97,10 +118,17 @@ public class SVMImageLayerSnapshotUtil extends ImageLayerSnapshotUtil { */ protected final Map> fieldsToRelink = new HashMap<>(); private final ImageClassLoader imageClassLoader; + protected final List externalValueFields; + /** This needs to be initialized after analysis, as some fields are not available before. */ + protected Map externalValues; @SuppressWarnings("this-escape") public SVMImageLayerSnapshotUtil(ImageClassLoader imageClassLoader) { - super(true); + try { + this.externalValueFields = ObjectCopier.getExternalValueFields(); + } catch (IOException e) { + throw AnalysisError.shouldNotReachHere("Unexpected exception when creating external value fields list", e); + } this.imageClassLoader = imageClassLoader; addSVMExternalValueFields(); } @@ -151,22 +179,69 @@ protected boolean shouldScanPackage(String packageName) { return true; } - @Override + /** + * Get all the field indexes that should be relinked using the hosted value of a constant from + * the given type. + */ + public Set getRelinkedFields(AnalysisType type, AnalysisMetaAccess metaAccess) { + Set result = fieldsToRelink.computeIfAbsent(type, key -> { + Class clazz = type.getJavaClass(); + if (clazz == Class.class) { + type.getInstanceFields(true); + return dynamicHubRelinkedFields.stream().map(metaAccess::lookupJavaField).map(AnalysisField::getPosition).collect(Collectors.toSet()); + } else { + return null; + } + }); + if (result == null) { + return Set.of(); + } + return result; + } + + public SVMGraphEncoder getGraphEncoder(SVMImageLayerWriter imageLayerWriter) { + return new SVMGraphEncoder(externalValues, imageLayerWriter); + } + + public AbstractSVMGraphDecoder getGraphHostedToAnalysisElementsDecoder(SVMImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { + return new SVMGraphHostedToAnalysisElementsDecoder(EncodedGraph.class.getClassLoader(), imageLayerLoader, analysisMethod, snippetReflectionProvider); + } + + public AbstractSVMGraphDecoder getGraphDecoder(SVMImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { + return new SVMGraphDecoder(EncodedGraph.class.getClassLoader(), imageLayerLoader, analysisMethod, snippetReflectionProvider); + } + + /** + * Compute and cache the final {@code externalValues} map in + * {@link SVMImageLayerSnapshotUtil#externalValues} to avoid computing it for each graph. + *

    + * A single {@code ObjectCopier.Encoder} instance could alternatively be used for all graphs, + * but it would then be impossible to process multiple graphs concurrently. + */ + public void initializeExternalValues() { + assert externalValues == null : "The external values should be computed only once."; + externalValues = ObjectCopier.Encoder.gatherExternalValues(externalValueFields); + } + + public static String snapshotFileName(String imageName) { + return FILE_NAME_PREFIX + imageName + FILE_EXTENSION; + } + + public static String snapshotGraphsFileName(String imageName) { + return GRAPHS_FILE_NAME_PREFIX + imageName + GRAPHS_FILE_EXTENSION; + } + public String getTypeDescriptor(AnalysisType type) { - if (type.toJavaName(true).contains(GENERATED_SERIALIZATION)) { + String javaName = type.toJavaName(true); + if (javaName.contains(GENERATED_SERIALIZATION)) { return getGeneratedSerializationName(type); } if (isProxyType(type)) { - return type.toJavaName(true); + return javaName; } - return super.getTypeDescriptor(type); - } - - private static String generatedSerializationClassName(SerializationSupport.SerializationLookupKey serializationLookupKey) { - return GENERATED_SERIALIZATION + ":" + serializationLookupKey.getDeclaringClass() + "," + serializationLookupKey.getTargetConstructorClass(); + return addModuleName(javaName, type.getJavaClass().getModule().getName()); } - @Override public String getMethodDescriptor(AnalysisMethod method) { AnalysisType declaringClass = method.getDeclaringClass(); String moduleName = declaringClass.getJavaClass().getModule().getName(); @@ -193,7 +268,11 @@ public String getMethodDescriptor(AnalysisMethod method) { if (isLambdaType(declaringClass) || isInjectedInvokerType(declaringClass) || isMethodHandleType(declaringClass) || isProxyType(declaringClass)) { return getQualifiedName(method); } - return super.getMethodDescriptor(method); + Executable originalMethod = OriginalMethodProvider.getJavaMethod(method); + if (originalMethod != null) { + return addModuleName(originalMethod.toString(), moduleName); + } + return addModuleName(getQualifiedName(method), moduleName); } /* @@ -208,43 +287,28 @@ private static String getGeneratedSerializationName(AnalysisType type) { return generatedSerializationClassName(serializationLookupKey); } - @Override - public Set getRelinkedFields(AnalysisType type, AnalysisMetaAccess metaAccess) { - Set result = fieldsToRelink.computeIfAbsent(type, key -> { - Class clazz = type.getJavaClass(); - if (clazz == Class.class) { - type.getInstanceFields(true); - return dynamicHubRelinkedFields.stream().map(metaAccess::lookupJavaField).map(AnalysisField::getPosition).collect(Collectors.toSet()); - } else { - return null; - } - }); - if (result == null) { - return Set.of(); - } - return result; - } - - @Override - public GraphEncoder getGraphEncoder(ImageLayerWriter imageLayerWriter) { - return new SVMGraphEncoder(externalValues, imageLayerWriter); + private static String generatedSerializationClassName(SerializationSupport.SerializationLookupKey serializationLookupKey) { + return GENERATED_SERIALIZATION + ":" + serializationLookupKey.getDeclaringClass() + "," + serializationLookupKey.getTargetConstructorClass(); } - @Override - public GraphDecoder getGraphAnalysisElementsDecoder(ImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { - return new SVMGraphAnalysisElementsDecoder(EncodedGraph.class.getClassLoader(), (SVMImageLayerLoader) imageLayerLoader, analysisMethod, snippetReflectionProvider); + private static String addModuleName(String elementName, String moduleName) { + return moduleName + ":" + elementName; } - @Override - public GraphDecoder getGraphDecoder(ImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { - return new SVMGraphDecoder(EncodedGraph.class.getClassLoader(), (SVMImageLayerLoader) imageLayerLoader, analysisMethod, snippetReflectionProvider); + private static String getQualifiedName(AnalysisMethod method) { + return method.getSignature().getReturnType().toJavaName(true) + " " + method.getQualifiedName(); } - public static class SVMGraphEncoder extends GraphEncoder { + public static class SVMGraphEncoder extends ObjectCopier.Encoder { @SuppressWarnings("this-escape") - public SVMGraphEncoder(Map externalValues, ImageLayerWriter imageLayerWriter) { - super(externalValues, imageLayerWriter); + public SVMGraphEncoder(Map externalValues, SVMImageLayerWriter imageLayerWriter) { + super(externalValues); + addBuiltin(new ImageHeapConstantBuiltIn(imageLayerWriter, null)); addBuiltin(new AnalysisTypeBuiltIn(null)); + addBuiltin(new AnalysisMethodBuiltIn(null, null)); + addBuiltin(new AnalysisFieldBuiltIn(null)); + addBuiltin(new FieldLocationIdentityBuiltIn(null)); + addBuiltin(new HostedTypeBuiltIn(null)); addBuiltin(new HostedMethodBuiltIn(null)); addBuiltin(new HostedOptionValuesBuiltIn()); addBuiltin(new HostedSnippetReflectionProviderBuiltIn(null)); @@ -254,24 +318,38 @@ public SVMGraphEncoder(Map externalValues, ImageLayerWriter image } } - public abstract static class AbstractSVMGraphDecoder extends GraphDecoder { + public abstract static class AbstractSVMGraphDecoder extends ObjectCopier.Decoder { + private final HostedImageLayerBuildingSupport imageLayerBuildingSupport; + @SuppressWarnings("this-escape") - public AbstractSVMGraphDecoder(ClassLoader classLoader, SVMImageLayerLoader svmImageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { - super(classLoader, svmImageLayerLoader, analysisMethod); + public AbstractSVMGraphDecoder(ClassLoader classLoader, SVMImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { + super(classLoader); + this.imageLayerBuildingSupport = imageLayerLoader.getImageLayerBuildingSupport(); + addBuiltin(new ImageHeapConstantBuiltIn(null, imageLayerLoader)); + addBuiltin(new AnalysisTypeBuiltIn(imageLayerLoader)); + addBuiltin(new AnalysisMethodBuiltIn(imageLayerLoader, analysisMethod)); + addBuiltin(new AnalysisFieldBuiltIn(imageLayerLoader)); + addBuiltin(new FieldLocationIdentityBuiltIn(imageLayerLoader)); addBuiltin(new HostedOptionValuesBuiltIn()); addBuiltin(new HostedSnippetReflectionProviderBuiltIn(snippetReflectionProvider)); addBuiltin(new CInterfaceLocationIdentityBuiltIn()); addBuiltin(new FastThreadLocalLocationIdentityBuiltIn()); addBuiltin(new VMThreadLocalInfoBuiltIn()); } + + @Override + public Class loadClass(String className) { + return imageLayerBuildingSupport.lookupClass(false, className); + } } - public static class SVMGraphAnalysisElementsDecoder extends AbstractSVMGraphDecoder { + public static class SVMGraphHostedToAnalysisElementsDecoder extends AbstractSVMGraphDecoder { @SuppressWarnings("this-escape") - public SVMGraphAnalysisElementsDecoder(ClassLoader classLoader, SVMImageLayerLoader svmImageLayerLoader, AnalysisMethod analysisMethod, SnippetReflectionProvider snippetReflectionProvider) { + public SVMGraphHostedToAnalysisElementsDecoder(ClassLoader classLoader, SVMImageLayerLoader svmImageLayerLoader, AnalysisMethod analysisMethod, + SnippetReflectionProvider snippetReflectionProvider) { super(classLoader, svmImageLayerLoader, analysisMethod, snippetReflectionProvider); - addBuiltin(new AnalysisTypeBuiltIn(svmImageLayerLoader)); - addBuiltin(new AnalysisMethodBuiltIn(svmImageLayerLoader)); + addBuiltin(new HostedToAnalysisTypeDecoderBuiltIn(svmImageLayerLoader)); + addBuiltin(new HostedToAnalysisMethodDecoderBuiltIn(svmImageLayerLoader)); } } @@ -284,6 +362,132 @@ public SVMGraphDecoder(ClassLoader classLoader, SVMImageLayerLoader svmImageLaye } } + public static class ImageHeapConstantBuiltIn extends ObjectCopier.Builtin { + private final SVMImageLayerWriter imageLayerWriter; + private final SVMImageLayerLoader imageLayerLoader; + + protected ImageHeapConstantBuiltIn(SVMImageLayerWriter imageLayerWriter, SVMImageLayerLoader imageLayerLoader) { + super(ImageHeapConstant.class, ImageHeapInstance.class, ImageHeapObjectArray.class, ImageHeapPrimitiveArray.class); + this.imageLayerWriter = imageLayerWriter; + this.imageLayerLoader = imageLayerLoader; + } + + @Override + public void encode(ObjectCopier.Encoder encoder, ObjectCopierOutputStream stream, Object obj) throws IOException { + ImageHeapConstant imageHeapConstant = (ImageHeapConstant) obj; + imageLayerWriter.ensureConstantPersisted(imageHeapConstant); + stream.writePackedUnsignedInt(ImageHeapConstant.getConstantID(imageHeapConstant)); + } + + @Override + protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, ObjectCopierInputStream stream) throws IOException { + int id = stream.readPackedUnsignedInt(); + return imageLayerLoader.getOrCreateConstant(id); + } + } + + public static class AnalysisTypeBuiltIn extends ObjectCopier.Builtin { + private final SVMImageLayerLoader imageLayerLoader; + + protected AnalysisTypeBuiltIn(SVMImageLayerLoader imageLayerLoader) { + super(AnalysisType.class, PointsToAnalysisType.class); + this.imageLayerLoader = imageLayerLoader; + } + + @Override + public void encode(ObjectCopier.Encoder encoder, ObjectCopierOutputStream stream, Object obj) throws IOException { + AnalysisType type = (AnalysisType) obj; + type.registerAsTrackedAcrossLayers(TRACKED_REASON); + stream.writePackedUnsignedInt(type.getId()); + } + + @Override + protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, ObjectCopierInputStream stream) throws IOException { + int id = stream.readPackedUnsignedInt(); + return imageLayerLoader.getAnalysisTypeForBaseLayerId(id); + } + } + + public static class AnalysisMethodBuiltIn extends ObjectCopier.Builtin { + private final SVMImageLayerLoader imageLayerLoader; + private final AnalysisMethod analysisMethod; + + protected AnalysisMethodBuiltIn(SVMImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod) { + super(AnalysisMethod.class, PointsToAnalysisMethod.class); + this.imageLayerLoader = imageLayerLoader; + this.analysisMethod = analysisMethod; + } + + @Override + public void encode(ObjectCopier.Encoder encoder, ObjectCopierOutputStream stream, Object obj) throws IOException { + AnalysisMethod method = (AnalysisMethod) obj; + method.registerAsTrackedAcrossLayers(TRACKED_REASON); + stream.writePackedUnsignedInt(method.getId()); + } + + @Override + protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, ObjectCopierInputStream stream) throws IOException { + int id = stream.readPackedUnsignedInt(); + if (id == analysisMethod.getId()) { + return analysisMethod; + } + return imageLayerLoader.getAnalysisMethodForBaseLayerId(id); + } + } + + public static class AnalysisFieldBuiltIn extends ObjectCopier.Builtin { + private final SVMImageLayerLoader imageLayerLoader; + + protected AnalysisFieldBuiltIn(SVMImageLayerLoader imageLayerLoader) { + super(AnalysisField.class, PointsToAnalysisField.class); + this.imageLayerLoader = imageLayerLoader; + } + + @Override + public void encode(ObjectCopier.Encoder encoder, ObjectCopierOutputStream stream, Object obj) throws IOException { + AnalysisField field = (AnalysisField) obj; + int id = encodeField(field); + stream.writePackedUnsignedInt(id); + } + + @Override + protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, ObjectCopierInputStream stream) throws IOException { + int id = stream.readPackedUnsignedInt(); + return decodeField(imageLayerLoader, id); + } + } + + public static class FieldLocationIdentityBuiltIn extends ObjectCopier.Builtin { + private final SVMImageLayerLoader imageLayerLoader; + + protected FieldLocationIdentityBuiltIn(SVMImageLayerLoader imageLayerLoader) { + super(FieldLocationIdentity.class); + this.imageLayerLoader = imageLayerLoader; + } + + @Override + public void encode(ObjectCopier.Encoder encoder, ObjectCopierOutputStream stream, Object obj) throws IOException { + FieldLocationIdentity fieldLocationIdentity = (FieldLocationIdentity) obj; + int id = encodeField((AnalysisField) fieldLocationIdentity.getField()); + stream.writePackedUnsignedInt(id); + } + + @Override + protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, ObjectCopierInputStream stream) throws IOException { + int id = stream.readPackedUnsignedInt(); + return new FieldLocationIdentity(decodeField(imageLayerLoader, id)); + } + } + + private static int encodeField(AnalysisField field) { + field.registerAsTrackedAcrossLayers(TRACKED_REASON); + return field.getId(); + } + + private static AnalysisField decodeField(SVMImageLayerLoader imageLayerLoader, int id) { + return imageLayerLoader.getAnalysisFieldForBaseLayerId(id); + } + public abstract static class AbstractHostedTypeBuiltIn extends ObjectCopier.Builtin { protected final SVMImageLayerLoader svmImageLayerLoader; @@ -299,8 +503,8 @@ protected void encode(ObjectCopier.Encoder encoder, ObjectCopierOutputStream str } } - public static class AnalysisTypeBuiltIn extends AbstractHostedTypeBuiltIn { - protected AnalysisTypeBuiltIn(SVMImageLayerLoader svmImageLayerLoader) { + public static class HostedToAnalysisTypeDecoderBuiltIn extends AbstractHostedTypeBuiltIn { + protected HostedToAnalysisTypeDecoderBuiltIn(SVMImageLayerLoader svmImageLayerLoader) { super(svmImageLayerLoader); } @@ -341,8 +545,8 @@ protected void encode(ObjectCopier.Encoder encoder, ObjectCopierOutputStream str } } - public static class AnalysisMethodBuiltIn extends AbstractHostedMethodBuiltIn { - protected AnalysisMethodBuiltIn(SVMImageLayerLoader svmImageLayerLoader) { + public static class HostedToAnalysisMethodDecoderBuiltIn extends AbstractHostedMethodBuiltIn { + protected HostedToAnalysisMethodDecoderBuiltIn(SVMImageLayerLoader svmImageLayerLoader) { super(svmImageLayerLoader); } 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 new file mode 100644 index 000000000000..c6c11b67ae0a --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java @@ -0,0 +1,1127 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.imagelayer; + +import static com.oracle.svm.hosted.imagelayer.SVMImageLayerSnapshotUtil.CONSTRUCTOR_NAME; +import static com.oracle.svm.hosted.imagelayer.SVMImageLayerSnapshotUtil.GENERATED_SERIALIZATION; +import static com.oracle.svm.hosted.imagelayer.SVMImageLayerSnapshotUtil.UNDEFINED_CONSTANT_ID; +import static com.oracle.svm.hosted.imagelayer.SVMImageLayerSnapshotUtil.UNDEFINED_FIELD_INDEX; +import static com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ClassInitializationInfo.Builder; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Field; +import java.lang.reflect.Parameter; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.BiConsumer; +import java.util.function.IntFunction; +import java.util.function.ObjIntConsumer; +import java.util.function.Supplier; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import org.capnproto.ListBuilder; +import org.capnproto.MessageBuilder; +import org.capnproto.PrimitiveList; +import org.capnproto.Serialize; +import org.capnproto.StructBuilder; +import org.capnproto.StructList; +import org.capnproto.Text; +import org.capnproto.TextList; +import org.capnproto.Void; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.MapCursor; +import org.graalvm.nativeimage.AnnotationAccess; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.c.function.RelocatedPointer; +import org.graalvm.nativeimage.impl.CEntryPointLiteralCodePointer; + +import com.oracle.graal.pointsto.BigBang; +import com.oracle.graal.pointsto.api.HostVM; +import com.oracle.graal.pointsto.api.ImageLayerWriter; +import com.oracle.graal.pointsto.flow.AnalysisParsedGraph; +import com.oracle.graal.pointsto.heap.ImageHeap; +import com.oracle.graal.pointsto.heap.ImageHeapConstant; +import com.oracle.graal.pointsto.heap.ImageHeapInstance; +import com.oracle.graal.pointsto.heap.ImageHeapObjectArray; +import com.oracle.graal.pointsto.heap.ImageHeapPrimitiveArray; +import com.oracle.graal.pointsto.heap.ImageHeapRelocatableConstant; +import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.meta.AnalysisUniverse; +import com.oracle.graal.pointsto.util.AnalysisError; +import com.oracle.graal.pointsto.util.AnalysisFuture; +import com.oracle.svm.core.FunctionPointerHolder; +import com.oracle.svm.core.StaticFieldsSupport; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.classinitialization.ClassInitializationInfo; +import com.oracle.svm.core.hub.DynamicHub; +import com.oracle.svm.core.layeredimagesingleton.ImageSingletonWriter; +import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton; +import com.oracle.svm.core.layeredimagesingleton.RuntimeOnlyWrapper; +import com.oracle.svm.core.meta.MethodPointer; +import com.oracle.svm.core.reflect.serialize.SerializationSupport; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.SVMHost; +import com.oracle.svm.hosted.annotation.AnnotationMemberValue; +import com.oracle.svm.hosted.annotation.AnnotationMetadata; +import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; +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; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonKey; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonObject; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.KeyStoreEntry; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisField; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod.WrappedMethod; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType.WrappedType; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant.Object.Relinking; +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; +import com.oracle.svm.hosted.lambda.StableLambdaProxyNameFeature; +import com.oracle.svm.hosted.meta.HostedField; +import com.oracle.svm.hosted.meta.HostedMethod; +import com.oracle.svm.hosted.meta.HostedUniverse; +import com.oracle.svm.hosted.meta.RelocatableConstant; +import com.oracle.svm.hosted.methodhandles.MethodHandleFeature; +import com.oracle.svm.hosted.methodhandles.MethodHandleInvokerSubstitutionType; +import com.oracle.svm.hosted.reflect.ReflectionExpandSignatureMethod; +import com.oracle.svm.hosted.reflect.proxy.ProxyRenamingSubstitutionProcessor; +import com.oracle.svm.hosted.reflect.proxy.ProxySubstitutionType; +import com.oracle.svm.util.FileDumpingUtil; +import com.oracle.svm.util.LogUtils; +import com.oracle.svm.util.ModuleSupport; + +import jdk.graal.compiler.core.common.NumUtil; +import jdk.graal.compiler.debug.Assertions; +import jdk.graal.compiler.debug.GraalError; +import jdk.graal.compiler.java.LambdaUtils; +import jdk.graal.compiler.nodes.EncodedGraph; +import jdk.graal.compiler.nodes.spi.IdentityHashCodeProvider; +import jdk.graal.compiler.util.ObjectCopier; +import jdk.vm.ci.meta.ConstantReflectionProvider; +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.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import sun.reflect.annotation.AnnotationType; + +public class SVMImageLayerWriter extends ImageLayerWriter { + private final SVMImageLayerSnapshotUtil imageLayerSnapshotUtil; + private ImageHeap imageHeap; + private AnalysisUniverse aUniverse; + private IdentityHashMap internedStringsIdentityMap; + + private final MessageBuilder snapshotFileBuilder = new MessageBuilder(); + private final SharedLayerSnapshot.Builder snapshotBuilder = this.snapshotFileBuilder.initRoot(SharedLayerSnapshot.factory); + private Map constantsMap; + private final Map methodsMap = new ConcurrentHashMap<>(); + private FileInfo fileInfo; + private GraphsOutput graphsOutput; + private final boolean useSharedLayerGraphs; + private final boolean useSharedLayerStrengthenedGraphs; + + private final Set constantsToPersist = ConcurrentHashMap.newKeySet(); + + public void ensureConstantPersisted(ImageHeapConstant constant) { + constantsToPersist.add(constant); + afterConstantAdded(constant); + } + + private NativeImageHeap nativeImageHeap; + private HostedUniverse hUniverse; + + private record ConstantParent(int constantId, int index) { + static ConstantParent NONE = new ConstantParent(UNDEFINED_CONSTANT_ID, UNDEFINED_FIELD_INDEX); + } + + private record FileInfo(Path layerFilePath, String fileName, String suffix) { + } + + private record MethodGraphsInfo(String analysisGraphLocation, boolean analysisGraphIsIntrinsic, + String strengthenedGraphLocation) { + + static final MethodGraphsInfo NO_GRAPHS = new MethodGraphsInfo(null, false, null); + + MethodGraphsInfo withAnalysisGraph(String location, boolean isIntrinsic) { + assert analysisGraphLocation == null && !analysisGraphIsIntrinsic; + return new MethodGraphsInfo(location, isIntrinsic, strengthenedGraphLocation); + } + + MethodGraphsInfo withStrengthenedGraph(String location) { + assert strengthenedGraphLocation == null; + return new MethodGraphsInfo(analysisGraphLocation, analysisGraphIsIntrinsic, location); + } + } + + private static class GraphsOutput { + private final Path path; + private final Path tempPath; + private final FileChannel tempChannel; + + private final AtomicLong currentOffset = new AtomicLong(0); + + GraphsOutput(Path path, String fileName, String suffix) { + this.path = path; + this.tempPath = FileDumpingUtil.createTempFile(path.getParent(), fileName, suffix); + try { + this.tempChannel = FileChannel.open(this.tempPath, EnumSet.of(StandardOpenOption.WRITE)); + } catch (IOException e) { + throw GraalError.shouldNotReachHere(e, "Error opening temporary graphs file."); + } + } + + String add(byte[] encodedGraph) { + long offset = currentOffset.getAndAdd(encodedGraph.length); + try { + tempChannel.write(ByteBuffer.wrap(encodedGraph), offset); + } catch (Exception e) { + throw GraalError.shouldNotReachHere(e, "Error during graphs file dumping."); + } + return new StringBuilder("@").append(offset).append("[").append(encodedGraph.length).append("]").toString(); + } + + void finish() { + try { + tempChannel.close(); + FileDumpingUtil.moveTryAtomically(tempPath, path); + } catch (Exception e) { + throw GraalError.shouldNotReachHere(e, "Error during graphs file dumping."); + } + } + } + + public SVMImageLayerWriter(SVMImageLayerSnapshotUtil imageLayerSnapshotUtil, boolean useSharedLayerGraphs, boolean useSharedLayerStrengthenedGraphs) { + this.imageLayerSnapshotUtil = imageLayerSnapshotUtil; + this.useSharedLayerGraphs = useSharedLayerGraphs; + this.useSharedLayerStrengthenedGraphs = useSharedLayerStrengthenedGraphs; + } + + public void setInternedStringsIdentityMap(IdentityHashMap map) { + this.internedStringsIdentityMap = map; + } + + public void setImageHeap(ImageHeap heap) { + this.imageHeap = heap; + } + + public void setSnapshotFileInfo(Path layerSnapshotPath, String fileName, String suffix) { + fileInfo = new FileInfo(layerSnapshotPath, fileName, suffix); + } + + public void setAnalysisUniverse(AnalysisUniverse aUniverse) { + this.aUniverse = aUniverse; + } + + public void setNativeImageHeap(NativeImageHeap nativeImageHeap) { + this.nativeImageHeap = nativeImageHeap; + } + + public void setHostedUniverse(HostedUniverse hUniverse) { + this.hUniverse = hUniverse; + } + + public void openGraphsOutput(Path layerGraphsPath, String fileName, String suffix) { + AnalysisError.guarantee(graphsOutput == null, "Graphs file has already been opened"); + graphsOutput = new GraphsOutput(layerGraphsPath, fileName, suffix); + } + + public void dumpFiles() { + graphsOutput.finish(); + + FileDumpingUtil.dumpFile(fileInfo.layerFilePath, fileInfo.fileName, fileInfo.suffix, outputStream -> { + try { + Serialize.write(Channels.newChannel(outputStream), snapshotFileBuilder); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + + public void initializeExternalValues() { + imageLayerSnapshotUtil.initializeExternalValues(); + } + + public void setImageHeapSize(long imageHeapSize) { + snapshotBuilder.setImageHeapSize(imageHeapSize); + } + + @Override + public void onTrackedAcrossLayer(AnalysisMethod method, Object reason) { + if (method.wrapped instanceof FactoryMethod factoryMethod) { + AnalysisMethod targetConstructor = method.getUniverse().lookup(factoryMethod.getTargetConstructor()); + targetConstructor.registerAsTrackedAcrossLayers(reason); + } + } + + public void persistAnalysisInfo() { + ImageHeapConstant staticPrimitiveFields = (ImageHeapConstant) hUniverse.getSnippetReflection().forObject(StaticFieldsSupport.getStaticPrimitiveFields()); + ImageHeapConstant staticObjectFields = (ImageHeapConstant) hUniverse.getSnippetReflection().forObject(StaticFieldsSupport.getStaticObjectFields()); + + snapshotBuilder.setStaticPrimitiveFieldsConstantId(ImageHeapConstant.getConstantID(staticPrimitiveFields)); + snapshotBuilder.setStaticObjectFieldsConstantId(ImageHeapConstant.getConstantID(staticObjectFields)); + + // Late constant scan so all of them are known with values available (readers installed) + List constantsToScan = new ArrayList<>(constantsToPersist); + imageHeap.getReachableObjects().values().forEach(constantsToScan::addAll); + constantsMap = HashMap.newHashMap(constantsToScan.size()); + constantsToScan.forEach(c -> constantsMap.put(c, ConstantParent.NONE)); + while (!constantsToScan.isEmpty()) { + List discoveredConstants = new ArrayList<>(); + constantsToScan.forEach(con -> scanConstantReferencedObjects(con, discoveredConstants)); + constantsToScan = discoveredConstants; + } + + snapshotBuilder.setNextTypeId(aUniverse.getNextTypeId()); + snapshotBuilder.setNextMethodId(aUniverse.getNextMethodId()); + snapshotBuilder.setNextFieldId(aUniverse.getNextFieldId()); + snapshotBuilder.setNextConstantId(ImageHeapConstant.getCurrentId()); + + List typesToPersist = aUniverse.getTypes().stream().filter(AnalysisType::isTrackedAcrossLayers).toList(); + List methodsToPersist = aUniverse.getMethods().stream().filter(AnalysisMethod::isTrackedAcrossLayers).toList(); + List fieldsToPersist = aUniverse.getFields().stream().filter(AnalysisField::isTrackedAcrossLayers).toList(); + + initSortedList(snapshotBuilder::initTypes, typesToPersist, Comparator.comparingInt(AnalysisType::getId), this::persistType); + initSortedList(snapshotBuilder::initMethods, methodsToPersist, Comparator.comparingInt(AnalysisMethod::getId), this::persistMethod); + initSortedList(snapshotBuilder::initFields, fieldsToPersist, Comparator.comparingInt(AnalysisField::getId), this::persistField); + + Set constantsToRelink = new HashSet<>(); + initSortedList(snapshotBuilder::initConstants, constantsMap.entrySet(), + Comparator.comparingInt(a -> ImageHeapConstant.getConstantID(a.getKey())), + (entry, bsupplier) -> persistConstant(entry.getKey(), entry.getValue(), bsupplier.get(), constantsToRelink)); + initInts(snapshotBuilder::initConstantsToRelink, constantsToRelink.stream().mapToInt(i -> i).sorted()); + } + + private static void initInts(IntFunction builderSupplier, IntStream ids) { + int[] values = ids.toArray(); + PrimitiveList.Int.Builder builder = builderSupplier.apply(values.length); + for (int i = 0; i < values.length; i++) { + builder.set(i, values[i]); + } + } + + private static void initStringList(IntFunction builderSupplier, Stream strings) { + Object[] array = strings.toArray(); + TextList.Builder builder = builderSupplier.apply(array.length); + for (int i = 0; i < array.length; i++) { + builder.set(i, new Text.Reader(array[i].toString())); + } + } + + private static void initSortedList(IntFunction> init, Collection objects, Comparator comparator, BiConsumer> action) { + @SuppressWarnings("unchecked") + T[] array = (T[]) objects.toArray(); + Arrays.sort(array, comparator); + + StructList.Builder builder = init.apply(objects.size()); + Iterator iterator = builder.iterator(); + for (T t : array) { + action.accept(t, iterator::next); + } + AnalysisError.guarantee(!iterator.hasNext(), "all created struct builders must have been used"); + } + + private void persistType(AnalysisType type, Supplier builderSupplier) { + PersistedAnalysisType.Builder builder = builderSupplier.get(); + HostVM hostVM = aUniverse.hostVM(); + SVMHost svmHost = (SVMHost) hostVM; + DynamicHub hub = svmHost.dynamicHub(type); + builder.setHubIdentityHashCode(System.identityHashCode(hub)); + + builder.setIsInitializedAtBuildTime(ClassInitializationSupport.singleton().maybeInitializeAtBuildTime(type)); + + ClassInitializationInfo info = hub.getClassInitializationInfo(); + if (info != null) { + Builder b = builder.initClassInitializationInfo(); + b.setIsNoInitializerNoTracking(info == ClassInitializationInfo.forNoInitializerInfo(false)); + b.setIsInitializedNoTracking(info == ClassInitializationInfo.forInitializedInfo(false)); + b.setIsFailedNoTracking(info == ClassInitializationInfo.forFailedInfo(false)); + b.setIsInitialized(info.isInitialized()); + b.setIsInErrorState(info.isInErrorState()); + b.setIsLinked(info.isLinked()); + b.setHasInitializer(info.hasInitializer()); + b.setIsBuildTimeInitialized(info.isBuildTimeInitialized()); + b.setIsTracked(info.isTracked()); + FunctionPointerHolder classInitializer = info.getClassInitializer(); + if (classInitializer != null) { + MethodPointer methodPointer = (MethodPointer) classInitializer.functionPointer; + AnalysisMethod classInitializerMethod = (AnalysisMethod) methodPointer.getMethod(); + b.setInitializerMethodId(classInitializerMethod.getId()); + } + } + + builder.setId(type.getId()); + builder.setDescriptor(imageLayerSnapshotUtil.getTypeDescriptor(type)); + + initInts(builder::initFields, Arrays.stream(type.getInstanceFields(true)).mapToInt(f -> ((AnalysisField) f).getId())); + builder.setClassJavaName(type.toJavaName()); + builder.setClassName(type.getName()); + builder.setModifiers(type.getModifiers()); + builder.setIsInterface(type.isInterface()); + builder.setIsEnum(type.isEnum()); + builder.setIsInitialized(type.isInitialized()); + builder.setIsLinked(type.isLinked()); + if (type.getSourceFileName() != null) { + builder.setSourceFileName(type.getSourceFileName()); + } + try { + AnalysisType enclosingType = type.getEnclosingType(); + if (enclosingType != null) { + builder.setEnclosingTypeId(enclosingType.getId()); + } + } catch (InternalError | TypeNotPresentException | LinkageError e) { + /* Ignore missing type errors. */ + } + if (type.isArray()) { + builder.setComponentTypeId(type.getComponentType().getId()); + } + if (type.getSuperclass() != null) { + builder.setSuperClassTypeId(type.getSuperclass().getId()); + } + initInts(builder::initInterfaces, Arrays.stream(type.getInterfaces()).mapToInt(AnalysisType::getId)); + initInts(builder::initInstanceFieldIds, Arrays.stream(type.getInstanceFields(false)).mapToInt(f -> ((AnalysisField) f).getId())); + initInts(builder::initInstanceFieldIdsWithSuper, Arrays.stream(type.getInstanceFields(true)).mapToInt(f -> ((AnalysisField) f).getId())); + initInts(builder::initStaticFieldIds, Arrays.stream(type.getStaticFields()).mapToInt(f -> ((AnalysisField) f).getId())); + persistAnnotations(type, builder::initAnnotationList); + + builder.setIsInstantiated(type.isInstantiated()); + builder.setIsUnsafeAllocated(type.isUnsafeAllocated()); + builder.setIsReachable(type.isReachable()); + + delegatePersistType(type, builder); + + afterTypeAdded(type); + } + + protected void delegatePersistType(AnalysisType type, PersistedAnalysisType.Builder builder) { + if (type.toJavaName(true).contains(GENERATED_SERIALIZATION)) { + WrappedType.SerializationGenerated.Builder b = builder.getWrappedType().initSerializationGenerated(); + var key = SerializationSupport.singleton().getKeyFromConstructorAccessorClass(type.getJavaClass()); + b.setRawDeclaringClass(key.getDeclaringClass().getName()); + b.setRawTargetConstructor(key.getTargetConstructorClass().getName()); + } else if (LambdaUtils.isLambdaType(type)) { + WrappedType.Lambda.Builder b = builder.getWrappedType().initLambda(); + b.setCapturingClass(LambdaUtils.capturingClass(type.toJavaName())); + } else if (ProxyRenamingSubstitutionProcessor.isProxyType(type)) { + builder.getWrappedType().setProxyType(Void.VOID); + } + } + + /** + * Some types can have an unstable name between two different image builds. To avoid producing + * wrong results, a warning should be printed if such types exist in the resulting image. + */ + private static void afterTypeAdded(AnalysisType type) { + /* + * Lambda functions containing the same method invocations will return the same hash. They + * will still have a different name, but in a multi threading context, the names can be + * switched. + */ + if (type.getWrapped() instanceof LambdaSubstitutionType lambdaSubstitutionType) { + StableLambdaProxyNameFeature stableLambdaProxyNameFeature = ImageSingletons.lookup(StableLambdaProxyNameFeature.class); + if (!stableLambdaProxyNameFeature.getLambdaSubstitutionProcessor().isNameAlwaysStable(lambdaSubstitutionType.getName())) { + String message = "The lambda method " + lambdaSubstitutionType.getName() + " might not have a stable name in the extension image."; + handleNameConflict(message); + } + } + /* + * Method handle with the same inner method handles will return the same hash. They will + * still have a different name, but in a multi threading context, the names can be switched. + */ + if (type.getWrapped() instanceof MethodHandleInvokerSubstitutionType methodHandleSubstitutionType) { + MethodHandleFeature methodHandleFeature = ImageSingletons.lookup(MethodHandleFeature.class); + if (!methodHandleFeature.getMethodHandleSubstitutionProcessor().isNameAlwaysStable(methodHandleSubstitutionType.getName())) { + String message = "The method handle " + methodHandleSubstitutionType.getName() + " might not have a stable name in the extension image."; + handleNameConflict(message); + } + } + + if (type.getWrapped() instanceof ProxySubstitutionType proxySubstitutionType) { + if (!ProxyRenamingSubstitutionProcessor.isNameAlwaysStable(proxySubstitutionType.getName())) { + String message = "The Proxy type " + proxySubstitutionType.getName() + " might not have a stable name in the extension image."; + handleNameConflict(message); + } + } + } + + private static void handleNameConflict(String message) { + if (SubstrateOptions.AbortOnNameConflict.getValue()) { + throw VMError.shouldNotReachHere(message); + } else { + LogUtils.warning(message); + } + } + + private void persistMethod(AnalysisMethod method, Supplier builderSupplier) { + PersistedAnalysisMethod.Builder builder = builderSupplier.get(); + MethodGraphsInfo graphsInfo = methodsMap.putIfAbsent(imageLayerSnapshotUtil.getMethodDescriptor(method), MethodGraphsInfo.NO_GRAPHS); + Executable executable = method.getJavaMethod(); + + if (builder.getId() != 0) { + throw GraalError.shouldNotReachHere("The method descriptor should be unique, but " + imageLayerSnapshotUtil.getMethodDescriptor(method) + " got added twice."); + } + if (executable != null) { + initStringList(builder::initArgumentClassNames, Arrays.stream(executable.getParameterTypes()).map(Class::getName)); + builder.setClassName(executable.getDeclaringClass().getName()); + } + + builder.setDescriptor(imageLayerSnapshotUtil.getMethodDescriptor(method)); + builder.setDeclaringTypeId(method.getDeclaringClass().getId()); + initInts(builder::initArgumentTypeIds, method.getSignature().toParameterList(null).stream().mapToInt(AnalysisType::getId)); + builder.setId(method.getId()); + builder.setName(method.getName()); + builder.setReturnTypeId(method.getSignature().getReturnType().getId()); + builder.setIsVarArgs(method.isVarArgs()); + builder.setCanBeStaticallyBound(method.canBeStaticallyBound()); + builder.setModifiers(method.getModifiers()); + builder.setIsConstructor(method.isConstructor()); + builder.setIsSynthetic(method.isSynthetic()); + byte[] code = method.getCode(); + if (code != null) { + builder.setCode(code); + } + builder.setCodeSize(method.getCodeSize()); + IntrinsicMethod intrinsicMethod = aUniverse.getBigbang().getConstantReflectionProvider().getMethodHandleAccess().lookupMethodHandleIntrinsic(method); + if (intrinsicMethod != null) { + builder.setMethodHandleIntrinsicName(intrinsicMethod.name()); + } + persistAnnotations(method, builder::initAnnotationList); + + builder.setIsVirtualRootMethod(method.isVirtualRootMethod()); + builder.setIsDirectRootMethod(method.isDirectRootMethod()); + builder.setIsInvoked(method.isSimplyInvoked()); + builder.setIsImplementationInvoked(method.isSimplyImplementationInvoked()); + builder.setIsIntrinsicMethod(method.isIntrinsicMethod()); + + if (graphsInfo != null && graphsInfo.analysisGraphLocation != null) { + builder.setAnalysisGraphLocation(graphsInfo.analysisGraphLocation); + builder.setAnalysisGraphIsIntrinsic(graphsInfo.analysisGraphIsIntrinsic); + } + if (graphsInfo != null && graphsInfo.strengthenedGraphLocation != null) { + builder.setStrengthenedGraphLocation(graphsInfo.strengthenedGraphLocation); + } + + delegatePersistMethod(method, builder); + + // register this method as persisted for name resolution + HostedDynamicLayerInfo.singleton().recordPersistedMethod(hUniverse.lookup(method)); + } + + protected void delegatePersistMethod(AnalysisMethod method, PersistedAnalysisMethod.Builder builder) { + if (method.wrapped instanceof FactoryMethod factoryMethod) { + WrappedMethod.FactoryMethod.Builder b = builder.getWrappedMethod().initFactoryMethod(); + AnalysisMethod targetConstructor = method.getUniverse().lookup(factoryMethod.getTargetConstructor()); + b.setTargetConstructorId(targetConstructor.getId()); + b.setThrowAllocatedObject(factoryMethod.throwAllocatedObject()); + AnalysisType instantiatedType = method.getUniverse().lookup(factoryMethod.getInstantiatedType()); + b.setInstantiatedTypeId(instantiatedType.getId()); + } else if (method.wrapped instanceof CEntryPointCallStubMethod cEntryPointCallStubMethod) { + WrappedMethod.CEntryPointCallStub.Builder b = builder.getWrappedMethod().initCEntryPointCallStub(); + AnalysisMethod originalMethod = CEntryPointCallStubSupport.singleton().getMethodForStub(cEntryPointCallStubMethod); + b.setOriginalMethodId(originalMethod.getId()); + b.setNotPublished(cEntryPointCallStubMethod.isNotPublished()); + } else if (method.wrapped instanceof ReflectionExpandSignatureMethod reflectionExpandSignatureMethod) { + WrappedMethod.WrappedMember.Builder b = builder.getWrappedMethod().initWrappedMember(); + b.setReflectionExpandSignature(Void.VOID); + Executable member = reflectionExpandSignatureMethod.getMember(); + persistMethodWrappedMember(b, member); + } else if (method.wrapped instanceof JNIJavaCallVariantWrapperMethod jniJavaCallVariantWrapperMethod) { + WrappedMethod.WrappedMember.Builder b = builder.getWrappedMethod().initWrappedMember(); + b.setJavaCallVariantWrapper(Void.VOID); + Executable executable = jniJavaCallVariantWrapperMethod.getMember(); + persistMethodWrappedMember(b, executable); + } + } + + private static void persistMethodWrappedMember(PersistedAnalysisMethod.WrappedMethod.WrappedMember.Builder b, Executable member) { + b.setName(member instanceof Constructor ? CONSTRUCTOR_NAME : member.getName()); + b.setDeclaringClassName(member.getDeclaringClass().getName()); + Parameter[] params = member.getParameters(); + TextList.Builder atb = b.initArgumentTypeNames(params.length); + for (int i = 0; i < params.length; i++) { + atb.set(i, new Text.Reader(params[i].getName())); + } + } + + private void persistField(AnalysisField field, Supplier fieldBuilderSupplier) { + PersistedAnalysisField.Builder builder = fieldBuilderSupplier.get(); + + builder.setId(field.getId()); + builder.setDeclaringTypeId(field.getDeclaringClass().getId()); + builder.setName(field.getName()); + builder.setIsAccessed(field.getAccessedReason() != null); + builder.setIsRead(field.getReadReason() != null); + builder.setIsWritten(field.getWrittenReason() != null); + builder.setIsFolded(field.getFoldedReason() != null); + + HostedField hostedField = hUniverse.lookup(field); + int location = hostedField.getLocation(); + if (location > 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())) { + builder.setClassName(originalField.getDeclaringClass().getName()); + } + builder.setIsStatic(field.isStatic()); + builder.setIsInternal(field.isInternal()); + builder.setIsSynthetic(field.isSynthetic()); + builder.setTypeId(field.getType().getId()); + builder.setModifiers(field.getModifiers()); + builder.setPosition(field.getPosition()); + + persistAnnotations(field, builder::initAnnotationList); + } + + private void persistAnnotations(AnnotatedElement annotatedElement, IntFunction> builder) { + Class[] annotationTypes = AnnotationAccess.getAnnotationTypes(annotatedElement); + persistAnnotations(annotatedElement, annotationTypes, builder); + } + + private void persistAnnotations(AnnotatedElement annotatedElement, Class[] annotationTypes, + IntFunction> builder) { + var b = builder.apply(annotationTypes.length); + for (int i = 0; i < annotationTypes.length; i++) { + Class annotationClass = annotationTypes[i]; + SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.Builder annotationBuilder = b.get(i); + annotationBuilder.setTypeName(annotationClass.getName()); + Annotation annotation = AnnotationAccess.getAnnotation(annotatedElement, annotationClass); + persistAnnotationValues(annotation, annotationClass, annotationBuilder::initValues); + } + } + + private void persistAnnotationValues(Annotation annotation, Class annotationClass, IntFunction> builder) { + AnnotationType annotationType = AnnotationType.getInstance(annotationClass); + EconomicMap members = EconomicMap.create(); + annotationType.members().forEach((memberName, memberAccessor) -> { + try { + String moduleName = memberAccessor.getDeclaringClass().getModule().getName(); + if (moduleName != null) { + ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, SVMImageLayerWriter.class, false, moduleName); + } + AnnotationMemberValue memberValue = AnnotationMemberValue.getMemberValue(annotation, memberName, memberAccessor, annotationType); + Object value = memberValue.get(annotationType.memberTypes().get(memberName)); + members.put(memberName, value); + } catch (AnnotationMetadata.AnnotationExtractionError e) { + /* We skip the incorrect annotation */ + } + }); + if (!members.isEmpty()) { + var list = builder.apply(members.size()); + MapCursor cursor = members.getEntries(); + for (int i = 0; cursor.advance(); i++) { + var b = list.get(i); + b.setName(cursor.getKey()); + Object v = cursor.getValue(); + persistAnnotationValue(v, b); + } + } + } + + private void persistAnnotationValue(Object v, AnnotationValue.Builder b) { + if (v.getClass().isArray()) { + if (v instanceof Object[] array) { + var ba = b.initMembers(); + ba.setClassName(v.getClass().getComponentType().getName()); + var bav = ba.initMemberValues(array.length); + for (int i = 0; i < array.length; ++i) { + persistAnnotationValue(array[i], bav.get(i)); + } + } else { + Class componentType = v.getClass().getComponentType(); + assert componentType.isPrimitive() : v + " should be a primitive array"; + persistConstantPrimitiveArray(b.initPrimitiveArray(), JavaKind.fromJavaClass(componentType), v); + } + } else { + switch (v) { + case Boolean z -> setAnnotationPrimitiveValue(b, JavaKind.Boolean, z ? 1L : 0L); + case Byte z -> setAnnotationPrimitiveValue(b, JavaKind.Byte, z); + case Short s -> setAnnotationPrimitiveValue(b, JavaKind.Short, s); + case Character c -> setAnnotationPrimitiveValue(b, JavaKind.Char, c); + case Integer i -> setAnnotationPrimitiveValue(b, JavaKind.Int, i); + case Float f -> setAnnotationPrimitiveValue(b, JavaKind.Float, Float.floatToRawIntBits(f)); + case Long j -> setAnnotationPrimitiveValue(b, JavaKind.Long, j); + case Double d -> setAnnotationPrimitiveValue(b, JavaKind.Double, Double.doubleToRawLongBits(d)); + case Class clazz -> b.setClassName(clazz.getName()); + case Annotation innerAnnotation -> + persistAnnotationValues(innerAnnotation, innerAnnotation.annotationType(), b.initAnnotation()::initValues); + case String s -> b.setString(s); + case Enum e -> { + var ba = b.initEnum(); + ba.setClassName(e.getDeclaringClass().getName()); + ba.setName(e.name()); + } + default -> throw AnalysisError.shouldNotReachHere("Unknown annotation value: " + v); + } + } + } + + private static void setAnnotationPrimitiveValue(AnnotationValue.Builder b, JavaKind kind, long rawValue) { + var pv = b.initPrimitive(); + pv.setTypeChar(NumUtil.safeToUByte(kind.getTypeChar())); + pv.setRawValue(rawValue); + } + + private void persistConstant(ImageHeapConstant imageHeapConstant, ConstantParent parent, PersistedConstant.Builder builder, Set constantsToRelink) { + ObjectInfo objectInfo = nativeImageHeap.getConstantInfo(imageHeapConstant); + builder.setObjectOffset((objectInfo == null) ? -1 : objectInfo.getOffset()); + + int id = ImageHeapConstant.getConstantID(imageHeapConstant); + builder.setId(id); + AnalysisType type = imageHeapConstant.getType(); + AnalysisError.guarantee(type.isTrackedAcrossLayers(), "Type %s from constant %s should have been marked as trackedAcrossLayers, but was not", type, imageHeapConstant); + builder.setTypeId(type.getId()); + + IdentityHashCodeProvider identityHashCodeProvider = (IdentityHashCodeProvider) aUniverse.getBigbang().getConstantReflectionProvider(); + int identityHashCode = identityHashCodeProvider.identityHashCode(imageHeapConstant); + builder.setIdentityHashCode(identityHashCode); + + switch (imageHeapConstant) { + case ImageHeapInstance imageHeapInstance -> { + builder.initObject().setInstance(Void.VOID); + persistConstantObjectData(builder.getObject(), imageHeapInstance::getFieldValue, imageHeapInstance.getFieldValuesSize()); + persistConstantRelinkingInfo(builder, imageHeapConstant, constantsToRelink, aUniverse.getBigbang()); + } + case ImageHeapObjectArray imageHeapObjectArray -> { + builder.initObject().setObjectArray(Void.VOID); + persistConstantObjectData(builder.getObject(), imageHeapObjectArray::getElement, imageHeapObjectArray.getLength()); + } + case ImageHeapPrimitiveArray imageHeapPrimitiveArray -> + persistConstantPrimitiveArray(builder.initPrimitiveData(), imageHeapPrimitiveArray.getType().getComponentType().getJavaKind(), imageHeapPrimitiveArray.getArray()); + case ImageHeapRelocatableConstant relocatableConstant -> { + builder.initRelocatable().setKey(relocatableConstant.getConstantData().key); + } + default -> throw AnalysisError.shouldNotReachHere("Unexpected constant type " + imageHeapConstant); + } + + if (!constantsToRelink.contains(id) && parent != ConstantParent.NONE) { + builder.setParentConstantId(parent.constantId); + assert parent.index != UNDEFINED_FIELD_INDEX : "Tried to persist child constant %s from parent constant %d, but got index %d".formatted(imageHeapConstant, parent.constantId, parent.index); + builder.setParentIndex(parent.index); + } + } + + private void persistConstantRelinkingInfo(PersistedConstant.Builder builder, ImageHeapConstant imageHeapConstant, Set constantsToRelink, BigBang bb) { + Class clazz = imageHeapConstant.getType().getJavaClass(); + JavaConstant hostedObject = imageHeapConstant.getHostedObject(); + boolean simulated = hostedObject == null; + builder.setIsSimulated(simulated); + if (!simulated) { + Relinking.Builder relinkingBuilder = builder.getObject().getRelinking(); + int id = ImageHeapConstant.getConstantID(imageHeapConstant); + ResolvedJavaType type = bb.getConstantReflectionProvider().asJavaType(hostedObject); + if (type instanceof AnalysisType analysisType) { + relinkingBuilder.initClassConstant().setTypeId(analysisType.getId()); + constantsToRelink.add(id); + } else if (clazz.equals(String.class)) { + StringConstant.Builder stringConstantBuilder = relinkingBuilder.initStringConstant(); + String value = bb.getSnippetReflectionProvider().asObject(String.class, hostedObject); + if (internedStringsIdentityMap.containsKey(value)) { + /* + * Interned strings must be relinked. + */ + stringConstantBuilder.setValue(value); + constantsToRelink.add(id); + } + } else if (Enum.class.isAssignableFrom(clazz)) { + EnumConstant.Builder enumBuilder = relinkingBuilder.initEnumConstant(); + Enum value = bb.getSnippetReflectionProvider().asObject(Enum.class, hostedObject); + enumBuilder.setEnumClass(value.getDeclaringClass().getName()); + enumBuilder.setEnumName(value.name()); + constantsToRelink.add(id); + } + } + } + + private static void persistConstantPrimitiveArray(PrimitiveArray.Builder builder, JavaKind componentKind, Object array) { + assert componentKind.toJavaClass().equals(array.getClass().getComponentType()); + switch (array) { + case boolean[] a -> persistArray(a, builder::initZ, (b, i) -> b.set(i, a[i])); + case byte[] a -> persistArray(a, builder::initB, (b, i) -> b.set(i, a[i])); + case short[] a -> persistArray(a, builder::initS, (b, i) -> b.set(i, a[i])); + case char[] a -> persistArray(a, builder::initC, (b, i) -> b.set(i, (short) a[i])); + case int[] a -> persistArray(a, builder::initI, (b, i) -> b.set(i, a[i])); + case long[] a -> persistArray(a, builder::initJ, (b, i) -> b.set(i, a[i])); + case float[] a -> persistArray(a, builder::initF, (b, i) -> b.set(i, a[i])); + case double[] a -> persistArray(a, builder::initD, (b, i) -> b.set(i, a[i])); + default -> throw new IllegalArgumentException("Unsupported kind: " + componentKind); + } + } + + /** Enables concise one-liners in {@link #persistConstantPrimitiveArray}. */ + private static void persistArray(A array, IntFunction init, ObjIntConsumer setter) { + int length = Array.getLength(array); + T builder = init.apply(length); + for (int i = 0; i < length; i++) { + setter.accept(builder, i); + } + } + + private void persistConstantObjectData(PersistedConstant.Object.Builder builder, IntFunction valuesFunction, int size) { + StructList.Builder refsBuilder = builder.initData(size); + for (int i = 0; i < size; ++i) { + Object object = valuesFunction.apply(i); + 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); + } + } + } + + private static boolean delegateProcessing(ConstantReference.Builder builder, Object constant) { + if (constant instanceof RelocatableConstant relocatableConstant) { + RelocatedPointer pointer = relocatableConstant.getPointer(); + if (pointer instanceof MethodPointer methodPointer) { + AnalysisMethod method = getRelocatableConstantMethod(methodPointer); + builder.initMethodPointer().setMethodId(method.getId()); + return true; + } else if (pointer instanceof CEntryPointLiteralCodePointer cp) { + CEntryPointLiteralReference.Builder b = builder.initCEntryPointLiteralCodePointer(); + b.setMethodName(cp.methodName); + b.setDefiningClass(cp.definingClass.getName()); + b.initParameterNames(cp.parameterTypes.length); + for (int i = 0; i < cp.parameterTypes.length; i++) { + b.getParameterNames().set(i, new Text.Reader(cp.parameterTypes[i].getName())); + } + return true; + } + } + return false; + } + + private void afterConstantAdded(ImageHeapConstant constant) { + constant.getType().registerAsTrackedAcrossLayers(constant); + /* If this is a Class constant persist the corresponding type. */ + ConstantReflectionProvider constantReflection = aUniverse.getBigbang().getConstantReflectionProvider(); + AnalysisType typeFromClassConstant = (AnalysisType) constantReflection.asJavaType(constant); + if (typeFromClassConstant != null) { + typeFromClassConstant.registerAsTrackedAcrossLayers(constant); + } + } + + private void scanConstantReferencedObjects(ImageHeapConstant constant, Collection discoveredConstants) { + if (Objects.requireNonNull(constant) instanceof ImageHeapInstance instance) { + scanConstantReferencedObjects(constant, instance::getFieldValue, instance.getFieldValuesSize(), discoveredConstants); + } else if (constant instanceof ImageHeapObjectArray objArray) { + scanConstantReferencedObjects(constant, objArray::getElement, objArray.getLength(), discoveredConstants); + } + } + + private void scanConstantReferencedObjects(ImageHeapConstant constant, IntFunction referencedObjectFunction, int size, Collection discoveredConstants) { + for (int i = 0; i < size; i++) { + AnalysisType parentType = constant.getType(); + Object obj = referencedObjectFunction.apply(i); + if (obj instanceof ImageHeapConstant con && !constantsMap.containsKey(con)) { + /* + * Some constants are not in imageHeap#reachableObjects, but are still created in + * reachable constants. They can be created in the extension image, but should not + * be used. + */ + Set relinkedFields = imageLayerSnapshotUtil.getRelinkedFields(parentType, aUniverse.getBigbang().getMetaAccess()); + ConstantParent parent = relinkedFields.contains(i) ? new ConstantParent(ImageHeapConstant.getConstantID(constant), i) : ConstantParent.NONE; + + discoveredConstants.add(con); + constantsMap.put(con, parent); + } else if (obj instanceof MethodPointer mp) { + getRelocatableConstantMethod(mp).registerAsTrackedAcrossLayers("In method pointer"); + } + } + } + + private static AnalysisMethod getRelocatableConstantMethod(MethodPointer methodPointer) { + ResolvedJavaMethod method = methodPointer.getMethod(); + if (method instanceof HostedMethod hostedMethod) { + return hostedMethod.wrapped; + } else { + return (AnalysisMethod) method; + } + } + + public void persistAnalysisParsedGraphs() { + // Persisting graphs discovers additional types, members and constants that need persisting + Set persistedGraphMethods = new HashSet<>(); + boolean modified; + do { + modified = false; + /* + * GR-60503: It would be better to mark all the elements as trackedAcrossLayers before + * the end of the analysis and only iterate only once over all methods. + */ + for (AnalysisMethod method : aUniverse.getMethods().stream().filter(AnalysisMethod::isTrackedAcrossLayers).toList()) { + if (persistedGraphMethods.add(method)) { + modified = true; + persistAnalysisParsedGraph(method); + } + } + } while (modified); + + // Note that constants are scanned late so all values are available. + } + + private void persistAnalysisParsedGraph(AnalysisMethod method) { + Object analyzedGraph = method.getGraph(); + if (analyzedGraph instanceof AnalysisParsedGraph analysisParsedGraph) { + String name = imageLayerSnapshotUtil.getMethodDescriptor(method); + MethodGraphsInfo graphsInfo = methodsMap.get(name); + if (graphsInfo == null || graphsInfo.analysisGraphLocation == null) { + String location = persistGraph(method, analysisParsedGraph.getEncodedGraph()); + if (location != null) { + methodsMap.compute(name, (n, mgi) -> (mgi != null ? mgi : MethodGraphsInfo.NO_GRAPHS) + .withAnalysisGraph(location, analysisParsedGraph.isIntrinsic())); + } + } + } + } + + public void persistMethodStrengthenedGraph(AnalysisMethod method) { + if (!useSharedLayerStrengthenedGraphs) { + return; + } + + String name = imageLayerSnapshotUtil.getMethodDescriptor(method); + MethodGraphsInfo graphsInfo = methodsMap.get(name); + + if (graphsInfo == null || graphsInfo.strengthenedGraphLocation == null) { + EncodedGraph analyzedGraph = method.getAnalyzedGraph(); + String location = persistGraph(method, analyzedGraph); + methodsMap.compute(name, (n, mgi) -> (mgi != null ? mgi : MethodGraphsInfo.NO_GRAPHS).withStrengthenedGraph(location)); + } + } + + private String persistGraph(AnalysisMethod method, EncodedGraph analyzedGraph) { + if (!useSharedLayerGraphs) { + return null; + } + byte[] encodedGraph = ObjectCopier.encode(imageLayerSnapshotUtil.getGraphEncoder(this), analyzedGraph); + if (contains(encodedGraph, LambdaUtils.LAMBDA_CLASS_NAME_SUBSTRING.getBytes(StandardCharsets.UTF_8))) { + throw AnalysisError.shouldNotReachHere("The graph for the method %s contains a reference to a lambda type, which cannot be decoded: %s".formatted(method, encodedGraph)); + } + return graphsOutput.add(encodedGraph); + } + + private static boolean contains(byte[] data, byte[] seq) { + outer: for (int i = 0; i <= data.length - seq.length; i++) { + for (int j = 0; j < seq.length; j++) { + if (data[i + j] != seq[j]) { + continue outer; + } + } + return true; + } + return false; + } + + record SingletonPersistInfo(LayeredImageSingleton.PersistFlags flags, int id, EconomicMap keyStore) { + } + + public void writeImageSingletonInfo(List, Object>> layeredImageSingletons) { + StructList.Builder singletonsBuilder = snapshotBuilder.initSingletonKeys(layeredImageSingletons.size()); + Map singletonInfoMap = new HashMap<>(); + int nextID = 1; + for (int i = 0; i < layeredImageSingletons.size(); i++) { + var singletonInfo = layeredImageSingletons.get(i); + LayeredImageSingleton singleton; + if (singletonInfo.getValue() instanceof RuntimeOnlyWrapper wrapper) { + singleton = wrapper.wrappedObject(); + } else { + singleton = (LayeredImageSingleton) singletonInfo.getValue(); + } + String key = singletonInfo.getKey().getName(); + if (!singletonInfoMap.containsKey(singleton)) { + var writer = new ImageSingletonWriterImpl(); + var flags = singleton.preparePersist(writer); + boolean persistData = flags == LayeredImageSingleton.PersistFlags.CREATE; + var info = new SingletonPersistInfo(flags, persistData ? nextID++ : -1, persistData ? writer.getKeyValueStore() : null); + singletonInfoMap.put(singleton, info); + } + var info = singletonInfoMap.get(singleton); + + ImageSingletonKey.Builder sb = singletonsBuilder.get(i); + sb.setKeyClassName(key); + sb.setObjectId(info.id); + sb.setPersistFlag(info.flags.ordinal()); + } + + var sortedByIDs = singletonInfoMap.entrySet().stream() + .filter(e -> e.getValue().flags == LayeredImageSingleton.PersistFlags.CREATE) + .sorted(Comparator.comparingInt(e -> e.getValue().id)) + .toList(); + StructList.Builder objectsBuilder = snapshotBuilder.initSingletonObjects(sortedByIDs.size()); + for (int i = 0; i < sortedByIDs.size(); i++) { + var entry = sortedByIDs.get(i); + var info = entry.getValue(); + + ImageSingletonObject.Builder ob = objectsBuilder.get(i); + ob.setId(info.id); + ob.setClassName(entry.getKey().getClass().getName()); + writeImageSingletonKeyStore(ob, info.keyStore); + } + } + + private static void writeImageSingletonKeyStore(ImageSingletonObject.Builder objectData, EconomicMap keyStore) { + StructList.Builder lb = objectData.initStore(keyStore.size()); + MapCursor cursor = keyStore.getEntries(); + for (int i = 0; cursor.advance(); i++) { + KeyStoreEntry.Builder b = lb.get(i); + b.setKey(cursor.getKey()); + switch (cursor.getValue()) { + case Integer iv -> b.getValue().setI(iv); + case Long jv -> b.getValue().setJ(jv); + case String str -> b.getValue().setStr(str); + case int[] il -> { + PrimitiveList.Int.Builder ilb = b.getValue().initIl(il.length); + for (int j = 0; j < il.length; j++) { + ilb.set(j, il[j]); + } + } + case String[] strl -> { + TextList.Builder strlb = b.getValue().initStrl(strl.length); + for (int j = 0; j < strl.length; j++) { + strlb.set(j, new Text.Reader(strl[j])); + } + } + case boolean[] zl -> { + PrimitiveList.Boolean.Builder zlb = b.getValue().initZl(zl.length); + for (int j = 0; j < zl.length; j++) { + zlb.set(j, zl[j]); + } + } + default -> throw new IllegalStateException("Unexpected type: " + cursor.getValue()); + } + } + } +} + +class ImageSingletonWriterImpl implements ImageSingletonWriter { + private final EconomicMap keyValueStore = EconomicMap.create(); + + EconomicMap getKeyValueStore() { + return keyValueStore; + } + + private static boolean nonNullEntries(List list) { + return list.stream().filter(Objects::isNull).findAny().isEmpty(); + } + + @Override + public void writeBoolList(String keyName, List value) { + assert nonNullEntries(value); + boolean[] b = new boolean[value.size()]; + for (int i = 0; i < value.size(); i++) { + b[i] = value.get(i); + } + var previous = keyValueStore.put(keyName, b); + assert previous == null : Assertions.errorMessage(keyName, previous); + } + + @Override + public void writeInt(String keyName, int value) { + var previous = keyValueStore.put(keyName, value); + assert previous == null : previous; + } + + @Override + public void writeIntList(String keyName, List value) { + assert nonNullEntries(value); + var previous = keyValueStore.put(keyName, value.stream().mapToInt(i -> i).toArray()); + assert previous == null : Assertions.errorMessage(keyName, previous); + } + + @Override + public void writeLong(String keyName, long value) { + var previous = keyValueStore.put(keyName, value); + assert previous == null : Assertions.errorMessage(keyName, previous); + } + + @Override + public void writeString(String keyName, String value) { + var previous = keyValueStore.put(keyName, value); + assert previous == null : Assertions.errorMessage(keyName, previous); + } + + @Override + public void writeStringList(String keyName, List value) { + assert nonNullEntries(value); + var previous = keyValueStore.put(keyName, value.toArray(String[]::new)); + assert previous == null : Assertions.errorMessage(keyName, previous); + } +} diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/SharedLayerSnapshotCapnProtoSchemaHolder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java similarity index 89% rename from substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/SharedLayerSnapshotCapnProtoSchemaHolder.java rename to substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java index 2c6b91b2cb0e..1db6d56da3ca 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/SharedLayerSnapshotCapnProtoSchemaHolder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java @@ -27,7 +27,7 @@ // Generated by Cap'n Proto compiler, DO NOT EDIT // source: SharedLayerSnapshotCapnProtoSchema.capnp -package com.oracle.graal.pointsto.heap; +package com.oracle.svm.hosted.imagelayer; @SuppressWarnings("all") public final class SharedLayerSnapshotCapnProtoSchemaHolder { @@ -280,23 +280,23 @@ public final org.capnproto.PrimitiveList.Int.Builder initStaticFieldIds(int size public final boolean hasAnnotationList() { return !_pointerFieldIsNull(9); } - public final org.capnproto.StructList.Builder getAnnotationList() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 9, null, 0); + public final org.capnproto.StructList.Builder getAnnotationList() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 9, null, 0); } - public final void setAnnotationList(org.capnproto.StructList.Reader value) { - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 9, value); + public final void setAnnotationList(org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 9, value); } - public final org.capnproto.StructList.Builder initAnnotationList(int size) { - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 9, size); + public final org.capnproto.StructList.Builder initAnnotationList(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 9, size); } - public final com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ClassInitializationInfo.Builder getClassInitializationInfo() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ClassInitializationInfo.factory, 10, null, 0); + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ClassInitializationInfo.Builder getClassInitializationInfo() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ClassInitializationInfo.factory, 10, null, 0); } - public final void setClassInitializationInfo(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ClassInitializationInfo.Reader value) { - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ClassInitializationInfo.factory,10, value); + public final void setClassInitializationInfo(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ClassInitializationInfo.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ClassInitializationInfo.factory,10, value); } - public final com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ClassInitializationInfo.Builder initClassInitializationInfo() { - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ClassInitializationInfo.factory,10, 0); + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ClassInitializationInfo.Builder initClassInitializationInfo() { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ClassInitializationInfo.factory,10, 0); } public final WrappedType.Builder getWrappedType() { return new PersistedAnalysisType.WrappedType.Builder(segment, data, pointers, dataSize, pointerCount); @@ -437,15 +437,15 @@ public final org.capnproto.PrimitiveList.Int.Reader getStaticFieldIds() { public final boolean hasAnnotationList() { return !_pointerFieldIsNull(9); } - public final org.capnproto.StructList.Reader getAnnotationList() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 9, null, 0); + public final org.capnproto.StructList.Reader getAnnotationList() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 9, null, 0); } public boolean hasClassInitializationInfo() { return !_pointerFieldIsNull(10); } - public com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ClassInitializationInfo.Reader getClassInitializationInfo() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ClassInitializationInfo.factory,10,null, 0); + public com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ClassInitializationInfo.Reader getClassInitializationInfo() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ClassInitializationInfo.factory,10,null, 0); } public WrappedType.Reader getWrappedType() { @@ -1120,14 +1120,14 @@ public final org.capnproto.Text.Builder initMethodHandleIntrinsicName(int size) public final boolean hasAnnotationList() { return !_pointerFieldIsNull(7); } - public final org.capnproto.StructList.Builder getAnnotationList() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 7, null, 0); + public final org.capnproto.StructList.Builder getAnnotationList() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 7, null, 0); } - public final void setAnnotationList(org.capnproto.StructList.Reader value) { - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 7, value); + public final void setAnnotationList(org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 7, value); } - public final org.capnproto.StructList.Builder initAnnotationList(int size) { - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 7, size); + public final org.capnproto.StructList.Builder initAnnotationList(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 7, size); } public final boolean getIsVarArgs() { return _getBooleanField(168); @@ -1298,8 +1298,8 @@ public org.capnproto.Text.Reader getMethodHandleIntrinsicName() { public final boolean hasAnnotationList() { return !_pointerFieldIsNull(7); } - public final org.capnproto.StructList.Reader getAnnotationList() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 7, null, 0); + public final org.capnproto.StructList.Reader getAnnotationList() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 7, null, 0); } public final boolean getIsVarArgs() { @@ -2022,14 +2022,14 @@ public final void setIsSynthetic(boolean value) { public final boolean hasAnnotationList() { return !_pointerFieldIsNull(1); } - public final org.capnproto.StructList.Builder getAnnotationList() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 1, null, 0); + public final org.capnproto.StructList.Builder getAnnotationList() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 1, null, 0); } - public final void setAnnotationList(org.capnproto.StructList.Reader value) { - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 1, value); + public final void setAnnotationList(org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 1, value); } - public final org.capnproto.StructList.Builder initAnnotationList(int size) { - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 1, size); + public final org.capnproto.StructList.Builder initAnnotationList(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 1, size); } public final boolean hasName() { return !_pointerFieldIsNull(2); @@ -2122,8 +2122,8 @@ public final boolean getIsSynthetic() { public final boolean hasAnnotationList() { return !_pointerFieldIsNull(1); } - public final org.capnproto.StructList.Reader getAnnotationList() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 1, null, 0); + public final org.capnproto.StructList.Reader getAnnotationList() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.listFactory, 1, null, 0); } public boolean hasName() { @@ -2323,18 +2323,18 @@ public final void setNotMaterialized(org.capnproto.Void value) { public final boolean isPrimitiveValue() { return which() == ConstantReference.Which.PRIMITIVE_VALUE; } - public final com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.Builder getPrimitiveValue() { + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.Builder getPrimitiveValue() { assert which() == ConstantReference.Which.PRIMITIVE_VALUE: "Must check which() before get()ing a union member."; - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.factory, 0, null, 0); + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.factory, 0, null, 0); } - public final void setPrimitiveValue(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.Reader value) { + public final void setPrimitiveValue(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.Reader value) { _setShortField(2, (short)ConstantReference.Which.PRIMITIVE_VALUE.ordinal()); - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.factory,0, value); + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.factory,0, value); } - public final com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.Builder initPrimitiveValue() { + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.Builder initPrimitiveValue() { _setShortField(2, (short)ConstantReference.Which.PRIMITIVE_VALUE.ordinal()); - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.factory,0, 0); + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.factory,0, 0); } public final boolean isMethodPointer() { return which() == ConstantReference.Which.METHOD_POINTER; @@ -2351,18 +2351,18 @@ public final MethodPointer.Builder initMethodPointer() { public final boolean isCEntryPointLiteralCodePointer() { return which() == ConstantReference.Which.C_ENTRY_POINT_LITERAL_CODE_POINTER; } - public final com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference.Builder getCEntryPointLiteralCodePointer() { + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference.Builder getCEntryPointLiteralCodePointer() { assert which() == ConstantReference.Which.C_ENTRY_POINT_LITERAL_CODE_POINTER: "Must check which() before get()ing a union member."; - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference.factory, 0, null, 0); + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference.factory, 0, null, 0); } - public final void setCEntryPointLiteralCodePointer(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference.Reader value) { + public final void setCEntryPointLiteralCodePointer(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference.Reader value) { _setShortField(2, (short)ConstantReference.Which.C_ENTRY_POINT_LITERAL_CODE_POINTER.ordinal()); - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference.factory,0, value); + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference.factory,0, value); } - public final com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference.Builder initCEntryPointLiteralCodePointer() { + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference.Builder initCEntryPointLiteralCodePointer() { _setShortField(2, (short)ConstantReference.Which.C_ENTRY_POINT_LITERAL_CODE_POINTER.ordinal()); - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference.factory,0, 0); + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference.factory,0, 0); } } @@ -2413,10 +2413,10 @@ public final boolean isPrimitiveValue() { public boolean hasPrimitiveValue() { return !_pointerFieldIsNull(0); } - public com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.Reader getPrimitiveValue() { + public com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.Reader getPrimitiveValue() { assert which() == ConstantReference.Which.PRIMITIVE_VALUE: "Must check which() before get()ing a union member."; - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.factory,0,null, 0); + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.factory,0,null, 0); } public final boolean isMethodPointer() { @@ -2432,10 +2432,10 @@ public final boolean isCEntryPointLiteralCodePointer() { public boolean hasCEntryPointLiteralCodePointer() { return !_pointerFieldIsNull(0); } - public com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference.Reader getCEntryPointLiteralCodePointer() { + public com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference.Reader getCEntryPointLiteralCodePointer() { assert which() == ConstantReference.Which.C_ENTRY_POINT_LITERAL_CODE_POINTER: "Must check which() before get()ing a union member."; - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference.factory,0,null, 0); + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference.factory,0,null, 0); } } @@ -2645,18 +2645,18 @@ public final Object.Builder initObject() { public final boolean isPrimitiveData() { return which() == PersistedConstant.Which.PRIMITIVE_DATA; } - public final com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.Builder getPrimitiveData() { + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.Builder getPrimitiveData() { assert which() == PersistedConstant.Which.PRIMITIVE_DATA: "Must check which() before get()ing a union member."; - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.factory, 0, null, 0); + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.factory, 0, null, 0); } - public final void setPrimitiveData(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.Reader value) { + public final void setPrimitiveData(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.Reader value) { _setShortField(16, (short)PersistedConstant.Which.PRIMITIVE_DATA.ordinal()); - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.factory,0, value); + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.factory,0, value); } - public final com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.Builder initPrimitiveData() { + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.Builder initPrimitiveData() { _setShortField(16, (short)PersistedConstant.Which.PRIMITIVE_DATA.ordinal()); - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.factory,0, 0); + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.factory,0, 0); } public final boolean isRelocatable() { return which() == PersistedConstant.Which.RELOCATABLE; @@ -2732,10 +2732,10 @@ public final boolean isPrimitiveData() { public boolean hasPrimitiveData() { return !_pointerFieldIsNull(0); } - public com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.Reader getPrimitiveData() { + public com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.Reader getPrimitiveData() { assert which() == PersistedConstant.Which.PRIMITIVE_DATA: "Must check which() before get()ing a union member."; - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.factory,0,null, 0); + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.factory,0,null, 0); } public final boolean isRelocatable() { @@ -2799,14 +2799,14 @@ public final Reader asReader() { public final boolean hasData() { return !_pointerFieldIsNull(0); } - public final org.capnproto.StructList.Builder getData() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference.listFactory, 0, null, 0); + public final org.capnproto.StructList.Builder getData() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference.listFactory, 0, null, 0); } - public final void setData(org.capnproto.StructList.Reader value) { - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference.listFactory, 0, value); + public final void setData(org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference.listFactory, 0, value); } - public final org.capnproto.StructList.Builder initData(int size) { - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference.listFactory, 0, size); + public final org.capnproto.StructList.Builder initData(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference.listFactory, 0, size); } public final boolean isInstance() { return which() == PersistedConstant.Object.Which.INSTANCE; @@ -2860,8 +2860,8 @@ public Which which() { public final boolean hasData() { return !_pointerFieldIsNull(0); } - public final org.capnproto.StructList.Reader getData() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference.listFactory, 0, null, 0); + public final org.capnproto.StructList.Reader getData() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference.listFactory, 0, null, 0); } public final boolean isInstance() { @@ -3745,14 +3745,14 @@ public final org.capnproto.Text.Builder initClassName(int size) { public final boolean hasStore() { return !_pointerFieldIsNull(1); } - public final org.capnproto.StructList.Builder getStore() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.KeyStoreEntry.listFactory, 1, null, 0); + public final org.capnproto.StructList.Builder getStore() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.KeyStoreEntry.listFactory, 1, null, 0); } - public final void setStore(org.capnproto.StructList.Reader value) { - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.KeyStoreEntry.listFactory, 1, value); + public final void setStore(org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.KeyStoreEntry.listFactory, 1, value); } - public final org.capnproto.StructList.Builder initStore(int size) { - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.KeyStoreEntry.listFactory, 1, size); + public final org.capnproto.StructList.Builder initStore(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.KeyStoreEntry.listFactory, 1, size); } } @@ -3775,8 +3775,8 @@ public org.capnproto.Text.Reader getClassName() { public final boolean hasStore() { return !_pointerFieldIsNull(1); } - public final org.capnproto.StructList.Reader getStore() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.KeyStoreEntry.listFactory, 1, null, 0); + public final org.capnproto.StructList.Reader getStore() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.KeyStoreEntry.listFactory, 1, null, 0); } } @@ -3830,14 +3830,14 @@ public final org.capnproto.Text.Builder initTypeName(int size) { public final boolean hasValues() { return !_pointerFieldIsNull(1); } - public final org.capnproto.StructList.Builder getValues() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue.listFactory, 1, null, 0); + public final org.capnproto.StructList.Builder getValues() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue.listFactory, 1, null, 0); } - public final void setValues(org.capnproto.StructList.Reader value) { - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue.listFactory, 1, value); + public final void setValues(org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue.listFactory, 1, value); } - public final org.capnproto.StructList.Builder initValues(int size) { - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue.listFactory, 1, size); + public final org.capnproto.StructList.Builder initValues(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue.listFactory, 1, size); } } @@ -3856,8 +3856,8 @@ public org.capnproto.Text.Reader getTypeName() { public final boolean hasValues() { return !_pointerFieldIsNull(1); } - public final org.capnproto.StructList.Reader getValues() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue.listFactory, 1, null, 0); + public final org.capnproto.StructList.Reader getValues() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue.listFactory, 1, null, 0); } } @@ -3945,34 +3945,34 @@ public final org.capnproto.Text.Builder initString(int size) { public final boolean isPrimitive() { return which() == AnnotationValue.Which.PRIMITIVE; } - public final com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.Builder getPrimitive() { + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.Builder getPrimitive() { assert which() == AnnotationValue.Which.PRIMITIVE: "Must check which() before get()ing a union member."; - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.factory, 1, null, 0); + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.factory, 1, null, 0); } - public final void setPrimitive(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.Reader value) { + public final void setPrimitive(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.Reader value) { _setShortField(0, (short)AnnotationValue.Which.PRIMITIVE.ordinal()); - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.factory,1, value); + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.factory,1, value); } - public final com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.Builder initPrimitive() { + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.Builder initPrimitive() { _setShortField(0, (short)AnnotationValue.Which.PRIMITIVE.ordinal()); - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.factory,1, 0); + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.factory,1, 0); } public final boolean isPrimitiveArray() { return which() == AnnotationValue.Which.PRIMITIVE_ARRAY; } - public final com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.Builder getPrimitiveArray() { + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.Builder getPrimitiveArray() { assert which() == AnnotationValue.Which.PRIMITIVE_ARRAY: "Must check which() before get()ing a union member."; - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.factory, 1, null, 0); + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.factory, 1, null, 0); } - public final void setPrimitiveArray(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.Reader value) { + public final void setPrimitiveArray(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.Reader value) { _setShortField(0, (short)AnnotationValue.Which.PRIMITIVE_ARRAY.ordinal()); - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.factory,1, value); + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.factory,1, value); } - public final com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.Builder initPrimitiveArray() { + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.Builder initPrimitiveArray() { _setShortField(0, (short)AnnotationValue.Which.PRIMITIVE_ARRAY.ordinal()); - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.factory,1, 0); + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.factory,1, 0); } public final boolean isEnum() { return which() == AnnotationValue.Which.ENUM; @@ -4012,18 +4012,18 @@ public final org.capnproto.Text.Builder initClassName(int size) { public final boolean isAnnotation() { return which() == AnnotationValue.Which.ANNOTATION; } - public final com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.Builder getAnnotation() { + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.Builder getAnnotation() { assert which() == AnnotationValue.Which.ANNOTATION: "Must check which() before get()ing a union member."; - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.factory, 1, null, 0); + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.factory, 1, null, 0); } - public final void setAnnotation(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.Reader value) { + public final void setAnnotation(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.Reader value) { _setShortField(0, (short)AnnotationValue.Which.ANNOTATION.ordinal()); - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.factory,1, value); + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.factory,1, value); } - public final com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.Builder initAnnotation() { + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.Builder initAnnotation() { _setShortField(0, (short)AnnotationValue.Which.ANNOTATION.ordinal()); - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.factory,1, 0); + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.factory,1, 0); } public final boolean isMembers() { return which() == AnnotationValue.Which.MEMBERS; @@ -4081,10 +4081,10 @@ public final boolean isPrimitive() { public boolean hasPrimitive() { return !_pointerFieldIsNull(1); } - public com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.Reader getPrimitive() { + public com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.Reader getPrimitive() { assert which() == AnnotationValue.Which.PRIMITIVE: "Must check which() before get()ing a union member."; - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.factory,1,null, 0); + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveValue.factory,1,null, 0); } public final boolean isPrimitiveArray() { @@ -4093,10 +4093,10 @@ public final boolean isPrimitiveArray() { public boolean hasPrimitiveArray() { return !_pointerFieldIsNull(1); } - public com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.Reader getPrimitiveArray() { + public com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.Reader getPrimitiveArray() { assert which() == AnnotationValue.Which.PRIMITIVE_ARRAY: "Must check which() before get()ing a union member."; - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.factory,1,null, 0); + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PrimitiveArray.factory,1,null, 0); } public final boolean isEnum() { @@ -4123,10 +4123,10 @@ public final boolean isAnnotation() { public boolean hasAnnotation() { return !_pointerFieldIsNull(1); } - public com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.Reader getAnnotation() { + public com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.Reader getAnnotation() { assert which() == AnnotationValue.Which.ANNOTATION: "Must check which() before get()ing a union member."; - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.factory,1,null, 0); + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.Annotation.factory,1,null, 0); } public final boolean isMembers() { @@ -4278,14 +4278,14 @@ public final org.capnproto.Text.Builder initClassName(int size) { public final boolean hasMemberValues() { return !_pointerFieldIsNull(2); } - public final org.capnproto.StructList.Builder getMemberValues() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue.listFactory, 2, null, 0); + public final org.capnproto.StructList.Builder getMemberValues() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue.listFactory, 2, null, 0); } - public final void setMemberValues(org.capnproto.StructList.Reader value) { - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue.listFactory, 2, value); + public final void setMemberValues(org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue.listFactory, 2, value); } - public final org.capnproto.StructList.Builder initMemberValues(int size) { - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue.listFactory, 2, size); + public final org.capnproto.StructList.Builder initMemberValues(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue.listFactory, 2, size); } } @@ -4304,8 +4304,8 @@ public org.capnproto.Text.Reader getClassName() { public final boolean hasMemberValues() { return !_pointerFieldIsNull(2); } - public final org.capnproto.StructList.Reader getMemberValues() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue.listFactory, 2, null, 0); + public final org.capnproto.StructList.Reader getMemberValues() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue.listFactory, 2, null, 0); } } @@ -4408,74 +4408,74 @@ public final org.capnproto.PrimitiveList.Int.Builder initConstantsToRelink(int s public final boolean hasTypes() { return !_pointerFieldIsNull(1); } - public final org.capnproto.StructList.Builder getTypes() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType.listFactory, 1, null, 0); + public final org.capnproto.StructList.Builder getTypes() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType.listFactory, 1, null, 0); } - public final void setTypes(org.capnproto.StructList.Reader value) { - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType.listFactory, 1, value); + public final void setTypes(org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType.listFactory, 1, value); } - public final org.capnproto.StructList.Builder initTypes(int size) { - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType.listFactory, 1, size); + public final org.capnproto.StructList.Builder initTypes(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType.listFactory, 1, size); } public final boolean hasMethods() { return !_pointerFieldIsNull(2); } - public final org.capnproto.StructList.Builder getMethods() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod.listFactory, 2, null, 0); + public final org.capnproto.StructList.Builder getMethods() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod.listFactory, 2, null, 0); } - public final void setMethods(org.capnproto.StructList.Reader value) { - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod.listFactory, 2, value); + public final void setMethods(org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod.listFactory, 2, value); } - public final org.capnproto.StructList.Builder initMethods(int size) { - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod.listFactory, 2, size); + public final org.capnproto.StructList.Builder initMethods(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod.listFactory, 2, size); } public final boolean hasConstants() { return !_pointerFieldIsNull(3); } - public final org.capnproto.StructList.Builder getConstants() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant.listFactory, 3, null, 0); + public final org.capnproto.StructList.Builder getConstants() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant.listFactory, 3, null, 0); } - public final void setConstants(org.capnproto.StructList.Reader value) { - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant.listFactory, 3, value); + public final void setConstants(org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant.listFactory, 3, value); } - public final org.capnproto.StructList.Builder initConstants(int size) { - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant.listFactory, 3, size); + public final org.capnproto.StructList.Builder initConstants(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant.listFactory, 3, size); } public final boolean hasSingletonKeys() { return !_pointerFieldIsNull(4); } - public final org.capnproto.StructList.Builder getSingletonKeys() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonKey.listFactory, 4, null, 0); + public final org.capnproto.StructList.Builder getSingletonKeys() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonKey.listFactory, 4, null, 0); } - public final void setSingletonKeys(org.capnproto.StructList.Reader value) { - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonKey.listFactory, 4, value); + public final void setSingletonKeys(org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonKey.listFactory, 4, value); } - public final org.capnproto.StructList.Builder initSingletonKeys(int size) { - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonKey.listFactory, 4, size); + public final org.capnproto.StructList.Builder initSingletonKeys(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonKey.listFactory, 4, size); } public final boolean hasSingletonObjects() { return !_pointerFieldIsNull(5); } - public final org.capnproto.StructList.Builder getSingletonObjects() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonObject.listFactory, 5, null, 0); + public final org.capnproto.StructList.Builder getSingletonObjects() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonObject.listFactory, 5, null, 0); } - public final void setSingletonObjects(org.capnproto.StructList.Reader value) { - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonObject.listFactory, 5, value); + public final void setSingletonObjects(org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonObject.listFactory, 5, value); } - public final org.capnproto.StructList.Builder initSingletonObjects(int size) { - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonObject.listFactory, 5, size); + public final org.capnproto.StructList.Builder initSingletonObjects(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonObject.listFactory, 5, size); } public final boolean hasFields() { return !_pointerFieldIsNull(6); } - public final org.capnproto.StructList.Builder getFields() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisField.listFactory, 6, null, 0); + public final org.capnproto.StructList.Builder getFields() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisField.listFactory, 6, null, 0); } - public final void setFields(org.capnproto.StructList.Reader value) { - _setPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisField.listFactory, 6, value); + public final void setFields(org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisField.listFactory, 6, value); } - public final org.capnproto.StructList.Builder initFields(int size) { - return _initPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisField.listFactory, 6, size); + public final org.capnproto.StructList.Builder initFields(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisField.listFactory, 6, size); } } @@ -4522,43 +4522,43 @@ public final org.capnproto.PrimitiveList.Int.Reader getConstantsToRelink() { public final boolean hasTypes() { return !_pointerFieldIsNull(1); } - public final org.capnproto.StructList.Reader getTypes() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType.listFactory, 1, null, 0); + public final org.capnproto.StructList.Reader getTypes() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisType.listFactory, 1, null, 0); } public final boolean hasMethods() { return !_pointerFieldIsNull(2); } - public final org.capnproto.StructList.Reader getMethods() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod.listFactory, 2, null, 0); + public final org.capnproto.StructList.Reader getMethods() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod.listFactory, 2, null, 0); } public final boolean hasConstants() { return !_pointerFieldIsNull(3); } - public final org.capnproto.StructList.Reader getConstants() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant.listFactory, 3, null, 0); + public final org.capnproto.StructList.Reader getConstants() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedConstant.listFactory, 3, null, 0); } public final boolean hasSingletonKeys() { return !_pointerFieldIsNull(4); } - public final org.capnproto.StructList.Reader getSingletonKeys() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonKey.listFactory, 4, null, 0); + public final org.capnproto.StructList.Reader getSingletonKeys() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonKey.listFactory, 4, null, 0); } public final boolean hasSingletonObjects() { return !_pointerFieldIsNull(5); } - public final org.capnproto.StructList.Reader getSingletonObjects() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonObject.listFactory, 5, null, 0); + public final org.capnproto.StructList.Reader getSingletonObjects() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonObject.listFactory, 5, null, 0); } public final boolean hasFields() { return !_pointerFieldIsNull(6); } - public final org.capnproto.StructList.Reader getFields() { - return _getPointerField(com.oracle.graal.pointsto.heap.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisField.listFactory, 6, null, 0); + public final org.capnproto.StructList.Reader getFields() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisField.listFactory, 6, null, 0); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java index b8c1ce7648c1..79023003e7e8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java @@ -24,7 +24,6 @@ */ package com.oracle.svm.hosted.meta; -import com.oracle.graal.pointsto.heap.ImageLayerLoader; import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; import com.oracle.graal.pointsto.infrastructure.WrappedJavaField; import com.oracle.graal.pointsto.meta.AnalysisField; @@ -32,6 +31,8 @@ import com.oracle.svm.core.StaticFieldsSupport; import com.oracle.svm.core.meta.SharedField; import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; +import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerLoader; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -187,7 +188,7 @@ public JavaConstant getStaticFieldBase() { AnalysisUniverse universe = type.wrapped.getUniverse(); boolean primitive = getStorageKind().isPrimitive(); if (isInBaseLayer()) { - ImageLayerLoader imageLayerLoader = universe.getImageLayerLoader(); + SVMImageLayerLoader imageLayerLoader = HostedImageLayerBuildingSupport.singleton().getLoader(); return primitive ? imageLayerLoader.getBaseLayerStaticPrimitiveFields() : imageLayerLoader.getBaseLayerStaticObjectFields(); } return universe.getSnippetReflection().forObject(primitive ? StaticFieldsSupport.getStaticPrimitiveFields() : StaticFieldsSupport.getStaticObjectFields()); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java index 9fd4be7c151f..3b763ee5cf20 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java @@ -44,7 +44,6 @@ import java.util.function.Function; import java.util.stream.Collectors; -import jdk.graal.compiler.serviceprovider.GraalServices; import org.graalvm.nativeimage.c.function.CEntryPointLiteral; import org.graalvm.nativeimage.c.function.CFunction; import org.graalvm.nativeimage.c.function.CFunctionPointer; @@ -107,6 +106,7 @@ import jdk.graal.compiler.core.common.NumUtil; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.debug.Indent; +import jdk.graal.compiler.serviceprovider.GraalServices; import jdk.internal.vm.annotation.Contended; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.ExceptionHandler; @@ -779,7 +779,7 @@ private void layoutStaticFields() { if (skipStaticField(field)) { // does not require memory. } else if (field.wrapped.isInBaseLayer()) { - field.setLocation(aUniverse.getImageLayerLoader().getFieldLocation(field.wrapped)); + field.setLocation(HostedImageLayerBuildingSupport.singleton().getLoader().getFieldLocation(field.wrapped)); } else if (field.getStorageKind() == JavaKind.Object) { field.setLocation(NumUtil.safeToInt(layout.getArrayElementOffset(JavaKind.Object, nextObjectField))); nextObjectField += 1;