From 264eb324b4e73a233b9d852132160756e247d52a Mon Sep 17 00:00:00 2001 From: Tom Shull Date: Thu, 23 May 2024 18:10:11 +0200 Subject: [PATCH] Use base text section offset for cross-layer direct calls. --- .../graal/amd64/SubstrateAMD64Backend.java | 17 +- .../core/code/BaseLayerMethodAccessor.java | 38 ---- .../graal/snippets/NonSnippetLowerings.java | 26 +-- .../imagelayer/DynamicImageLayerInfo.java | 38 +--- .../ImageSingletonLoader.java | 2 + .../ImageSingletonWriter.java | 2 + .../svm/hosted/heap/SVMImageLayerLoader.java | 10 +- .../svm/hosted/heap/SVMImageLayerWriter.java | 7 +- .../svm/hosted/image/BaseLayerSupport.java | 96 -------- .../oracle/svm/hosted/image/NativeImage.java | 18 +- .../imagelayer/HostedDynamicLayerInfo.java | 210 ++++++++++++++++++ .../imagelayer/ImageLayerSectionFeature.java | 3 +- 12 files changed, 272 insertions(+), 195 deletions(-) delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/BaseLayerMethodAccessor.java delete mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/BaseLayerSupport.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedDynamicLayerInfo.java diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java index d1be8b681ba3..bafdd9e9519f 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java @@ -45,6 +45,7 @@ import java.util.function.BiConsumer; import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Pair; import org.graalvm.nativeimage.ImageSingletons; import com.oracle.svm.core.CPUFeatureAccess; @@ -54,7 +55,6 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.amd64.AMD64CPUFeatureAccess; -import com.oracle.svm.core.code.BaseLayerMethodAccessor; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.cpufeature.Stubs; import com.oracle.svm.core.deopt.Deoptimizer; @@ -84,6 +84,7 @@ import com.oracle.svm.core.graal.nodes.ComputedIndirectCallTargetNode.FieldLoadIfZero; import com.oracle.svm.core.heap.ReferenceAccess; import com.oracle.svm.core.heap.SubstrateReferenceMapBuilder; +import com.oracle.svm.core.imagelayer.DynamicImageLayerInfo; import com.oracle.svm.core.meta.CompressedNullConstant; import com.oracle.svm.core.meta.SharedField; import com.oracle.svm.core.meta.SharedMethod; @@ -673,14 +674,14 @@ protected Value emitIndirectForeignCallAddress(ForeignCallLinkage linkage) { SharedMethod targetMethod = (SharedMethod) callTarget.getMethod(); if (SubstrateUtil.HOSTED && targetMethod.forceIndirectCall()) { /* - * Load the absolute address of the target method from the method entry stored in - * the data section. + * Load the address for the start of the text section and then add in the offset for + * this specific method. */ - CGlobalDataInfo methodDataInfo = BaseLayerMethodAccessor.singleton().getMethodData(targetMethod); - AllocatableValue methodPointerAddress = newVariable(getLIRKindTool().getWordKind()); - append(new AMD64CGlobalDataLoadAddressOp(methodDataInfo, methodPointerAddress)); - AMD64AddressValue methodTableEntryAddress = new AMD64AddressValue(getLIRKindTool().getWordKind(), methodPointerAddress, Value.ILLEGAL, Stride.S1, 0); - return getArithmetic().emitLoad(getLIRKindTool().getWordKind(), methodTableEntryAddress, null, MemoryOrderMode.PLAIN, MemoryExtendKind.DEFAULT); + Pair methodLocation = DynamicImageLayerInfo.singleton().getPriorLayerMethodLocation(targetMethod); + AllocatableValue basePointerAddress = newVariable(getLIRKindTool().getWordKind()); + append(new AMD64CGlobalDataLoadAddressOp(methodLocation.getLeft(), basePointerAddress)); + Value codeOffsetInSection = emitConstant(getLIRKindTool().getWordKind(), JavaConstant.forLong(methodLocation.getRight())); + return getArithmetic().emitAdd(basePointerAddress, codeOffsetInSection, false); } if (!shouldEmitOnlyIndirectCalls()) { return null; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/BaseLayerMethodAccessor.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/BaseLayerMethodAccessor.java deleted file mode 100644 index ae3694cd3752..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/BaseLayerMethodAccessor.java +++ /dev/null @@ -1,38 +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.core.code; - -import org.graalvm.nativeimage.ImageSingletons; - -import com.oracle.svm.core.graal.code.CGlobalDataInfo; -import com.oracle.svm.core.meta.SharedMethod; - -public interface BaseLayerMethodAccessor { - CGlobalDataInfo getMethodData(SharedMethod method); - - static BaseLayerMethodAccessor singleton() { - return ImageSingletons.lookup(BaseLayerMethodAccessor.class); - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java index e98eb8398f0b..7c357ba22c4a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java @@ -33,13 +33,13 @@ import java.util.Map; import java.util.function.Predicate; +import org.graalvm.collections.Pair; import org.graalvm.word.LocationIdentity; import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.c.BoxedRelocatedPointer; -import com.oracle.svm.core.code.BaseLayerMethodAccessor; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.graal.code.CGlobalDataInfo; import com.oracle.svm.core.graal.code.SubstrateBackend; @@ -49,6 +49,7 @@ import com.oracle.svm.core.graal.nodes.LoadOpenTypeWorldDispatchTableStartingOffset; import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; import com.oracle.svm.core.graal.nodes.ThrowBytecodeExceptionNode; +import com.oracle.svm.core.imagelayer.DynamicImageLayerInfo; import com.oracle.svm.core.meta.SharedMethod; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.snippets.ImplicitExceptions; @@ -369,7 +370,7 @@ public void lower(FixedNode node, LoweringTool tool) { SharedMethod targetMethod = method; if (!invokeKind.isDirect()) { /* - * We only have one possible implementation for a indirect call, so we can + * We only have one possible implementation for an indirect call, so we can * emit a direct call to the unique implementation. */ targetMethod = implementations[0]; @@ -378,19 +379,14 @@ public void lower(FixedNode node, LoweringTool tool) { if (SubstrateUtil.HOSTED && targetMethod.forceIndirectCall()) { /* * Lower cross layer boundary direct calls to indirect calls. First load the - * target method absolute address from the method entry stored in the data - * section. Then call that address indirectly. + * address offset of the text section start and then add in the offset for + * this specific method. */ - CGlobalDataInfo methodDataInfo = BaseLayerMethodAccessor.singleton().getMethodData(targetMethod); - AddressNode methodPointerAddress = graph.addOrUniqueWithInputs(OffsetAddressNode.create(new CGlobalDataLoadAddressNode(methodDataInfo))); - - /* - * Use the ANY location identity to prevent ReadNode.canonicalizeRead() to - * try to constant fold the method address. - */ - ReadNode entry = graph.add(new ReadNode(methodPointerAddress, LocationIdentity.any(), FrameAccess.getWordStamp(), BarrierType.NONE, MemoryOrderMode.PLAIN)); - loweredCallTarget = createIndirectCall(graph, callTarget, parameters, method, signature, callType, invokeKind, entry); - graph.addBeforeFixed(node, entry); + Pair methodLocation = DynamicImageLayerInfo.singleton().getPriorLayerMethodLocation(targetMethod); + AddressNode methodPointerAddress = graph.addOrUniqueWithInputs( + new OffsetAddressNode(new CGlobalDataLoadAddressNode(methodLocation.getLeft()), + ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), methodLocation.getRight()))); + loweredCallTarget = createIndirectCall(graph, callTarget, parameters, method, signature, callType, invokeKind, methodPointerAddress); } else if (!SubstrateBackend.shouldEmitOnlyIndirectCalls()) { loweredCallTarget = createDirectCall(graph, callTarget, parameters, signature, callType, invokeKind, targetMethod, node); } else if (!targetMethod.hasImageCodeOffset()) { @@ -494,7 +490,7 @@ protected LoweredCallTargetNode createDirectCall(StructuredGraph graph, MethodCa } protected IndirectCallTargetNode createIndirectCall(StructuredGraph graph, MethodCallTargetNode callTarget, NodeInputList parameters, SharedMethod method, JavaType[] signature, - CallingConvention.Type callType, InvokeKind invokeKind, ReadNode entry) { + CallingConvention.Type callType, InvokeKind invokeKind, ValueNode entry) { return graph.add(new IndirectCallTargetNode(entry, parameters.toArray(new ValueNode[parameters.size()]), callTarget.returnStamp(), signature, method, callType, invokeKind)); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/DynamicImageLayerInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/DynamicImageLayerInfo.java index d1aa523c3eff..113915fbf098 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/DynamicImageLayerInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/DynamicImageLayerInfo.java @@ -24,27 +24,18 @@ */ package com.oracle.svm.core.imagelayer; -import java.util.EnumSet; - +import org.graalvm.collections.Pair; import org.graalvm.nativeimage.ImageSingletons; -import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; -import com.oracle.svm.core.layeredimagesingleton.ImageSingletonLoader; -import com.oracle.svm.core.layeredimagesingleton.ImageSingletonWriter; -import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton; -import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags; +import com.oracle.svm.core.graal.code.CGlobalDataInfo; +import com.oracle.svm.core.meta.SharedMethod; -@AutomaticallyRegisteredImageSingleton(onlyWith = BuildingImageLayerPredicate.class) -public class DynamicImageLayerInfo implements LayeredImageSingleton { +public abstract class DynamicImageLayerInfo { public final int layerNumber; public final int nextLayerNumber; public final int numLayers; - public DynamicImageLayerInfo() { - this(0); - } - - private DynamicImageLayerInfo(int layerNumber) { + protected DynamicImageLayerInfo(int layerNumber) { this.layerNumber = layerNumber; this.nextLayerNumber = layerNumber + 1; this.numLayers = nextLayerNumber; @@ -54,19 +45,8 @@ public static DynamicImageLayerInfo singleton() { return ImageSingletons.lookup(DynamicImageLayerInfo.class); } - @Override - public EnumSet getImageBuilderFlags() { - return LayeredImageSingletonBuilderFlags.BUILDTIME_ACCESS_ONLY; - } - - @Override - public PersistFlags preparePersist(ImageSingletonWriter writer) { - writer.writeInt("nextLayerNumber", nextLayerNumber); - return PersistFlags.CREATE; - } - - @SuppressWarnings("unused") - public static Object createFromLoader(ImageSingletonLoader loader) { - return new DynamicImageLayerInfo(loader.readInt("nextLayerNumber")); - } + /** + * Returns a (Base, Offset) pair which can be used to call a method defined in a prior layer. + */ + public abstract Pair getPriorLayerMethodLocation(SharedMethod method); } 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 aeeafd0db123..7558e4935130 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 @@ -30,4 +30,6 @@ public interface ImageSingletonLoader { int readInt(String keyName); List readIntList(String keyName); + + String readString(String keyName); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/ImageSingletonWriter.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/ImageSingletonWriter.java index 8b19b6042798..2ee302e399a9 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/ImageSingletonWriter.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/ImageSingletonWriter.java @@ -30,4 +30,6 @@ public interface ImageSingletonWriter { void writeInt(String keyName, int value); void writeIntList(String keyName, List value); + + void writeString(String keyName, String value); } 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 index c2fa4d39ac2f..81d9c0a2df8d 100644 --- 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 @@ -294,7 +294,15 @@ public int readInt(String keyName) { public List readIntList(String keyName) { List value = cast(keyStore.get(keyName)); String type = cast(value.get(0)); - assert type.equals("I[]") : type; + assert type.equals("I(") : type; + return cast(value.get(1)); + } + + @Override + public String readString(String keyName) { + List value = cast(keyStore.get(keyName)); + String type = cast(value.get(0)); + assert type.equals("S") : type; return cast(value.get(1)); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java index 59f228a2f712..073e9623fb7d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java @@ -269,6 +269,11 @@ public void writeInt(String keyName, int value) { @Override public void writeIntList(String keyName, List value) { - keyValueStore.put(keyName, List.of("I[]", value)); + keyValueStore.put(keyName, List.of("I(", value)); + } + + @Override + public void writeString(String keyName, String value) { + keyValueStore.put(keyName, List.of("S", value)); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/BaseLayerSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/BaseLayerSupport.java deleted file mode 100644 index 8ff23b0e0b96..000000000000 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/BaseLayerSupport.java +++ /dev/null @@ -1,96 +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.image; - -import java.util.concurrent.ConcurrentHashMap; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.word.PointerBase; - -import com.oracle.objectfile.ObjectFile.ProgbitsSectionImpl; -import com.oracle.objectfile.ObjectFile.RelocationKind; -import com.oracle.svm.core.c.CGlobalData; -import com.oracle.svm.core.c.CGlobalDataFactory; -import com.oracle.svm.core.code.BaseLayerMethodAccessor; -import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.core.feature.InternalFeature; -import com.oracle.svm.core.graal.code.CGlobalDataInfo; -import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; -import com.oracle.svm.core.meta.SharedMethod; -import com.oracle.svm.hosted.c.CGlobalDataFeature; -import com.oracle.svm.hosted.image.BaseLayerSupport.BaseLayerMethodAccessorImpl; -import com.oracle.svm.hosted.meta.HostedMethod; - -@AutomaticallyRegisteredFeature -class LoadBaseLayerFeature implements InternalFeature { - - @Override - public boolean isInConfiguration(IsInConfigurationAccess access) { - return ImageLayerBuildingSupport.buildingExtensionLayer(); - } - - @Override - public void duringSetup(DuringSetupAccess access) { - ImageSingletons.add(BaseLayerMethodAccessor.class, new BaseLayerMethodAccessorImpl()); - } -} - -public class BaseLayerSupport { - - public static void markDynamicRelocationSites(ProgbitsSectionImpl rwDataSection) { - if (ImageSingletons.contains(BaseLayerMethodAccessor.class)) { - ((BaseLayerMethodAccessorImpl) ImageSingletons.lookup(BaseLayerMethodAccessor.class)).markDynamicRelocations(rwDataSection); - } - } - - public static class BaseLayerMethodAccessorImpl implements BaseLayerMethodAccessor { - - final ConcurrentHashMap methodMap = new ConcurrentHashMap<>(); - - @Override - public CGlobalDataInfo getMethodData(SharedMethod method) { - return methodMap.computeIfAbsent((HostedMethod) method, m -> { - /* - * Create word to store the absolute method address at run time. We will register a - * relocation for the offset of this CGlobalData object which the dynamic linker - * will resolve at run time, when the base layer is loaded. - */ - String symbolName = "MethodEntry_" + NativeImage.localSymbolNameForMethod(method); - CGlobalData cGlobalData = CGlobalDataFactory.createWord(symbolName); - return CGlobalDataFeature.singleton().registerAsAccessedOrGet(cGlobalData); - }); - } - - void markDynamicRelocations(ProgbitsSectionImpl rwDataSection) { - methodMap.forEach((method, info) -> { - /* For each of the accessed base layer methods create a relocation record. */ - int pointerSize = ConfigurationValues.getTarget().wordSize; - String symbolName = NativeImage.localSymbolNameForMethod(method); - rwDataSection.markRelocationSite(info.getOffset(), RelocationKind.getDirect(pointerSize), symbolName, 0L); - }); - } - } -} 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 c05c0b95ca1c..deb2a3dcbe81 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,6 +91,7 @@ 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.imagelayer.DynamicImageLayerInfo; import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.core.option.SubstrateOptionsParser; @@ -407,6 +408,14 @@ private ObjectFile.Symbol defineRelocationForSymbol(String name, long position) return symbol; } + public static String getTextSectionStartSymbol() { + if (ImageLayerBuildingSupport.buildingImageLayer()) { + return String.format("__svm_layer_code_section_%s", DynamicImageLayerInfo.singleton().layerNumber); + } else { + return "__svm_code_section"; + } + } + /** * Create the image sections for code, constants, and the heap. */ @@ -452,6 +461,10 @@ public void build(String imageName, DebugContext debug) { // Define symbols for the sections. objectFile.createDefinedSymbol(textSection.getName(), textSection, 0, 0, false, false); + if (ImageLayerBuildingSupport.buildingSharedLayer() || SubstrateOptions.DeleteLocalSymbols.getValue()) { + /* add a dummy function symbol at the start of the code section */ + objectFile.createDefinedSymbol(getTextSectionStartSymbol(), textSection, 0, 0, true, true); + } objectFile.createDefinedSymbol("__svm_text_end", textSection, textSectionSize, 0, false, SubstrateOptions.InternalSymbolsAreGlobal.getValue()); objectFile.createDefinedSymbol(roDataSection.getName(), roDataSection, 0, 0, false, false); objectFile.createDefinedSymbol(rwDataSection.getName(), rwDataSection, 0, 0, false, false); @@ -468,7 +481,6 @@ public void build(String imageName, DebugContext debug) { isGlobalSymbol || SubstrateOptions.InternalSymbolsAreGlobal.getValue()), (offset, symbolName, isGlobalSymbol) -> defineRelocationForSymbol(symbolName, offset)); defineDataSymbol(CGlobalDataInfo.CGLOBALDATA_BASE_SYMBOL_NAME, rwDataSection, RWDATA_CGLOBALS_PARTITION_OFFSET); - BaseLayerSupport.markDynamicRelocationSites((ProgbitsSectionImpl) rwDataSection); // - Write the heap to its own section. // Dynamic linkers/loaders generally don't ensure any alignment to more than page @@ -921,10 +933,6 @@ protected void writeTextSection(DebugContext debug, final Section textSection, f * 3. the linkage names given by @CEntryPoint */ - if (SubstrateOptions.DeleteLocalSymbols.getValue()) { - /* add a dummy function symbol at the start of the code section */ - objectFile.createDefinedSymbol("__svm_code_section", textSection, 0, 0, true, true); - } final Map methodsBySignature = new HashMap<>(); // 1. fq with return type diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedDynamicLayerInfo.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedDynamicLayerInfo.java new file mode 100644 index 000000000000..db5c32cd7ed7 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedDynamicLayerInfo.java @@ -0,0 +1,210 @@ +/* + * 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 java.util.ArrayList; +import java.util.BitSet; +import java.util.Collection; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.graalvm.collections.Pair; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.word.PointerBase; + +import com.oracle.svm.core.c.CGlobalData; +import com.oracle.svm.core.c.CGlobalDataFactory; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.graal.code.CGlobalDataInfo; +import com.oracle.svm.core.imagelayer.DynamicImageLayerInfo; +import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; +import com.oracle.svm.core.layeredimagesingleton.ImageSingletonLoader; +import com.oracle.svm.core.layeredimagesingleton.ImageSingletonWriter; +import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton; +import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags; +import com.oracle.svm.core.meta.SharedMethod; +import com.oracle.svm.hosted.FeatureImpl; +import com.oracle.svm.hosted.c.CGlobalDataFeature; +import com.oracle.svm.hosted.image.NativeImage; +import com.oracle.svm.hosted.meta.HostedMethod; + +import jdk.graal.compiler.debug.Assertions; + +public class HostedDynamicLayerInfo extends DynamicImageLayerInfo implements LayeredImageSingleton { + private final Map methodIdToOffsetMap; + private final CGlobalData cGlobalData; + + HostedDynamicLayerInfo() { + this(0, null, new HashMap<>()); + } + + public static HostedDynamicLayerInfo singleton() { + return (HostedDynamicLayerInfo) ImageSingletons.lookup(DynamicImageLayerInfo.class); + } + + private HostedDynamicLayerInfo(int layerNumber, String codeSectionStartSymbol, Map methodIdToOffsetMap) { + super(layerNumber); + this.methodIdToOffsetMap = methodIdToOffsetMap; + cGlobalData = codeSectionStartSymbol == null ? null : CGlobalDataFactory.forSymbol(codeSectionStartSymbol); + } + + @Override + public Pair getPriorLayerMethodLocation(SharedMethod sMethod) { + assert ImageLayerBuildingSupport.buildingExtensionLayer() : "This should only be called within extension images. Within the initial layer the direct calls can be performed"; + HostedMethod method = (HostedMethod) sMethod; + assert method.wrapped.isInBaseLayer() && methodIdToOffsetMap.containsKey(method.getWrapped().getId()) : method; + + var basePointer = CGlobalDataFeature.singleton().registerAsAccessedOrGet(cGlobalData); + var offset = methodIdToOffsetMap.get(method.getWrapped().getId()); + return Pair.create(basePointer, offset); + } + + void registerOffset(HostedMethod method) { + int offset = method.getCodeAddressOffset(); + int methodID = method.getWrapped().getId(); + + assert !methodIdToOffsetMap.containsKey(methodID) : Assertions.errorMessage("Duplicate entry", methodID, offset); + methodIdToOffsetMap.put(methodID, offset); + } + + @Override + public EnumSet getImageBuilderFlags() { + return LayeredImageSingletonBuilderFlags.BUILDTIME_ACCESS_ONLY; + } + + /** + * Verifies each method has been mapped to a unique offset. + */ + boolean verifyUniqueOffsets(Collection methods) { + BitSet seenOffsets = new BitSet(); + for (var entry : methodIdToOffsetMap.entrySet()) { + if (seenOffsets.get(entry.getValue())) { + var method = methods.stream().filter(m -> ((HostedMethod) m).getWrapped().getId() == entry.getKey()).findAny(); + assert false : Assertions.errorMessage("Value has already been found", method, entry.getKey(), entry.getValue()); + } + + seenOffsets.set(entry.getValue()); + } + + return true; + } + + @Override + public PersistFlags preparePersist(ImageSingletonWriter writer) { + /* + * When there are multiple shared layers we will need to store the starting code offset of + * each layer. + */ + assert ImageLayerBuildingSupport.buildingInitialLayer() : "This code must be adjusted to support multiple shared layers"; + + /* + * First write out next layer number. + */ + writer.writeInt("nextLayerNumber", nextLayerNumber); + + /* + * Next write the start of the code section + */ + writer.writeString("codeSectionStartSymbol", NativeImage.getTextSectionStartSymbol()); + + /* + * Write out all method offsets. + */ + List offsets = new ArrayList<>(methodIdToOffsetMap.size()); + List methodIDs = new ArrayList<>(methodIdToOffsetMap.size()); + methodIdToOffsetMap.forEach((key, value) -> { + methodIDs.add(key); + offsets.add(value); + }); + writer.writeIntList("methodIDs", methodIDs); + writer.writeIntList("offsets", offsets); + + return PersistFlags.CREATE; + } + + @SuppressWarnings("unused") + public static Object createFromLoader(ImageSingletonLoader loader) { + assert loader.readIntList("offsets").size() == loader.readIntList("methodIDs").size() : Assertions.errorMessage("Offsets and methodIDs are incompatible", loader.readIntList("offsets"), + loader.readIntList("methodIDs")); + + int layerNumber = loader.readInt("nextLayerNumber"); + + String codeSectionStartSymbol = loader.readString("codeSectionStartSymbol"); + + /* + * Load the offsets of all methods in the prior layers. + */ + var offsets = loader.readIntList("offsets").iterator(); + var methodIDs = loader.readIntList("methodIDs").iterator(); + Map initialMethodIdToOffsetMap = new HashMap<>(); + + while (offsets.hasNext()) { + int methodId = methodIDs.next(); + int offset = offsets.next(); + initialMethodIdToOffsetMap.put(methodId, offset); + } + + return new HostedDynamicLayerInfo(layerNumber, codeSectionStartSymbol, initialMethodIdToOffsetMap); + } +} + +@AutomaticallyRegisteredFeature +class HostedDynamicLayerInfoFeature implements InternalFeature { + + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return ImageLayerBuildingSupport.buildingImageLayer(); + } + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + if (ImageLayerBuildingSupport.buildingInitialLayer()) { + ImageSingletons.add(DynamicImageLayerInfo.class, new HostedDynamicLayerInfo()); + } + } + + @Override + public void afterCompilation(AfterCompilationAccess access) { + /* + * Store all compiled method offsets into the singleton. + */ + + if (ImageLayerBuildingSupport.buildingApplicationLayer()) { + // This is the last layer; no need to store anything + return; + } + + var config = (FeatureImpl.AfterCompilationAccessImpl) access; + + assert HostedDynamicLayerInfo.singleton().verifyUniqueOffsets(config.getMethods()); + + for (var entry : config.getCodeCache().getOrderedCompilations()) { + HostedDynamicLayerInfo.singleton().registerOffset(entry.getLeft()); + } + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/ImageLayerSectionFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/ImageLayerSectionFeature.java index a7417b33c5e1..6bb1002c9812 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/ImageLayerSectionFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/ImageLayerSectionFeature.java @@ -48,7 +48,6 @@ import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.imagelayer.DynamicImageLayerInfo; -import com.oracle.svm.core.imagelayer.DynamicImageLayerInfoFeature; import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; import com.oracle.svm.core.imagelayer.ImageLayerSection; import com.oracle.svm.core.layeredimagesingleton.FeatureSingleton; @@ -104,7 +103,7 @@ public boolean isInConfiguration(IsInConfigurationAccess access) { @Override public List> getRequiredFeatures() { - return List.of(DynamicImageLayerInfoFeature.class); + return List.of(HostedDynamicLayerInfoFeature.class); } @Override