diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64CGlobalDataLoadAddressOp.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64CGlobalDataLoadAddressOp.java index 334da99646c7..d3fd06b7c2d2 100755 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64CGlobalDataLoadAddressOp.java +++ b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/AArch64CGlobalDataLoadAddressOp.java @@ -24,23 +24,23 @@ */ package com.oracle.svm.core.graal.aarch64; -import static jdk.vm.ci.code.ValueUtil.asRegister; import static jdk.graal.compiler.lir.LIRInstruction.OperandFlag.REG; +import static jdk.vm.ci.code.ValueUtil.asRegister; -import jdk.graal.compiler.asm.aarch64.AArch64Address; -import jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler; -import jdk.graal.compiler.lir.LIRInstructionClass; -import jdk.graal.compiler.lir.aarch64.AArch64LIRInstruction; -import jdk.graal.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.word.Pointer; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; -import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.graal.code.CGlobalDataInfo; import com.oracle.svm.core.graal.code.CGlobalDataReference; +import jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler; +import jdk.graal.compiler.lir.LIRInstructionClass; +import jdk.graal.compiler.lir.aarch64.AArch64LIRInstruction; +import jdk.graal.compiler.lir.asm.CompilationResultBuilder; import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.AllocatableValue; +@Platforms(Platform.HOSTED_ONLY.class) public final class AArch64CGlobalDataLoadAddressOp extends AArch64LIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64CGlobalDataLoadAddressOp.class); @@ -58,25 +58,15 @@ public final class AArch64CGlobalDataLoadAddressOp extends AArch64LIRInstruction public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { int addressBitSize = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; assert addressBitSize == 64; - if (SubstrateUtil.HOSTED) { - // AOT compilation: record patch that is fixed up later - crb.compilationResult.recordDataPatch(masm.position(), new CGlobalDataReference(dataInfo)); - Register resultRegister = asRegister(result); - if (dataInfo.isSymbolReference()) { - // Pure symbol reference: the data contains the symbol's address, load it - masm.adrpLdr(addressBitSize, resultRegister, resultRegister); - } else { - // Data: load its address - masm.adrpAdd(resultRegister); - } + + crb.compilationResult.recordDataPatch(masm.position(), new CGlobalDataReference(dataInfo)); + Register resultRegister = asRegister(result); + if (dataInfo.isSymbolReference()) { + // Pure symbol reference: the data contains the symbol's address, load it + masm.adrpLdr(addressBitSize, resultRegister, resultRegister); } else { - // Runtime compilation: compute the actual address - Pointer globalsBase = CGlobalDataInfo.CGLOBALDATA_RUNTIME_BASE_ADDRESS.get(); - Pointer address = globalsBase.add(dataInfo.getOffset()); - masm.mov(asRegister(result), address.rawValue()); - if (dataInfo.isSymbolReference()) { // load data, which contains symbol's address - masm.ldr(addressBitSize, asRegister(result), AArch64Address.createBaseRegisterOnlyAddress(addressBitSize, asRegister(result))); - } + // Data: load its address + masm.adrpAdd(resultRegister); } } } diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64CGlobalDataLoadAddressOp.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64CGlobalDataLoadAddressOp.java index e7860f9cb42b..1feff20ab414 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64CGlobalDataLoadAddressOp.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/AMD64CGlobalDataLoadAddressOp.java @@ -27,9 +27,9 @@ import static jdk.graal.compiler.lir.LIRInstruction.OperandFlag.REG; import static jdk.vm.ci.code.ValueUtil.asRegister; -import org.graalvm.word.Pointer; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; -import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.graal.code.CGlobalDataInfo; import com.oracle.svm.core.graal.code.CGlobalDataReference; @@ -41,6 +41,7 @@ import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.AllocatableValue; +@Platforms(Platform.HOSTED_ONLY.class) public final class AMD64CGlobalDataLoadAddressOp extends AMD64LIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64CGlobalDataLoadAddressOp.class); @@ -64,27 +65,16 @@ public final class AMD64CGlobalDataLoadAddressOp extends AMD64LIRInstruction { @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { Register resultReg = asRegister(result); - if (SubstrateUtil.HOSTED) { - // AOT compilation: record patch that is fixed up later - int before = masm.position(); - AMD64Address address = masm.getPlaceholder(before); - if (dataInfo.isSymbolReference()) { - // Pure symbol reference: the data contains the symbol's address, load it - masm.movq(resultReg, address); - } else { - // Data: load its address - masm.leaq(resultReg, address); - } - crb.compilationResult.recordDataPatch(before, new CGlobalDataReference(dataInfo)); + int before = masm.position(); + AMD64Address address = masm.getPlaceholder(before); + if (dataInfo.isSymbolReference()) { + // Pure symbol reference: the data contains the symbol's address, load it + masm.movq(resultReg, address); } else { - // Runtime compilation: compute the actual address - Pointer globalsBase = CGlobalDataInfo.CGLOBALDATA_RUNTIME_BASE_ADDRESS.get(); - Pointer address = globalsBase.add(dataInfo.getOffset()); - masm.movq(resultReg, address.rawValue()); - if (dataInfo.isSymbolReference()) { // load data, which contains symbol's address - masm.movq(resultReg, new AMD64Address(asRegister(result))); - } + // Data: load its address + masm.leaq(resultReg, address); } + crb.compilationResult.recordDataPatch(before, new CGlobalDataReference(dataInfo)); if (addend != 0) { masm.addq(resultReg, addend); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java index 6b0a3c15355d..e753d57511f3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateDiagnostics.java @@ -67,6 +67,7 @@ import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.graal.RuntimeCompilation; +import com.oracle.svm.core.graal.code.CGlobalDataInfo; import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.RestrictHeapAccess; @@ -890,6 +891,7 @@ public void printDiagnostics(Log log, ErrorContext context, int maxDiagnosticLev log.string("Runtime information:").indent(true); log.string("Isolate id: ").signed(Isolates.getIsolateId()).newline(); log.string("Heap base: ").zhex(KnownIntrinsics.heapBase()).newline(); + log.string("CGlobalData base: ").zhex(CGlobalDataInfo.CGLOBALDATA_RUNTIME_BASE_ADDRESS.getPointer()).newline(); if (Container.singleton().isContainerized()) { log.string("CPU cores (container): "); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/CGlobalDataBasePointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/CGlobalDataBasePointer.java new file mode 100644 index 000000000000..7072aba4c647 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/CGlobalDataBasePointer.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025, 2025, 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.graal.code; + +import static com.oracle.svm.core.util.VMError.shouldNotReachHere; + +import org.graalvm.nativeimage.c.function.RelocatedPointer; +import org.graalvm.word.ComparableWord; +import org.graalvm.word.PointerBase; + +import com.oracle.svm.core.c.CGlobalData; + +/** Placeholder for the base address of {@link CGlobalData} memory during the image build. */ +public final class CGlobalDataBasePointer implements PointerBase, RelocatedPointer { + public static final CGlobalDataBasePointer INSTANCE = new CGlobalDataBasePointer(); + + private CGlobalDataBasePointer() { + } + + private static RuntimeException mustNotBeCalledHosted() { + throw shouldNotReachHere("must not be called in hosted mode"); + } + + @Override + public boolean equal(ComparableWord val) { + throw mustNotBeCalledHosted(); + } + + @Override + public boolean notEqual(ComparableWord val) { + throw mustNotBeCalledHosted(); + } + + @Override + public long rawValue() { + throw mustNotBeCalledHosted(); + } + + @Override + public boolean isNull() { + throw mustNotBeCalledHosted(); + } + + @Override + public boolean isNonNull() { + throw mustNotBeCalledHosted(); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/CGlobalDataInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/CGlobalDataInfo.java index 063c1b987ebf..e6bece627556 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/CGlobalDataInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/CGlobalDataInfo.java @@ -29,19 +29,20 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platform.HOSTED_ONLY; import org.graalvm.nativeimage.Platforms; -import org.graalvm.word.Pointer; import com.oracle.svm.core.BuildPhaseProvider.AfterHeapLayout; import com.oracle.svm.core.BuildPhaseProvider.AfterHostedUniverse; -import com.oracle.svm.core.c.CGlobalData; -import com.oracle.svm.core.c.CGlobalDataFactory; +import com.oracle.svm.core.c.BoxedRelocatedPointer; import com.oracle.svm.core.c.CGlobalDataImpl; import com.oracle.svm.core.heap.UnknownPrimitiveField; import com.oracle.svm.core.util.VMError; public final class CGlobalDataInfo { - public static final String CGLOBALDATA_BASE_SYMBOL_NAME = "__svm_cglobaldata_base"; - public static final CGlobalData CGLOBALDATA_RUNTIME_BASE_ADDRESS = CGlobalDataFactory.forSymbol(CGLOBALDATA_BASE_SYMBOL_NAME); + /** + * Image heap object storing the base address of CGlobalData memory using a relocation. Before + * the image heap is set up, CGlobalData must be accessed via relocations in the code instead. + */ + public static final BoxedRelocatedPointer CGLOBALDATA_RUNTIME_BASE_ADDRESS = new BoxedRelocatedPointer(CGlobalDataBasePointer.INSTANCE); private final CGlobalDataImpl data; private final boolean isSymbolReference; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/CGlobalDataLoadAddressNode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/CGlobalDataLoadAddressNode.java index 5ca0b0545f3b..a3ec5cb45317 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/CGlobalDataLoadAddressNode.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/CGlobalDataLoadAddressNode.java @@ -24,6 +24,13 @@ */ package com.oracle.svm.core.graal.nodes; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.graal.code.CGlobalDataInfo; +import com.oracle.svm.core.graal.code.SubstrateNodeLIRBuilder; + import jdk.graal.compiler.graph.NodeClass; import jdk.graal.compiler.nodeinfo.NodeCycles; import jdk.graal.compiler.nodeinfo.NodeInfo; @@ -32,10 +39,12 @@ import jdk.graal.compiler.nodes.spi.LIRLowerable; import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; -import com.oracle.svm.core.FrameAccess; -import com.oracle.svm.core.graal.code.CGlobalDataInfo; -import com.oracle.svm.core.graal.code.SubstrateNodeLIRBuilder; - +/** + * Directly load the address of {@code CGlobalData} memory. + * + * Only for use in AOT-compiled code because it uses relocations. + */ +@Platforms(Platform.HOSTED_ONLY.class) @NodeInfo(cycles = NodeCycles.CYCLES_1, size = NodeSize.SIZE_1, sizeRationale = "same as LoadAddressNode") public final class CGlobalDataLoadAddressNode extends FloatingNode implements LIRLowerable { public static final NodeClass TYPE = NodeClass.create(CGlobalDataLoadAddressNode.class); diff --git a/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp b/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp index 762709b97a39..5a24d2853806 100644 --- a/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp +++ b/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp @@ -159,6 +159,7 @@ struct ConstantReference { methodId @4 :MethodId; } cEntryPointLiteralCodePointer @5 :CEntryPointLiteralReference; + cGlobalDataBasePointer @6 :Void; } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CGlobalDataFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CGlobalDataFeature.java index 8608536ef2ed..5b12ed9eb0b3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CGlobalDataFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CGlobalDataFeature.java @@ -40,6 +40,7 @@ import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.svm.core.ParsingReason; +import com.oracle.svm.core.c.BoxedRelocatedPointer; import com.oracle.svm.core.c.CGlobalData; import com.oracle.svm.core.c.CGlobalDataImpl; import com.oracle.svm.core.c.CGlobalDataNonConstantRegistry; @@ -57,6 +58,7 @@ import jdk.graal.compiler.core.common.memory.MemoryOrderMode; import jdk.graal.compiler.core.common.type.IntegerStamp; import jdk.graal.compiler.core.common.type.StampFactory; +import jdk.graal.compiler.core.common.type.StampPair; import jdk.graal.compiler.nodes.AbstractBeginNode; import jdk.graal.compiler.nodes.AbstractMergeNode; import jdk.graal.compiler.nodes.BeginNode; @@ -84,6 +86,7 @@ import jdk.graal.compiler.nodes.memory.address.OffsetAddressNode; import jdk.graal.compiler.phases.util.Providers; import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; @@ -93,11 +96,11 @@ public class CGlobalDataFeature implements InternalFeature { private final Method getCGlobalDataInfoMethod = ReflectionUtil.lookupMethod(CGlobalDataNonConstantRegistry.class, "getCGlobalDataInfo", CGlobalDataImpl.class); private final Field offsetField = ReflectionUtil.lookupField(CGlobalDataInfo.class, "offset"); private final Field isSymbolReferenceField = ReflectionUtil.lookupField(CGlobalDataInfo.class, "isSymbolReference"); + private final Field baseHolderPointerField = ReflectionUtil.lookupField(BoxedRelocatedPointer.class, "pointer"); private final CGlobalDataNonConstantRegistry nonConstantRegistry = new CGlobalDataNonConstantRegistry(); private final Map, CGlobalDataInfo> map = new ConcurrentHashMap<>(); - private CGlobalDataInfo cGlobalDataBaseAddress; private int totalSize = -1; public static CGlobalDataFeature singleton() { @@ -111,7 +114,6 @@ private boolean isLaidOut() { @Override public void duringSetup(DuringSetupAccess a) { a.registerObjectReplacer(this::replaceObject); - cGlobalDataBaseAddress = registerAsAccessedOrGet(CGlobalDataInfo.CGLOBALDATA_RUNTIME_BASE_ADDRESS); } @Override @@ -126,33 +128,54 @@ public void registerInvocationPlugins(Providers providers, Plugins plugins, Pars @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { assert providers.getSnippetReflection() instanceof HostedSnippetReflectionProvider; - JavaConstant nonConstantRegistryJavaConstant = providers.getSnippetReflection().forObject(nonConstantRegistry); ValueNode cGlobalDataNode = receiver.get(true); + CGlobalDataInfo constantInfo = null; if (cGlobalDataNode.isConstant()) { CGlobalDataImpl data = providers.getSnippetReflection().asObject(CGlobalDataImpl.class, cGlobalDataNode.asJavaConstant()); - CGlobalDataInfo info = CGlobalDataFeature.this.map.get(data); - b.addPush(targetMethod.getSignature().getReturnKind(), new CGlobalDataLoadAddressNode(info)); - } else { - ConstantNode registry = ConstantNode.forConstant(nonConstantRegistryJavaConstant, b.getMetaAccess(), b.getGraph()); - - ValueNode info = (ValueNode) b.handleReplacedInvoke(InvokeKind.Virtual, b.getMetaAccess().lookupJavaMethod(getCGlobalDataInfoMethod), - new ValueNode[]{registry, cGlobalDataNode}, false); - b.pop(info.getStackKind()); - info = b.nullCheckedValue(info); + constantInfo = CGlobalDataFeature.this.map.get(data); + } - ResolvedJavaType infoType = b.getMetaAccess().lookupJavaType(CGlobalDataInfo.class); - if (infoType instanceof AnalysisType) { - ((AnalysisType) infoType).registerAsReachable("registered by " + CGlobalDataFeature.class.getName()); + if (constantInfo != null && reason != ParsingReason.JITCompilation) { + /* Use a relocation in code to load the location directly */ + b.addPush(targetMethod.getSignature().getReturnKind(), new CGlobalDataLoadAddressNode(constantInfo)); + } else { + ValueNode info; + if (constantInfo != null) { + /* + * JIT-compiled code must get the CGlobalData base address from the holder + * object on the image heap because the code can end up in an auxiliary + * image which is loaded in another process with a different base address. + */ + JavaConstant infoConstant = providers.getSnippetReflection().forObject(constantInfo); + info = ConstantNode.forConstant(infoConstant, b.getMetaAccess(), b.getGraph()); + } else { + // Non-constant CGlobalData must be resolved at runtime through a map. + JavaConstant nonConstantRegistryJavaConstant = providers.getSnippetReflection().forObject(nonConstantRegistry); + ConstantNode registry = ConstantNode.forConstant(nonConstantRegistryJavaConstant, b.getMetaAccess(), b.getGraph()); + + info = (ValueNode) b.handleReplacedInvoke(InvokeKind.Virtual, b.getMetaAccess().lookupJavaMethod(getCGlobalDataInfoMethod), + new ValueNode[]{registry, cGlobalDataNode}, false); + b.pop(info.getStackKind()); + info = b.nullCheckedValue(info); + + ResolvedJavaType infoType = b.getMetaAccess().lookupJavaType(CGlobalDataInfo.class); + if (infoType instanceof AnalysisType aInfoType) { + aInfoType.registerAsReachable("registered by " + CGlobalDataFeature.class.getName()); + } } - ValueNode offset = b.add(LoadFieldNode.create(b.getAssumptions(), info, b.getMetaAccess().lookupJavaField(offsetField))); - CGlobalDataLoadAddressNode baseAddress = b.add(new CGlobalDataLoadAddressNode(cGlobalDataBaseAddress)); + JavaConstant baseHolderConstant = providers.getSnippetReflection().forObject(CGlobalDataInfo.CGLOBALDATA_RUNTIME_BASE_ADDRESS); + ConstantNode baseHolder = ConstantNode.forConstant(baseHolderConstant, b.getMetaAccess(), b.getGraph()); + ResolvedJavaField holderPointerField = providers.getMetaAccess().lookupJavaField(baseHolderPointerField); + StampPair pointerStamp = StampPair.createSingle(providers.getWordTypes().getWordStamp((ResolvedJavaType) holderPointerField.getType())); + LoadFieldNode baseAddress = b.add(LoadFieldNode.createOverrideStamp(pointerStamp, baseHolder, holderPointerField)); - /* Both operands should have the same bits size */ + /* Both address and offset need to have the same bit width. */ + ValueNode offset = b.add(LoadFieldNode.create(b.getAssumptions(), info, b.getMetaAccess().lookupJavaField(offsetField))); ValueNode offsetWidened = b.getGraph().addOrUnique(SignExtendNode.create(offset, IntegerStamp.getBits(baseAddress.stamp(NodeView.DEFAULT)), NodeView.DEFAULT)); ValueNode address = b.add(new AddNode(baseAddress, offsetWidened)); - /* Do not dereference the address if CGlobalDataInfo is not a reference */ + /* Dereference the address if CGlobalDataInfo is a symbol reference. */ ValueNode isSymbolReference = b.add(LoadFieldNode.create(b.getAssumptions(), info, b.getMetaAccess().lookupJavaField(isSymbolReferenceField))); LogicNode condition = IntegerEqualsNode.create(isSymbolReference, ConstantNode.forBoolean(false, b.getGraph()), NodeView.DEFAULT); ReadNode readValue = b.add(new ReadNode(b.add(OffsetAddressNode.create(address)), NamedLocationIdentity.ANY_LOCATION, 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 e3dde81928b1..d2ff1c3a6bc4 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 @@ -88,6 +88,7 @@ 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.CGlobalDataBasePointer; import com.oracle.svm.core.graal.code.CGlobalDataInfo; import com.oracle.svm.core.graal.code.CGlobalDataReference; import com.oracle.svm.core.image.ImageHeapLayoutInfo; @@ -484,7 +485,6 @@ public void build(String imageName, DebugContext debug) { (offset, symbolName, isGlobalSymbol) -> objectFile.createDefinedSymbol(symbolName, rwDataSection, offset + RWDATA_CGLOBALS_PARTITION_OFFSET, wordSize, false, isGlobalSymbol || SubstrateOptions.InternalSymbolsAreGlobal.getValue()), (offset, symbolName, isGlobalSymbol) -> defineRelocationForSymbol(symbolName, offset)); - defineDataSymbol(CGlobalDataInfo.CGLOBALDATA_BASE_SYMBOL_NAME, rwDataSection, RWDATA_CGLOBALS_PARTITION_OFFSET); // - Write the heap to its own section. // Dynamic linkers/loaders generally don't ensure any alignment to more than page @@ -601,22 +601,18 @@ public void markRelocationSitesFromBuffer(RelocatableBuffer buffer, ProgbitsSect assert ConfigurationValues.getTarget().arch instanceof AArch64 || checkEmbeddedOffset(sectionImpl, offset, info); - // Figure out what kind of relocation site it is. if (info.getTargetObject() instanceof CFunctionPointer) { - // References to functions are via relocations to the symbol for the function. markFunctionRelocationSite(sectionImpl, offset, info); } else { - // A data relocation. if (sectionImpl.getElement() == textSection) { - // A wrinkle on relocations *from* the text section: they are *always* to - // constants (in the "constant partition" of the roDataSection). markDataRelocationSiteFromText(buffer, sectionImpl, offset, info); + } else if (info.getTargetObject() instanceof CGlobalDataBasePointer) { + assert info.getAddend() == 0 : "addressing from base not intended"; + sectionImpl.markRelocationSite(offset, info.getRelocationKind(), rwDataSection.getName(), RWDATA_CGLOBALS_PARTITION_OFFSET); } else { - // Relocations from other sections go to the section containing the target. - // Pass along the information about the target. final JavaConstant targetConstant = (JavaConstant) info.getTargetObject(); final ObjectInfo targetObjectInfo = heap.getConstantInfo(targetConstant); - markDataRelocationSite(sectionImpl, offset, info, targetObjectInfo); + markHeapReferenceRelocationSite(sectionImpl, offset, info, targetObjectInfo); } } } @@ -658,7 +654,6 @@ private void markFunctionRelocationSite(final ProgbitsSectionImpl sectionImpl, f validateNoDirectRelocationsInTextSection(info); } - // References to functions are via relocations to the symbol for the function. MethodPointer methodPointer = (MethodPointer) info.getTargetObject(); ResolvedJavaMethod method = methodPointer.getMethod(); HostedMethod target = (method instanceof HostedMethod) ? (HostedMethod) method : heap.hUniverse.lookup(method); @@ -669,7 +664,6 @@ private void markFunctionRelocationSite(final ProgbitsSectionImpl sectionImpl, f } assert checkMethodPointerRelocationKind(info); - // A reference to a method. Mark the relocation site using the symbol name. relocationProvider.markMethodPointerRelocation(sectionImpl, offset, info.getRelocationKind(), target, info.getAddend(), methodPointer, injectedNotCompiled); } @@ -692,15 +686,9 @@ private static boolean isAddendAligned(Architecture arch, long addend, Relocatio return true; } - // TODO: These two methods for marking data relocations might have to be merged if text sections - // TODO: ever have relocations to some where other than constants at the beginning of the - // TODO: read-only data section. - - // A reference to data. Mark the relocation using the section and addend in the relocation info. - private void markDataRelocationSite(ProgbitsSectionImpl sectionImpl, int offset, RelocatableBuffer.Info info, ObjectInfo targetObjectInfo) { - // References to objects are via relocations to offsets in the heap section. + /** Mark a relocation site for the location of an image heap object. */ + private void markHeapReferenceRelocationSite(ProgbitsSectionImpl sectionImpl, int offset, RelocatableBuffer.Info info, ObjectInfo targetObjectInfo) { assert ConfigurationValues.getTarget().arch instanceof AArch64 || info.getRelocationSize() == 4 || info.getRelocationSize() == 8 : "AMD64 Data relocation size should be 4 or 8 bytes."; - assert targetObjectInfo != null; String targetSectionName = heapSection.getName(); long relocationAddend = targetObjectInfo.getOffset() + info.getAddend(); sectionImpl.markRelocationSite(offset, info.getRelocationKind(), targetSectionName, relocationAddend); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java index 650475f8d788..20a6a08e5cb5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java @@ -34,7 +34,6 @@ import java.util.stream.Stream; import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.nativeimage.c.function.RelocatedPointer; import org.graalvm.nativeimage.impl.CEntryPointLiteralCodePointer; import org.graalvm.word.WordBase; @@ -48,6 +47,7 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.config.ObjectLayout; +import com.oracle.svm.core.graal.code.CGlobalDataBasePointer; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.ObjectHeader; import com.oracle.svm.core.hub.DynamicHub; @@ -314,8 +314,7 @@ private void addDirectRelocationWithAddend(RelocatableBuffer buffer, int index, */ private void addNonDataRelocation(RelocatableBuffer buffer, int index, RelocatedPointer pointer) { mustBeReferenceAligned(index); - assert pointer instanceof CFunctionPointer : "unknown relocated pointer " + pointer; - assert pointer instanceof MethodPointer : "cannot create relocation for unknown FunctionPointer " + pointer; + assert pointer instanceof MethodPointer || pointer instanceof CGlobalDataBasePointer : "unknown relocated pointer " + pointer; int pointerSize = ConfigurationValues.getTarget().wordSize; addDirectRelocationWithoutAddend(buffer, index, pointerSize, pointer); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/RelocatableBuffer.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/RelocatableBuffer.java index 9ba53597e6c6..8fa80ca72e48 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/RelocatableBuffer.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/RelocatableBuffer.java @@ -37,6 +37,7 @@ import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.objectfile.ObjectFile; +import com.oracle.svm.core.graal.code.CGlobalDataBasePointer; import com.oracle.svm.core.meta.MethodPointer; import jdk.graal.compiler.core.common.NumUtil; @@ -96,7 +97,8 @@ public static final class Info { this.targetObject = targetObject; /* Sanity check for allowed groups of target objects. */ - assert targetObject instanceof Reference || targetObject instanceof MethodPointer || targetObject instanceof ImageHeapConstant : targetObject; + assert targetObject instanceof Reference || targetObject instanceof MethodPointer || + targetObject instanceof CGlobalDataBasePointer || targetObject instanceof ImageHeapConstant : targetObject; } public int getRelocationSize() { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java index 988998d3200e..f00890f15296 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java @@ -1415,6 +1415,11 @@ private boolean delegateProcessing(ConstantReference.Reader constantRef, Object[ .map(this::lookupBaseLayerTypeInHostVM).toArray(Class[]::new); values[i] = new RelocatableConstant(new CEntryPointLiteralCodePointer(definingClass, methodName, parameterTypes), cEntryPointerLiteralPointerType); return true; + } else if (constantRef.isCGlobalDataBasePointer()) { + values[i] = new AnalysisFuture<>(() -> { + throw AnalysisError.shouldNotReachHere("Reading the CGlobalData base address of the base image is not implemented."); + }); + return true; } return false; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java index 39e2f5e51dfb..be25b4b47705 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java @@ -105,6 +105,7 @@ import com.oracle.svm.core.StaticFieldsSupport; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.classinitialization.ClassInitializationInfo; +import com.oracle.svm.core.graal.code.CGlobalDataBasePointer; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.layeredimagesingleton.ImageSingletonWriter; import com.oracle.svm.core.layeredimagesingleton.InitialLayerOnlyImageSingleton; @@ -943,6 +944,9 @@ private static boolean delegateProcessing(ConstantReference.Builder builder, Obj b.getParameterNames().set(i, new Text.Reader(cp.parameterTypes[i].getName())); } return true; + } else if (pointer instanceof CGlobalDataBasePointer) { + builder.setCGlobalDataBasePointer(Void.VOID); + return true; } } return false; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java index 7036f7ad05c0..5980a97fcdf3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java @@ -2402,6 +2402,7 @@ public Which which() { case 3 : return Which.PRIMITIVE_VALUE; case 4 : return Which.METHOD_POINTER; case 5 : return Which.C_ENTRY_POINT_LITERAL_CODE_POINTER; + case 6 : return Which.C_GLOBAL_DATA_BASE_POINTER; default: return Which._NOT_IN_SCHEMA; } } @@ -2488,6 +2489,18 @@ public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchema _setShortField(2, (short)ConstantReference.Which.C_ENTRY_POINT_LITERAL_CODE_POINTER.ordinal()); return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference.factory,0, 0); } + public final boolean isCGlobalDataBasePointer() { + return which() == ConstantReference.Which.C_GLOBAL_DATA_BASE_POINTER; + } + public final org.capnproto.Void getCGlobalDataBasePointer() { + assert which() == ConstantReference.Which.C_GLOBAL_DATA_BASE_POINTER: + "Must check which() before get()ing a union member."; + return org.capnproto.Void.VOID; + } + public final void setCGlobalDataBasePointer(org.capnproto.Void value) { + _setShortField(2, (short)ConstantReference.Which.C_GLOBAL_DATA_BASE_POINTER.ordinal()); + } + } public static final class Reader extends org.capnproto.StructReader { @@ -2503,6 +2516,7 @@ public Which which() { case 3 : return Which.PRIMITIVE_VALUE; case 4 : return Which.METHOD_POINTER; case 5 : return Which.C_ENTRY_POINT_LITERAL_CODE_POINTER; + case 6 : return Which.C_GLOBAL_DATA_BASE_POINTER; default: return Which._NOT_IN_SCHEMA; } } @@ -2562,6 +2576,15 @@ assert which() == ConstantReference.Which.C_ENTRY_POINT_LITERAL_CODE_POINTER: return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference.factory,0,null, 0); } + public final boolean isCGlobalDataBasePointer() { + return which() == ConstantReference.Which.C_GLOBAL_DATA_BASE_POINTER; + } + public final org.capnproto.Void getCGlobalDataBasePointer() { + assert which() == ConstantReference.Which.C_GLOBAL_DATA_BASE_POINTER: + "Must check which() before get()ing a union member."; + return org.capnproto.Void.VOID; + } + } public enum Which { @@ -2571,6 +2594,7 @@ public enum Which { PRIMITIVE_VALUE, METHOD_POINTER, C_ENTRY_POINT_LITERAL_CODE_POINTER, + C_GLOBAL_DATA_BASE_POINTER, _NOT_IN_SCHEMA, } public static class ObjectConstant { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java index efe327080ae5..f0c1412a38fc 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java @@ -30,6 +30,7 @@ import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.svm.core.graal.code.CGlobalDataBasePointer; import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; @@ -117,10 +118,10 @@ protected boolean isClassInitialized(ResolvedJavaField field) { @Override protected boolean isFinalFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool tool) { - if (value.getJavaKind() == JavaKind.Object && metaAccess.isInstanceOf(value, MethodPointer.class)) { + if (value.getJavaKind() == JavaKind.Object && (metaAccess.isInstanceOf(value, MethodPointer.class) || metaAccess.isInstanceOf(value, CGlobalDataBasePointer.class))) { /* - * Prevent the constant folding of MethodPointer objects. MethodPointer is a "hosted" - * type, so it cannot be present in compiler graphs. + * Prevent the constant folding of RelocatablePointer placeholder objects. These are + * "hosted" types and so cannot be present in compiler graphs. */ return false; }