From cc18eee8925f5c4d0341731230ac315e11038826 Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Thu, 23 Nov 2023 12:46:06 +0100 Subject: [PATCH 1/4] Initialize the application layer heap after the base layer heap --- .../graal/pointsto/heap/ImageLayerLoader.java | 9 +++ .../pointsto/heap/ImageLayerSnapshotUtil.java | 1 + .../graal/pointsto/heap/ImageLayerWriter.java | 5 ++ .../oracle/svm/core/genscavenge/HeapImpl.java | 17 ++++- .../posix/linux/LinuxImageHeapProvider.java | 67 ++++++++++++++-- .../src/com/oracle/svm/core/heap/Heap.java | 9 +++ .../layeredimage/LayeredImageHeapSymbols.java | 52 +++++++++++++ .../svm/hosted/NativeImageGenerator.java | 5 ++ .../oracle/svm/hosted/image/NativeImage.java | 76 ++++++++++++++----- 9 files changed, 216 insertions(+), 25 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimage/LayeredImageHeapSymbols.java diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java index 506ed4418e54..e39fda9b49e7 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java @@ -40,6 +40,7 @@ import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.FIELD_READ_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.FIELD_WRITTEN_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.ID_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IMAGE_HEAP_SIZE_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INSTANCE_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INTERFACES_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_ENUM_TAG; @@ -252,6 +253,8 @@ public class ImageLayerLoader { protected EconomicMap jsonMap; + private long imageHeapSize; + public ImageLayerLoader() { this(new ImageLayerSnapshotUtil(), List.of()); } @@ -308,6 +311,8 @@ private void loadLayerAnalysis0() { int nextFieldId = get(jsonMap, NEXT_FIELD_ID_TAG); universe.setStartFieldId(nextFieldId); + imageHeapSize = Long.parseLong(get(jsonMap, IMAGE_HEAP_SIZE_TAG)); + /* This mapping allows one to get the base layer information from a type id */ EconomicMap typesMap = get(jsonMap, TYPES_TAG); MapCursor typesCursor = typesMap.getEntries(); @@ -985,4 +990,8 @@ private ImageHeapConstant getTaggedImageHeapConstant(String tag) { int id = get(jsonMap, tag); return constants.get(id); } + + public long getImageHeapSize() { + return imageHeapSize; + } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java index bfba72e2ec88..311b3354cce6 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java @@ -74,6 +74,7 @@ public class ImageLayerSnapshotUtil { public static final String NEXT_TYPE_ID_TAG = "next type id"; public static final String NEXT_METHOD_ID_TAG = "next method id"; public static final String NEXT_FIELD_ID_TAG = "next field id"; + public static final String IMAGE_HEAP_SIZE_TAG = "image heap size"; public static final String VALUE_TAG = "value"; public static final String ENUM_CLASS_TAG = "enum class"; public static final String ENUM_NAME_TAG = "enum name"; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java index 7c29e73b8231..733db7287ed9 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java @@ -41,6 +41,7 @@ import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.FIELD_WRITTEN_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IDENTITY_HASH_CODE_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.ID_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IMAGE_HEAP_SIZE_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INSTANCE_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.INTERFACES_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_ENUM_TAG; @@ -145,6 +146,10 @@ public void dumpFile() { FileDumpingUtil.dumpFile(fileInfo.layerSnapshotPath, fileInfo.fileName, fileInfo.suffix, writer -> JSONFormatter.printJSON(jsonMap, writer)); } + public void persistImageHeapSize(long imageHeapSize) { + jsonMap.put(IMAGE_HEAP_SIZE_TAG, String.valueOf(imageHeapSize)); + } + public void persistAnalysisInfo(Universe hostedUniverse, AnalysisUniverse analysisUniverse) { persistHook(hostedUniverse, analysisUniverse); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java index ecf4502bc38a..64a1e0e006e9 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java @@ -433,15 +433,28 @@ public int getPreferredAddressSpaceAlignment() { @Fold @Override public int getImageHeapOffsetInAddressSpace() { + int imageHeapOffset = 0; if (SubstrateOptions.SpawnIsolates.getValue() && SubstrateOptions.UseNullRegion.getValue()) { /* * The image heap will be mapped in a way that there is a memory protected gap between * the heap base and the start of the image heap. The gap won't need any memory in the * native image file. */ - return NumUtil.safeToInt(SerialAndEpsilonGCOptions.AlignedHeapChunkSize.getValue()); + imageHeapOffset = NumUtil.safeToInt(SerialAndEpsilonGCOptions.AlignedHeapChunkSize.getValue()); } - return 0; + /* + * GR-53993: With ImageLayerSupport, it would be possible to fetch the startOffset from the + * loader instead of storing it in the Heap. + */ + if (SubstrateOptions.LoadImageLayer.hasBeenSet()) { + /* + * GR-53964: The page size used to round up the start offset should be the same as the + * one used in run time. + */ + int runtimePageSize = 4096; + imageHeapOffset = NumUtil.roundUp(imageHeapOffset + NumUtil.safeToInt(startOffset), runtimePageSize); + } + return imageHeapOffset; } @Fold diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java index 5915a3a0137d..cb941c192b8b 100644 --- a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxImageHeapProvider.java @@ -31,11 +31,20 @@ import static com.oracle.svm.core.Isolates.IMAGE_HEAP_RELOCATABLE_END; import static com.oracle.svm.core.Isolates.IMAGE_HEAP_WRITABLE_BEGIN; import static com.oracle.svm.core.Isolates.IMAGE_HEAP_WRITABLE_END; +import static com.oracle.svm.core.layeredimage.LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_A_RELOCATABLE_POINTER; +import static com.oracle.svm.core.layeredimage.LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_BEGIN; +import static com.oracle.svm.core.layeredimage.LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_END; +import static com.oracle.svm.core.layeredimage.LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_RELOCATABLE_BEGIN; +import static com.oracle.svm.core.layeredimage.LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_RELOCATABLE_END; +import static com.oracle.svm.core.layeredimage.LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_WRITABLE_BEGIN; +import static com.oracle.svm.core.layeredimage.LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_WRITABLE_END; import static com.oracle.svm.core.posix.linux.ProcFSSupport.findMapping; import static com.oracle.svm.core.util.PointerUtils.roundDown; +import static com.oracle.svm.core.util.UnsignedUtils.isAMultiple; import static com.oracle.svm.core.util.UnsignedUtils.roundUp; import static org.graalvm.word.WordFactory.signed; +import java.nio.ByteBuffer; import java.util.concurrent.ThreadLocalRandom; import org.graalvm.nativeimage.StackValue; @@ -47,8 +56,10 @@ import org.graalvm.word.PointerBase; import org.graalvm.word.SignedWord; import org.graalvm.word.UnsignedWord; +import org.graalvm.word.WordBase; import org.graalvm.word.WordFactory; +import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.c.CGlobalData; import com.oracle.svm.core.c.CGlobalDataFactory; @@ -68,6 +79,7 @@ import com.oracle.svm.core.util.VMError; import jdk.graal.compiler.word.Word; +import jdk.vm.ci.code.Architecture; /** * An optimal image heap provider for Linux which creates isolate image heaps that retain the @@ -91,11 +103,41 @@ public class LinuxImageHeapProvider extends AbstractImageHeapProvider { private static final SignedWord UNASSIGNED_FD = signed(-1); private static final SignedWord CANNOT_OPEN_FD = signed(-2); - private static final CGlobalData CACHED_IMAGE_FD = CGlobalDataFactory.createWord(UNASSIGNED_FD); - private static final CGlobalData CACHED_IMAGE_HEAP_OFFSET_IN_FILE = CGlobalDataFactory.createWord(); + + private static final int IMAGE_COUNT = 2; + private static final CGlobalData CACHED_IMAGE_FDS = CGlobalDataFactory.createBytes(() -> createWords(IMAGE_COUNT, UNASSIGNED_FD)); + private static final CGlobalData CACHED_IMAGE_HEAP_OFFSETS = CGlobalDataFactory.createBytes(() -> createWords(IMAGE_COUNT, WordFactory.zero())); private static final int MAX_PATHLEN = 4096; + private static byte[] createWords(int count, WordBase initialValue) { + Architecture arch = ConfigurationValues.getTarget().arch; + assert arch.getWordSize() == Long.BYTES : "currently hard-coded for 8 byte words"; + ByteBuffer buffer = ByteBuffer.allocate(count * Long.BYTES).order(arch.getByteOrder()); + for (int i = 0; i < count; i++) { + buffer.putLong(initialValue.rawValue()); + } + return buffer.array(); + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + protected UnsignedWord getImageHeapAddressSpaceSize() { + if (SubstrateOptions.ImageLayer.hasBeenSet() || SubstrateOptions.LoadImageLayer.hasBeenSet()) { + int imageHeapOffset = Heap.getHeap().getImageHeapOffsetInAddressSpace(); + assert imageHeapOffset >= 0; + UnsignedWord size = WordFactory.unsigned(imageHeapOffset); + UnsignedWord granularity = VirtualMemoryProvider.get().getGranularity(); + assert isAMultiple(size, granularity); + size = size.add(getImageHeapSizeInFile(IMAGE_HEAP_BEGIN.get(), IMAGE_HEAP_END.get())); + size = roundUp(size, granularity); + size = size.add(getImageHeapSizeInFile(SECOND_IMAGE_HEAP_BEGIN.get(), SECOND_IMAGE_HEAP_END.get())); + return size; + } else { + return super.getImageHeapAddressSpaceSize(); + } + } + @Override @Uninterruptible(reason = "Called during isolate initialization.") public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, WordPointer basePointer, WordPointer endPointer) { @@ -143,15 +185,30 @@ public int initialize(Pointer reservedAddressSpace, UnsignedWord reservedSize, W int imageHeapOffsetInAddressSpace = Heap.getHeap().getImageHeapOffsetInAddressSpace(); basePointer.write(heapBase); - Pointer imageHeapStart = heapBase.add(imageHeapOffsetInAddressSpace); + Pointer firstHeapStart = heapBase.add(imageHeapOffsetInAddressSpace); remainingSize = remainingSize.subtract(imageHeapOffsetInAddressSpace); - int result = initializeImageHeap(imageHeapStart, remainingSize, endPointer, - CACHED_IMAGE_FD.get(), CACHED_IMAGE_HEAP_OFFSET_IN_FILE.get(), MAGIC.get(), + boolean layeredImage = SubstrateOptions.ImageLayer.hasBeenSet() || SubstrateOptions.LoadImageLayer.hasBeenSet(); + WordPointer firstEndPtr = layeredImage ? StackValue.get(WordPointer.class) : endPointer; + int result = initializeImageHeap(firstHeapStart, remainingSize, firstEndPtr, + CACHED_IMAGE_FDS.get().addressOf(0), CACHED_IMAGE_HEAP_OFFSETS.get().addressOf(0), MAGIC.get(), IMAGE_HEAP_BEGIN.get(), IMAGE_HEAP_END.get(), IMAGE_HEAP_RELOCATABLE_BEGIN.get(), IMAGE_HEAP_A_RELOCATABLE_POINTER.get(), IMAGE_HEAP_RELOCATABLE_END.get(), IMAGE_HEAP_WRITABLE_BEGIN.get(), IMAGE_HEAP_WRITABLE_END.get()); if (result != CEntryPointErrors.NO_ERROR) { freeImageHeap(selfReservedHeapBase); + return result; + } + if (SubstrateOptions.ImageLayer.hasBeenSet() || SubstrateOptions.LoadImageLayer.hasBeenSet()) { + Pointer secondHeapStart = firstEndPtr.read(); // aligned + remainingSize = remainingSize.subtract(secondHeapStart.subtract(firstHeapStart)); + result = initializeImageHeap(secondHeapStart, remainingSize, endPointer, + CACHED_IMAGE_FDS.get().addressOf(1), CACHED_IMAGE_HEAP_OFFSETS.get().addressOf(1), MAGIC.get(), + SECOND_IMAGE_HEAP_BEGIN.get(), SECOND_IMAGE_HEAP_END.get(), + SECOND_IMAGE_HEAP_RELOCATABLE_BEGIN.get(), SECOND_IMAGE_HEAP_A_RELOCATABLE_POINTER.get(), SECOND_IMAGE_HEAP_RELOCATABLE_END.get(), + SECOND_IMAGE_HEAP_WRITABLE_BEGIN.get(), SECOND_IMAGE_HEAP_WRITABLE_END.get()); + if (result != CEntryPointErrors.NO_ERROR) { + freeImageHeap(selfReservedHeapBase); + } } return result; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java index 67e0b9798627..f2b5fbbee88f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Heap.java @@ -48,6 +48,8 @@ import jdk.graal.compiler.api.replacements.Fold; public abstract class Heap { + protected long startOffset; + @Fold public static Heap getHeap() { return ImageSingletons.lookup(Heap.class); @@ -250,4 +252,11 @@ public Pointer getImageHeapStart() { */ @Uninterruptible(reason = "Ensure that no GC can occur between this call and usage of the salt.", callerMustBe = true) public abstract long getIdentityHashSalt(Object obj); + + /** + * Sets the start offset of the heap. + */ + public void setStartOffset(long startOffset) { + this.startOffset = startOffset; + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimage/LayeredImageHeapSymbols.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimage/LayeredImageHeapSymbols.java new file mode 100644 index 000000000000..165fe15c8303 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimage/LayeredImageHeapSymbols.java @@ -0,0 +1,52 @@ +/* + * 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.core.layeredimage; + +import com.oracle.svm.core.c.CGlobalData; +import com.oracle.svm.core.c.CGlobalDataFactory; + +import jdk.graal.compiler.word.Word; + +/** + * Stores the heap symbols for the application layer. This is a temporary solution and should be + * fixed with GR-53995. + */ +public class LayeredImageHeapSymbols { + public static final String SECOND_IMAGE_HEAP_BEGIN_SYMBOL_NAME = "__svm_second_heap_begin"; + public static final String SECOND_IMAGE_HEAP_END_SYMBOL_NAME = "__svm_second_heap_end"; + public static final String SECOND_IMAGE_HEAP_RELOCATABLE_BEGIN_SYMBOL_NAME = "__svm_second_heap_relocatable_begin"; + public static final String SECOND_IMAGE_HEAP_RELOCATABLE_END_SYMBOL_NAME = "__svm_second_heap_relocatable_end"; + public static final String SECOND_IMAGE_HEAP_A_RELOCATABLE_POINTER_SYMBOL_NAME = "__svm_second_heap_a_relocatable_pointer"; + public static final String SECOND_IMAGE_HEAP_WRITABLE_BEGIN_SYMBOL_NAME = "__svm_second_heap_writable_begin"; + public static final String SECOND_IMAGE_HEAP_WRITABLE_END_SYMBOL_NAME = "__svm_second_heap_writable_end"; + + public static final CGlobalData SECOND_IMAGE_HEAP_BEGIN = CGlobalDataFactory.forSymbol(SECOND_IMAGE_HEAP_BEGIN_SYMBOL_NAME); + public static final CGlobalData SECOND_IMAGE_HEAP_END = CGlobalDataFactory.forSymbol(SECOND_IMAGE_HEAP_END_SYMBOL_NAME); + public static final CGlobalData SECOND_IMAGE_HEAP_RELOCATABLE_BEGIN = CGlobalDataFactory.forSymbol(SECOND_IMAGE_HEAP_RELOCATABLE_BEGIN_SYMBOL_NAME); + public static final CGlobalData SECOND_IMAGE_HEAP_RELOCATABLE_END = CGlobalDataFactory.forSymbol(SECOND_IMAGE_HEAP_RELOCATABLE_END_SYMBOL_NAME); + public static final CGlobalData SECOND_IMAGE_HEAP_A_RELOCATABLE_POINTER = CGlobalDataFactory.forSymbol(SECOND_IMAGE_HEAP_A_RELOCATABLE_POINTER_SYMBOL_NAME); + public static final CGlobalData SECOND_IMAGE_HEAP_WRITABLE_BEGIN = CGlobalDataFactory.forSymbol(SECOND_IMAGE_HEAP_WRITABLE_BEGIN_SYMBOL_NAME); + public static final CGlobalData SECOND_IMAGE_HEAP_WRITABLE_END = CGlobalDataFactory.forSymbol(SECOND_IMAGE_HEAP_WRITABLE_END_SYMBOL_NAME); +} 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 953b8b7bf53f..ae77c16b8871 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 @@ -168,6 +168,7 @@ import com.oracle.svm.core.graal.word.SubstrateWordOperationPlugins; import com.oracle.svm.core.graal.word.SubstrateWordTypes; import com.oracle.svm.core.heap.BarrierSetProvider; +import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.RestrictHeapAccessCallees; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.hub.LayoutEncoding; @@ -1042,6 +1043,10 @@ protected void setupNativeImage(OptionValues options, Map feature.duringSetup(config)); } + if (SVMImageLayerSupport.singleton().loadAnalysis()) { + Heap.getHeap().setStartOffset(SVMImageLayerSupport.singleton().getLoader().getImageHeapSize()); + } + initializeBigBang(bb, options, featureHandler, nativeLibraries, debug, aMetaAccess, aUniverse.getSubstitutions(), loader, true, new SubstrateClassInitializationPlugin((SVMHost) aUniverse.hostVM()), this.isStubBasedPluginsSupported(), aProviders); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java index 595be791477d..f3c262d260ef 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java @@ -91,12 +91,14 @@ import com.oracle.svm.core.graal.code.CGlobalDataReference; import com.oracle.svm.core.image.ImageHeapLayoutInfo; import com.oracle.svm.core.image.ImageHeapPartition; +import com.oracle.svm.core.layeredimage.LayeredImageHeapSymbols; import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.NativeImageOptions; +import com.oracle.svm.hosted.SVMImageLayerSupport; import com.oracle.svm.hosted.c.CGlobalDataFeature; import com.oracle.svm.hosted.c.NativeLibraries; import com.oracle.svm.hosted.c.codegen.CSourceCodeWriter; @@ -135,7 +137,7 @@ public abstract class NativeImage extends AbstractImage { private final Set uniqueEntryPoints = new HashSet<>(); private final MethodPointerRelocationProvider relocationProvider; - private long imageHeapSize = -1; + private ImageHeapLayoutInfo heapLayout; // The sections of the native image. private Section textSection; @@ -416,7 +418,7 @@ public void build(String imageName, DebugContext debug) { long roSectionSize = codeCache.getAlignedConstantsSize(); long rwSectionSize = ConfigurationValues.getObjectLayout().alignUp(cGlobals.getSize()); - ImageHeapLayoutInfo heapLayout = heap.getLayouter().layout(heap, objectFile.getPageSize()); + heapLayout = heap.getLayouter().layout(heap, objectFile.getPageSize()); // after this point, the layout is final and must not be changed anymore assert !hasDuplicatedObjects(heap.getObjects()) : "heap.getObjects() must not contain any duplicates"; @@ -424,23 +426,29 @@ public void build(String imageName, DebugContext debug) { heap.getLayouter().afterLayout(heap); - imageHeapSize = heapLayout.getImageHeapSize(); + int pageSize = objectFile.getPageSize(); + + long imageHeapSize = getImageHeapSize(); + + if (SVMImageLayerSupport.singleton().persistAnalysis()) { + SVMImageLayerSupport.singleton().getWriter().persistImageHeapSize(imageHeapSize); + } // Text section (code) final int textSectionSize = codeCache.getCodeCacheSize(); final RelocatableBuffer textBuffer = new RelocatableBuffer(textSectionSize, objectFile.getByteOrder()); final NativeTextSectionImpl textImpl = NativeTextSectionImpl.factory(textBuffer, objectFile, codeCache); - textSection = objectFile.newProgbitsSection(SectionName.TEXT.getFormatDependentName(objectFile.getFormat()), objectFile.getPageSize(), false, true, textImpl); + textSection = objectFile.newProgbitsSection(SectionName.TEXT.getFormatDependentName(objectFile.getFormat()), pageSize, false, true, textImpl); // Read-only data section final RelocatableBuffer roDataBuffer = new RelocatableBuffer(roSectionSize, objectFile.getByteOrder()); final ProgbitsSectionImpl roDataImpl = new BasicProgbitsSectionImpl(roDataBuffer.getBackingArray()); - roDataSection = objectFile.newProgbitsSection(SectionName.RODATA.getFormatDependentName(objectFile.getFormat()), objectFile.getPageSize(), false, false, roDataImpl); + roDataSection = objectFile.newProgbitsSection(SectionName.RODATA.getFormatDependentName(objectFile.getFormat()), pageSize, false, false, roDataImpl); // Read-write data section final RelocatableBuffer rwDataBuffer = new RelocatableBuffer(rwSectionSize, objectFile.getByteOrder()); final ProgbitsSectionImpl rwDataImpl = new BasicProgbitsSectionImpl(rwDataBuffer.getBackingArray()); - rwDataSection = objectFile.newProgbitsSection(SectionName.DATA.getFormatDependentName(objectFile.getFormat()), objectFile.getPageSize(), true, false, rwDataImpl); + rwDataSection = objectFile.newProgbitsSection(SectionName.DATA.getFormatDependentName(objectFile.getFormat()), pageSize, true, false, rwDataImpl); // Define symbols for the sections. objectFile.createDefinedSymbol(textSection.getName(), textSection, 0, 0, false, false); @@ -465,13 +473,12 @@ public void build(String imageName, DebugContext debug) { // - Write the heap to its own section. // Dynamic linkers/loaders generally don't ensure any alignment to more than page // boundaries, so we take care of this ourselves in CommittedMemoryProvider, if we can. - int alignment = objectFile.getPageSize(); + int alignment = pageSize; // Manually add padding to the SVM_HEAP section, because when SpawnIsolates are disabled // we operate with mprotect on it with page size granularity. long paddedImageHeapSize = SpawnIsolates.getValue() ? imageHeapSize : NumUtil.roundUp(imageHeapSize, alignment); RelocatableBuffer heapSectionBuffer = new RelocatableBuffer(paddedImageHeapSize, objectFile.getByteOrder()); - ProgbitsSectionImpl heapSectionImpl = new BasicProgbitsSectionImpl(heapSectionBuffer.getBackingArray()); // Note: On isolate startup the read only part of the heap will be set up as such. heapSection = objectFile.newProgbitsSection(SectionName.SVM_HEAP.getFormatDependentName(objectFile.getFormat()), alignment, true, false, heapSectionImpl); @@ -480,14 +487,48 @@ public void build(String imageName, DebugContext debug) { long sectionOffsetOfARelocatablePointer = writer.writeHeap(debug, heapSectionBuffer); assert !SpawnIsolates.getValue() || heapSectionBuffer.getByteBuffer().getLong((int) sectionOffsetOfARelocatablePointer) == 0L; - defineDataSymbol(Isolates.IMAGE_HEAP_BEGIN_SYMBOL_NAME, heapSection, 0); - defineDataSymbol(Isolates.IMAGE_HEAP_END_SYMBOL_NAME, heapSection, imageHeapSize); - defineDataSymbol(Isolates.IMAGE_HEAP_RELOCATABLE_BEGIN_SYMBOL_NAME, heapSection, heapLayout.getReadOnlyRelocatableOffset() - heapLayout.getStartOffset()); - defineDataSymbol(Isolates.IMAGE_HEAP_RELOCATABLE_END_SYMBOL_NAME, heapSection, - heapLayout.getReadOnlyRelocatableOffset() + heapLayout.getReadOnlyRelocatableSize() - heapLayout.getStartOffset()); - defineDataSymbol(Isolates.IMAGE_HEAP_A_RELOCATABLE_POINTER_SYMBOL_NAME, heapSection, sectionOffsetOfARelocatablePointer); - defineDataSymbol(Isolates.IMAGE_HEAP_WRITABLE_BEGIN_SYMBOL_NAME, heapSection, heapLayout.getWritableOffset() - heapLayout.getStartOffset()); - defineDataSymbol(Isolates.IMAGE_HEAP_WRITABLE_END_SYMBOL_NAME, heapSection, heapLayout.getWritableOffset() + heapLayout.getWritableSize() - heapLayout.getStartOffset()); + if (!SVMImageLayerSupport.singleton().hasLoader()) { + defineDataSymbol(Isolates.IMAGE_HEAP_BEGIN_SYMBOL_NAME, heapSection, 0); + defineDataSymbol(Isolates.IMAGE_HEAP_END_SYMBOL_NAME, heapSection, imageHeapSize); + defineDataSymbol(Isolates.IMAGE_HEAP_RELOCATABLE_BEGIN_SYMBOL_NAME, heapSection, heapLayout.getReadOnlyRelocatableOffset() - heapLayout.getStartOffset()); + defineDataSymbol(Isolates.IMAGE_HEAP_RELOCATABLE_END_SYMBOL_NAME, heapSection, + heapLayout.getReadOnlyRelocatableOffset() + heapLayout.getReadOnlyRelocatableSize() - heapLayout.getStartOffset()); + defineDataSymbol(Isolates.IMAGE_HEAP_A_RELOCATABLE_POINTER_SYMBOL_NAME, heapSection, sectionOffsetOfARelocatablePointer); + defineDataSymbol(Isolates.IMAGE_HEAP_WRITABLE_BEGIN_SYMBOL_NAME, heapSection, heapLayout.getWritableOffset() - heapLayout.getStartOffset()); + defineDataSymbol(Isolates.IMAGE_HEAP_WRITABLE_END_SYMBOL_NAME, heapSection, heapLayout.getWritableOffset() + heapLayout.getWritableSize() - heapLayout.getStartOffset()); + + if (SVMImageLayerSupport.singleton().persistAnalysis()) { + objectFile.createUndefinedSymbol(LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_BEGIN_SYMBOL_NAME, 0, false); + objectFile.createUndefinedSymbol(LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_END_SYMBOL_NAME, 0, false); + objectFile.createUndefinedSymbol(LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_RELOCATABLE_BEGIN_SYMBOL_NAME, 0, false); + objectFile.createUndefinedSymbol(LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_RELOCATABLE_END_SYMBOL_NAME, 0, false); + objectFile.createUndefinedSymbol(LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_A_RELOCATABLE_POINTER_SYMBOL_NAME, 0, false); + objectFile.createUndefinedSymbol(LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_WRITABLE_BEGIN_SYMBOL_NAME, 0, false); + objectFile.createUndefinedSymbol(LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_WRITABLE_END_SYMBOL_NAME, 0, false); + } + } else { + objectFile.createUndefinedSymbol(Isolates.IMAGE_HEAP_BEGIN_SYMBOL_NAME, 0, false); + objectFile.createUndefinedSymbol(Isolates.IMAGE_HEAP_END_SYMBOL_NAME, 0, false); + objectFile.createUndefinedSymbol(Isolates.IMAGE_HEAP_RELOCATABLE_BEGIN_SYMBOL_NAME, 0, false); + objectFile.createUndefinedSymbol(Isolates.IMAGE_HEAP_RELOCATABLE_END_SYMBOL_NAME, 0, false); + objectFile.createUndefinedSymbol(Isolates.IMAGE_HEAP_A_RELOCATABLE_POINTER_SYMBOL_NAME, 0, false); + objectFile.createUndefinedSymbol(Isolates.IMAGE_HEAP_WRITABLE_BEGIN_SYMBOL_NAME, 0, false); + objectFile.createUndefinedSymbol(Isolates.IMAGE_HEAP_WRITABLE_END_SYMBOL_NAME, 0, false); + + boolean global = true; // keep heap section alive + objectFile.createDefinedSymbol(LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_BEGIN_SYMBOL_NAME, heapSection, 0, wordSize, false, global); + objectFile.createDefinedSymbol(LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_END_SYMBOL_NAME, heapSection, imageHeapSize, wordSize, false, global); + objectFile.createDefinedSymbol(LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_RELOCATABLE_BEGIN_SYMBOL_NAME, heapSection, + heapLayout.getReadOnlyRelocatableOffset() - heapLayout.getStartOffset(), wordSize, false, global); + objectFile.createDefinedSymbol(LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_RELOCATABLE_END_SYMBOL_NAME, heapSection, + heapLayout.getReadOnlyRelocatableOffset() + heapLayout.getReadOnlyRelocatableSize() - heapLayout.getStartOffset(), wordSize, false, global); + objectFile.createDefinedSymbol(LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_A_RELOCATABLE_POINTER_SYMBOL_NAME, heapSection, + sectionOffsetOfARelocatablePointer, wordSize, false, global); + objectFile.createDefinedSymbol(LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_WRITABLE_BEGIN_SYMBOL_NAME, heapSection, + heapLayout.getWritableOffset() - heapLayout.getStartOffset(), wordSize, false, global); + objectFile.createDefinedSymbol(LayeredImageHeapSymbols.SECOND_IMAGE_HEAP_WRITABLE_END_SYMBOL_NAME, heapSection, + heapLayout.getWritableOffset() + heapLayout.getWritableSize() - heapLayout.getStartOffset(), wordSize, false, global); + } // Mark the sections with the relocations from the maps. markRelocationSitesFromBuffer(textBuffer, textImpl); @@ -771,8 +812,7 @@ public static String globalSymbolNameForMethod(ResolvedJavaMethod sm) { @Override public long getImageHeapSize() { - assert imageHeapSize > -1 : "imageHeapSize accessed before set"; - return imageHeapSize; + return heapLayout.getImageHeapSize(); } @Override From 5ab5204fd3da9b8ea4dbca696c4d0bc66e1cbfc7 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Thu, 2 May 2024 17:07:44 +0200 Subject: [PATCH 2/4] Allow methods to be inlined in the application layer --- .../src/com/oracle/graal/pointsto/meta/AnalysisMethod.java | 3 --- 1 file changed, 3 deletions(-) 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 2755e01e8ea9..740a1c1df1b4 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 @@ -775,9 +775,6 @@ public Type[] getGenericParameterTypes() { @Override public boolean canBeInlined() { - if (isInBaseLayer) { - return false; - } return !hasNeverInlineDirective(); } From 31e479307f0c488bb136faea32e2a5526d7b7590 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Tue, 7 May 2024 12:51:06 +0200 Subject: [PATCH 3/4] Remove symbols options --- .../src/com/oracle/svm/core/SubstrateOptions.java | 4 ---- .../src/com/oracle/svm/hosted/image/CCLinkerInvocation.java | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index b930b5f55b30..31d8391f385e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -112,7 +112,6 @@ protected void onValueUpdate(EconomicMap, Object> values, Boolean o ClosedTypeWorld.update(values, !newValue); PersistImageLayerAnalysis.update(values, newValue); PersistImageLayerSingletons.update(values, newValue); - DeleteLocalSymbols.update(values, !newValue); StripDebugInfo.update(values, !newValue); InternalSymbolsAreGlobal.update(values, newValue); AOTTrivialInline.update(values, !newValue); @@ -722,8 +721,6 @@ public static boolean useLIRBackend() { */ @Option(help = "Use linker option to prevent unreferenced symbols in image.")// public static final HostedOptionKey RemoveUnusedSymbols = new HostedOptionKey<>(OS.getCurrent() != OS.DARWIN); - @Option(help = "Keep all undefined symbols.")// - public static final HostedOptionKey PreserveUndefinedSymbols = new HostedOptionKey<>(false); @Option(help = "Ignore undefined symbols referenced from the built image.")// public static final HostedOptionKey IgnoreUndefinedReferences = new HostedOptionKey<>(false); @Option(help = "Use linker option to remove all local symbols from image.")// @@ -1152,7 +1149,6 @@ public static boolean closedTypeWorld() { public void update(EconomicMap, Object> values, Object boxedValue) { super.update(values, boxedValue); ClosedTypeWorld.update(values, false); - PreserveUndefinedSymbols.update(values, true); /* Ignore any potential undefined references caused by inlining in base layer. */ IgnoreUndefinedReferences.update(values, true); AOTTrivialInline.update(values, false); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java index 9e35d03b795e..b47c8d986997 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java @@ -99,7 +99,7 @@ public List getImageSymbols(boolean onlyGlobal) { Set globalHiddenSymbols = CGlobalDataFeature.singleton().getGlobalHiddenSymbols(); stream = stream.filter(symbol -> symbol.isGlobal() && !globalHiddenSymbols.contains(symbol.getName())); } - if (!(SubstrateOptions.useLLVMBackend() || SubstrateOptions.PreserveUndefinedSymbols.getValue())) { + if (!SubstrateOptions.useLLVMBackend()) { stream = stream.filter(ObjectFile.Symbol::isDefined); } return stream.map(this::getSymbolName).collect(Collectors.toList()); From 09ae8a8f329da90161a1dd1b72adc43f74b59bac Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Tue, 7 May 2024 13:14:11 +0200 Subject: [PATCH 4/4] Avoid using InternalSymbolsAreGlobals for the base layer and only have the method symbols as globals --- .../src/com/oracle/svm/core/SubstrateOptions.java | 1 - .../src/com/oracle/svm/hosted/image/NativeImage.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 31d8391f385e..9afda06e2a0b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -113,7 +113,6 @@ protected void onValueUpdate(EconomicMap, Object> values, Boolean o PersistImageLayerAnalysis.update(values, newValue); PersistImageLayerSingletons.update(values, newValue); StripDebugInfo.update(values, !newValue); - InternalSymbolsAreGlobal.update(values, newValue); AOTTrivialInline.update(values, !newValue); if (imageLayerEnabledHandler != null) { imageLayerEnabledHandler.onOptionEnabled(values); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java index f3c262d260ef..8037d6f860aa 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java @@ -971,7 +971,7 @@ protected void writeTextSection(DebugContext debug, final Section textSection, f HostedMethod current = pair.getLeft(); final String symName = localSymbolNameForMethod(current); final String signatureString = current.getUniqueShortName(); - defineMethodSymbol(textSection, current, methodsBySignature, signatureString, symName, SubstrateOptions.InternalSymbolsAreGlobal.getValue(), pair.getRight()); + defineMethodSymbol(textSection, current, methodsBySignature, signatureString, symName, SVMImageLayerSupport.singleton().persistAnalysis(), pair.getRight()); } // 2. fq without return type -- only for entry points! for (Map.Entry ent : methodsBySignature.entrySet()) {