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 768802f799df..506ed4418e54 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 @@ -261,6 +261,10 @@ public ImageLayerLoader(ImageLayerSnapshotUtil imageLayerSnapshotUtil, List getLoadPaths() { + return loadPaths; + } + public void setUniverse(AnalysisUniverse newUniverse) { this.universe = newUniverse; } 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 6985427a521d..38e891964879 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 @@ -43,6 +43,7 @@ import java.util.EnumSet; import java.util.function.BiConsumer; +import com.oracle.svm.core.graal.code.CGlobalDataInfo; import org.graalvm.collections.EconomicMap; import org.graalvm.nativeimage.ImageSingletons; @@ -53,6 +54,7 @@ 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; @@ -79,7 +81,6 @@ import com.oracle.svm.core.graal.nodes.ComputedIndirectCallTargetNode.Computation; import com.oracle.svm.core.graal.nodes.ComputedIndirectCallTargetNode.FieldLoad; import com.oracle.svm.core.graal.nodes.ComputedIndirectCallTargetNode.FieldLoadIfZero; -import com.oracle.svm.core.graal.snippets.NonSnippetLowerings; import com.oracle.svm.core.heap.ReferenceAccess; import com.oracle.svm.core.heap.SubstrateReferenceMapBuilder; import com.oracle.svm.core.meta.CompressedNullConstant; @@ -200,7 +201,6 @@ import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.Value; @@ -669,16 +669,15 @@ protected Value emitIndirectForeignCallAddress(ForeignCallLinkage linkage) { SubstrateForeignCallLinkage callTarget = (SubstrateForeignCallLinkage) linkage; SharedMethod targetMethod = (SharedMethod) callTarget.getMethod(); if (SubstrateUtil.HOSTED && targetMethod.forceIndirectCall()) { - // Emit a load for the BoxedRelocatedPointer.pointer field holding the - // MethodPointer to the target method - ResolvedJavaField boxedPointerField = getMetaAccess().lookupJavaField(NonSnippetLowerings.boxedRelocatedPointerField); - int displacement = boxedPointerField.getOffset(); - JavaConstant boxedPointerBase = targetMethod.getMethodPointer(); - RegisterValue heapBaseRegister = ReservedRegisters.singleton().getHeapBaseRegister().asValue(); - AMD64AddressValue boxedRelocatedPointerBaseAddress = new AMD64AddressValue(getLIRKindTool().getWordKind(), heapBaseRegister, Value.ILLEGAL, - Stride.S1, displacement + SubstrateAMD64Backend.addressDisplacement(boxedPointerBase, getConstantReflection()), - SubstrateAMD64Backend.addressDisplacementAnnotation(boxedPointerBase)); - return getArithmetic().emitLoad(getLIRKindTool().getWordKind(), boxedRelocatedPointerBaseAddress, null, MemoryOrderMode.PLAIN, MemoryExtendKind.DEFAULT); + /* + * Load the absolute address of the target method from the method entry stored in + * the data section. + */ + 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); } if (!shouldEmitOnlyIndirectCalls()) { return null; diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java index 1611f7ce4ba4..226d76d34fac 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java @@ -29,6 +29,7 @@ import static com.oracle.svm.core.graal.llvm.LLVMToolchainUtils.llvmLink; import static com.oracle.svm.core.graal.llvm.LLVMToolchainUtils.llvmOptimize; import static com.oracle.svm.core.graal.llvm.LLVMToolchainUtils.nativeLink; +import static com.oracle.svm.core.util.VMError.intentionallyUnimplemented; import static com.oracle.svm.core.util.VMError.shouldNotReachHereUnexpectedInput; import static com.oracle.svm.hosted.image.NativeImage.RWDATA_CGLOBALS_PARTITION_OFFSET; @@ -46,11 +47,6 @@ import java.util.stream.IntStream; import org.graalvm.collections.Pair; -import jdk.graal.compiler.code.CompilationResult; -import jdk.graal.compiler.core.common.NumUtil; -import jdk.graal.compiler.debug.DebugContext; -import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.debug.Indent; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -78,6 +74,11 @@ import com.oracle.svm.hosted.image.RelocatableBuffer; import com.oracle.svm.hosted.meta.HostedMethod; +import jdk.graal.compiler.code.CompilationResult; +import jdk.graal.compiler.core.common.NumUtil; +import jdk.graal.compiler.debug.DebugContext; +import jdk.graal.compiler.debug.GraalError; +import jdk.graal.compiler.debug.Indent; import jdk.vm.ci.code.site.Call; import jdk.vm.ci.code.site.DataPatch; import jdk.vm.ci.code.site.DataSectionReference; @@ -317,6 +318,11 @@ public void patchMethods(DebugContext debug, RelocatableBuffer relocs, ObjectFil @Override public NativeTextSectionImpl getTextSectionImpl(RelocatableBuffer buffer, ObjectFile objectFile, NativeImageCodeCache codeCache) { return new NativeTextSectionImpl(buffer, objectFile, codeCache) { + @Override + protected void defineBaseLayerMethodSymbol(String name, Element section, HostedMethod method) { + throw intentionallyUnimplemented(); // ExcludeFromJacocoGeneratedReport + } + @Override protected void defineMethodSymbol(String name, boolean global, Element section, HostedMethod method, CompilationResult result) { ObjectFile.Symbol symbol = objectFile.createUndefinedSymbol(name, 0, true); 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 b7ea884facfc..402265135de4 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 @@ -24,6 +24,7 @@ */ package com.oracle.svm.core; +import static com.oracle.svm.core.Containers.Options.UseContainerSupport; import static com.oracle.svm.core.option.RuntimeOptionKey.RuntimeOptionKeyFlag.Immutable; import static com.oracle.svm.core.option.RuntimeOptionKey.RuntimeOptionKeyFlag.RelevantForCompilationIsolates; import static jdk.graal.compiler.core.common.SpectrePHTMitigations.None; @@ -113,6 +114,12 @@ protected void onValueUpdate(EconomicMap, Object> values, Boolean o PersistImageLayerSingletons.update(values, newValue); DeleteLocalSymbols.update(values, !newValue); StripDebugInfo.update(values, !newValue); + InternalSymbolsAreGlobal.update(values, newValue); + AOTTrivialInline.update(values, !newValue); + if (imageLayerEnabledHandler != null) { + imageLayerEnabledHandler.onOptionEnabled(values); + } + UseContainerSupport.update(values, !newValue); } }; @@ -707,6 +714,10 @@ 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.")// public static final HostedOptionKey DeleteLocalSymbols = new HostedOptionKey<>(true); @Option(help = "Compatibility option to make symbols used for the image heap global. " + @@ -1133,6 +1144,10 @@ 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); if (imageLayerEnabledHandler != null) { imageLayerEnabledHandler.onOptionEnabled(values); } 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 new file mode 100644 index 000000000000..ae3694cd3752 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/BaseLayerMethodAccessor.java @@ -0,0 +1,38 @@ +/* + * 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 18e44b4f7a3c..d6c663a3cdd6 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 @@ -39,10 +39,13 @@ 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; import com.oracle.svm.core.graal.meta.KnownOffsets; import com.oracle.svm.core.graal.meta.RuntimeConfiguration; +import com.oracle.svm.core.graal.nodes.CGlobalDataLoadAddressNode; import com.oracle.svm.core.graal.nodes.LoadOpenTypeWorldDispatchTableStartingOffset; import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; import com.oracle.svm.core.graal.nodes.ThrowBytecodeExceptionNode; @@ -109,7 +112,6 @@ import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; public abstract class NonSnippetLowerings { @@ -369,18 +371,15 @@ public void lower(FixedNode node, LoweringTool tool) { targetMethod = implementations[0]; } - if (targetMethod.forceIndirectCall()) { + if (SubstrateUtil.HOSTED && targetMethod.forceIndirectCall()) { /* - * Lower cross layer boundary direct calls to indirect calls. First emit a - * load for the BoxedRelocatedPointer.pointer field holding the - * MethodPointer to the target method, then emit an indirect call to that - * pointer. + * 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. */ - ResolvedJavaField boxedPointerField = tool.getMetaAccess().lookupJavaField(NonSnippetLowerings.boxedRelocatedPointerField); - ConstantNode boxedPointerFieldOffset = ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), boxedPointerField.getOffset(), graph); - ConstantNode boxedPointerBase = ConstantNode.forConstant(targetMethod.getMethodPointer(), tool.getMetaAccess(), graph); + CGlobalDataInfo methodDataInfo = BaseLayerMethodAccessor.singleton().getMethodData(targetMethod); + AddressNode methodPointerAddress = graph.addOrUniqueWithInputs(OffsetAddressNode.create(new CGlobalDataLoadAddressNode(methodDataInfo))); - AddressNode methodPointerAddress = graph.unique(new OffsetAddressNode(boxedPointerBase, boxedPointerFieldOffset)); /* * Use the ANY location identity to prevent ReadNode.canonicalizeRead() to * try to constant fold the method address. diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/SharedMethod.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/SharedMethod.java index d5b6a5cb30a9..fae25501180d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/SharedMethod.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/SharedMethod.java @@ -30,7 +30,6 @@ import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; import com.oracle.svm.core.graal.code.SubstrateCallingConventionType; -import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaMethod; /** @@ -84,7 +83,4 @@ public interface SharedMethod extends ResolvedJavaMethod { /** Always call this method indirectly, even if it is normally called directly. */ boolean forceIndirectCall(); - - /** Return a boxed pointer to this method. */ - JavaConstant getMethodPointer(); } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateMethod.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateMethod.java index ac65d02f38ff..301a25ede2bf 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateMethod.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateMethod.java @@ -60,7 +60,6 @@ import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.DefaultProfilingInfo; import jdk.vm.ci.meta.ExceptionHandler; -import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.LineNumberTable; import jdk.vm.ci.meta.LocalVariableTable; import jdk.vm.ci.meta.ProfilingInfo; @@ -230,11 +229,6 @@ public boolean forceIndirectCall() { return false; } - @Override - public JavaConstant getMethodPointer() { - throw VMError.intentionallyUnimplemented(); // ExcludeFromJacocoGeneratedReport - } - @Override public int getEncodedGraphStartOffset() { return encodedGraphStartOffset; 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 681180fd5142..953b8b7bf53f 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 @@ -1299,7 +1299,25 @@ protected NativeLibraries setupNativeLibraries(HostedProviders providers, CEnumC if (CAnnotationProcessorCache.Options.ExitAfterCAPCache.getValue()) { throw new InterruptImageBuilding("Exiting image generation because of " + SubstrateOptionsParser.commandArgument(CAnnotationProcessorCache.Options.ExitAfterCAPCache, "+")); } - + if (SVMImageLayerSupport.singleton().hasLoader()) { + for (Path layerPath : SVMImageLayerSupport.singleton().getLoader().getLoadPaths()) { + Path snapshotFileName = layerPath.getFileName(); + if (snapshotFileName != null) { + String layerName = snapshotFileName.toString().split(ImageLayerSnapshotUtil.FILE_NAME_PREFIX)[1].split(ImageLayerSnapshotUtil.FILE_EXTENSION)[0].trim(); + /* + * This currently assumes lib{layer}.so is in the same dir as the layer + * snapshot. GR-53663 will create a proper bundle that contains both files. + */ + Path layerPathDir = layerPath.getParent(); + if (layerPathDir != null && layerName.startsWith("lib") && Files.exists(layerPathDir.resolve(layerName + ".so"))) { + nativeLibs.getLibraryPaths().add(layerPathDir.toString()); + nativeLibs.addDynamicNonJniLibrary(layerName.split("lib")[1]); + } else { + throw VMError.shouldNotReachHere("Missing " + layerName + ".so. It must be placed in the same dir as the layer snapshot."); + } + } + } + } return nativeLibs; } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMImageLayerSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMImageLayerSupport.java index a060ac7d74e1..88e10784cf77 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMImageLayerSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMImageLayerSupport.java @@ -52,6 +52,10 @@ public static SVMImageLayerSupport singleton() { return ImageSingletons.lookup(SVMImageLayerSupport.class); } + public boolean hasLoader() { + return loader != null; + } + public SVMImageLayerLoader getLoader() { return loader; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/AbstractImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/AbstractImage.java index b543ce3b7fcf..0ab223ad6b1f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/AbstractImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/AbstractImage.java @@ -54,7 +54,7 @@ public enum NativeImageKind { IMAGE_LAYER(false, true) { @Override public String getFilenameSuffix() { - return ".gso"; // Graal shared object + return ".so"; } }, SHARED_LIBRARY(false) { 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 new file mode 100644 index 000000000000..e5d65c55f803 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/BaseLayerSupport.java @@ -0,0 +1,96 @@ +/* + * 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.meta.SharedMethod; +import com.oracle.svm.hosted.SVMImageLayerSupport; +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 SVMImageLayerSupport.singleton().hasLoader(); + } + + @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/CCLinkerInvocation.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java index d37ba21e4f68..9e35d03b795e 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 @@ -24,6 +24,8 @@ */ package com.oracle.svm.hosted.image; +import static com.oracle.svm.core.SubstrateOptions.SpawnIsolates; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -59,8 +61,6 @@ import jdk.graal.compiler.options.Option; import jdk.graal.compiler.options.OptionStability; -import static com.oracle.svm.core.SubstrateOptions.SpawnIsolates; - public abstract class CCLinkerInvocation implements LinkerInvocation { protected CCLinkerInvocation(AbstractImage.NativeImageKind imageKind, NativeLibraries nativeLibs, List imageSymbols) { @@ -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()) { + if (!(SubstrateOptions.useLLVMBackend() || SubstrateOptions.PreserveUndefinedSymbols.getValue())) { stream = stream.filter(ObjectFile.Symbol::isDefined); } return stream.map(this::getSymbolName).collect(Collectors.toList()); @@ -270,6 +270,10 @@ private static class BinutilsCCLinkerInvocation extends CCLinkerInvocation { /* Perform garbage collection of unused input sections. */ additionalPreOptions.add("-Wl,--gc-sections"); } + if (SubstrateOptions.IgnoreUndefinedReferences.getValue()) { + /* Ignore references to undefined symbols from the object files. */ + additionalPreOptions.add("-Wl,--unresolved-symbols=ignore-in-object-files"); + } /* Use --version-script to control the visibility of image symbols. */ try { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java index 4c24089f007f..abd090ad6569 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java @@ -485,14 +485,16 @@ private NativeTextSectionImpl(RelocatableBuffer buffer, ObjectFile objectFile, N super(buffer, objectFile, codeCache); } + @Override + protected void defineBaseLayerMethodSymbol(String name, ObjectFile.Element section, HostedMethod method) { + VMError.guarantee(method.wrapped.isInBaseLayer(), "Expecting a base layer method, found %s", method); + objectFile.createUndefinedSymbol(name, 0, true); + } + @Override protected void defineMethodSymbol(String name, boolean global, ObjectFile.Element section, HostedMethod method, CompilationResult result) { - if (method.wrapped.isInBaseLayer()) { - objectFile.createUndefinedSymbol(name, 0, true); - } else { - final int size = result == null ? 0 : result.getTargetCodeSize(); - objectFile.createDefinedSymbol(name, section, method.getCodeAddressOffset(), size, true, global); - } + final int size = result == null ? 0 : result.getTargetCodeSize(); + objectFile.createDefinedSymbol(name, section, method.getCodeAddressOffset(), size, true, global); } } 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 ee15de0772aa..595be791477d 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 @@ -460,6 +460,7 @@ 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 @@ -871,6 +872,8 @@ public byte[] getOrDecideContent(Map alreadyDecided, return getContent(); } + protected abstract void defineBaseLayerMethodSymbol(String name, Element section, HostedMethod method); + protected abstract void defineMethodSymbol(String name, boolean global, Element section, HostedMethod method, CompilationResult result); @SuppressWarnings("try") @@ -920,8 +923,7 @@ protected void writeTextSection(DebugContext debug, final Section textSection, f // define base layer methods symbols for (HostedMethod current : codeCache.getBaseLayerMethods()) { final String symName = localSymbolNameForMethod(current); - final String signatureString = current.getUniqueShortName(); - defineMethodSymbol(textSection, current, methodsBySignature, signatureString, symName, null); + defineBaseLayerMethodSymbol(symName, textSection, current); } } @@ -929,7 +931,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, pair.getRight()); + defineMethodSymbol(textSection, current, methodsBySignature, signatureString, symName, SubstrateOptions.InternalSymbolsAreGlobal.getValue(), pair.getRight()); } // 2. fq without return type -- only for entry points! for (Map.Entry ent : methodsBySignature.entrySet()) { @@ -973,7 +975,7 @@ protected void writeTextSection(DebugContext debug, final Section textSection, f } private void defineMethodSymbol(Section textSection, HostedMethod current, Map methodsBySignature, - String signatureString, String symName, CompilationResult compilationResult) { + String signatureString, String symName, boolean global, CompilationResult compilationResult) { final HostedMethod existing = methodsBySignature.get(signatureString); if (existing != null) { /* @@ -990,7 +992,7 @@ private void defineMethodSymbol(Section textSection, HostedMethod current, Map signature; @@ -212,14 +208,6 @@ private HostedMethod(AnalysisMethod wrapped, HostedType holder, ResolvedSignatur this.uniqueShortName = uniqueShortName; this.multiMethodKey = multiMethodKey; this.multiMethodMap = multiMethodMap; - /* - * Cache a method pointer for base layer methods. Cross layer direct calls are currently - * lowered to indirect calls. - */ - if (wrapped.isInBaseLayer()) { - BoxedRelocatedPointer pointer = new BoxedRelocatedPointer(new MethodPointer(wrapped)); - this.methodPointer = wrapped.getUniverse().getSnippetReflection().forObject(pointer); - } } @Override @@ -283,12 +271,6 @@ public boolean forceIndirectCall() { return wrapped.isInBaseLayer(); } - @Override - public JavaConstant getMethodPointer() { - assert forceIndirectCall(); - return methodPointer; - } - @Override public boolean hasImageCodeOffset() { throw intentionallyUnimplemented(); // ExcludeFromJacocoGeneratedReport