diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index c758f06eaa8d..9ff21f273eb9 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -1805,7 +1805,7 @@ public interface Symbol { public abstract Symbol createDefinedSymbol(String name, Element baseSection, long position, int size, boolean isCode, boolean isGlobal); - public abstract Symbol createUndefinedSymbol(String name, int size, boolean isCode); + public abstract Symbol createUndefinedSymbol(String name, boolean isCode); protected abstract SymbolTable createSymbolTable(); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index 60ab09fd39a5..e5613300d420 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -190,7 +190,7 @@ public Symbol createDefinedSymbol(String name, Element baseSection, long positio } @Override - public Symbol createUndefinedSymbol(String name, int size, boolean isCode) { + public Symbol createUndefinedSymbol(String name, boolean isCode) { ELFSymtab symtab = createSymbolTable(); return symtab.newUndefinedEntry(name, isCode); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachOObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachOObjectFile.java index eb833b4c777e..97330b81f67e 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachOObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachOObjectFile.java @@ -180,7 +180,7 @@ public Symbol createDefinedSymbol(String name, Element baseSection, long positio } @Override - public Symbol createUndefinedSymbol(String name, int size, boolean isCode) { + public Symbol createUndefinedSymbol(String name, boolean isCode) { MachOSymtab symtab = (MachOSymtab) getOrCreateSymbolTable(); return symtab.newUndefinedEntry(name, isCode); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java index 98904f2cbf76..d28fb5aa9854 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java @@ -114,7 +114,7 @@ public Symbol createDefinedSymbol(String name, Element baseSection, long positio } @Override - public Symbol createUndefinedSymbol(String name, int size, boolean isCode) { + public Symbol createUndefinedSymbol(String name, boolean isCode) { PECoffSymtab st = createSymbolTable(); return st.newUndefinedEntry(name, isCode); } 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 1cedfffa2785..39f5f8b88634 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 @@ -293,7 +293,7 @@ public void patchMethods(DebugContext debug, RelocatableBuffer relocs, ObjectFil CGlobalDataInfo info = ((CGlobalDataReference) dataPatch.reference).getDataInfo(); CGlobalDataImpl data = info.getData(); if (info.isSymbolReference() && objectFile.getOrCreateSymbolTable().getSymbol(data.symbolName) == null) { - objectFile.createUndefinedSymbol(data.symbolName, 0, true); + objectFile.createUndefinedSymbol(data.symbolName, true); } String symbolName = (String) dataPatch.note; @@ -319,7 +319,7 @@ public NativeTextSectionImpl getTextSectionImpl(RelocatableBuffer buffer, Object return new NativeTextSectionImpl(buffer, objectFile, codeCache) { @Override protected void defineMethodSymbol(String name, boolean global, Element section, HostedMethod method, CompilationResult result) { - ObjectFile.Symbol symbol = objectFile.createUndefinedSymbol(name, 0, true); + ObjectFile.Symbol symbol = objectFile.createUndefinedSymbol(name, true); if (global) { globalSymbols.add(symbol); } diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/objectfile/LLVMObjectFile.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/objectfile/LLVMObjectFile.java index bc3801c339a8..460fb11104d0 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/objectfile/LLVMObjectFile.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/objectfile/LLVMObjectFile.java @@ -165,7 +165,7 @@ public Symbol createDefinedSymbol(String name, Element baseSection, long positio } @Override - public Symbol createUndefinedSymbol(String name, int size, boolean isCode) { + public Symbol createUndefinedSymbol(String name, boolean isCode) { SymbolTable symtab = getOrCreateSymbolTable(); return symtab.newUndefinedEntry(name, isCode); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/CGlobalData.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/CGlobalData.java index 3efd8899664a..9c64d3afefd3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/CGlobalData.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/CGlobalData.java @@ -31,7 +31,7 @@ /** * An object of this class represents a chunk of static global data that is located outside the heap * and can be accessed directly {@linkplain PointerBase by address}. No - * {@linkplain CEntryPointOptions#prologue()} Java execution context} is required. + * {@linkplain CEntryPointOptions#prologue() Java execution context} is required. */ public abstract class CGlobalData { /** diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/CGlobalDataImpl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/CGlobalDataImpl.java index 748d11217bfe..945119471bf6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/CGlobalDataImpl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/CGlobalDataImpl.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.core.c; +import java.util.EnumSet; +import java.util.Optional; import java.util.function.IntSupplier; import java.util.function.Supplier; @@ -31,7 +33,15 @@ import org.graalvm.nativeimage.Platforms; import org.graalvm.word.PointerBase; +import com.oracle.svm.core.graal.code.CGlobalDataInfo; + +/** + * Stores static information about a CGlobal. Build-specific information is stored in + * {@link CGlobalDataInfo}. This separation of data is used to facilitate storing + * {@link CGlobalDataImpl} within static fields. + */ public final class CGlobalDataImpl extends CGlobalData { + /** * The name of the symbol to create for this data (or null to create no symbol), or if the other * fields are null, the name of the symbol to be referenced by this instance. @@ -39,6 +49,13 @@ public final class CGlobalDataImpl extends CGlobalData @Platforms(Platform.HOSTED_ONLY.class) // public final String symbolName; + /** + * When a CGlobal does not have a {@link #symbolName}, when building layered images, + * {@link #computeCodeLocation} is used as a unique key. + */ + @Platforms(Platform.HOSTED_ONLY.class) // + public final StackWalker.StackFrame codeLocation; + @Platforms(Platform.HOSTED_ONLY.class) // public final Supplier bytesSupplier; @Platforms(Platform.HOSTED_ONLY.class) // @@ -74,6 +91,11 @@ public final class CGlobalDataImpl extends CGlobalData this(symbolName, null, null, nonConstant); } + @Platforms(Platform.HOSTED_ONLY.class) + public boolean isSymbolReference() { + return bytesSupplier == null && sizeSupplier == null; + } + @Platforms(Platform.HOSTED_ONLY.class) private CGlobalDataImpl(String symbolName, Supplier bytesSupplier, IntSupplier sizeSupplier, boolean nonConstant) { assert !(bytesSupplier != null && sizeSupplier != null); @@ -81,5 +103,26 @@ private CGlobalDataImpl(String symbolName, Supplier bytesSupplier, IntSu this.bytesSupplier = bytesSupplier; this.sizeSupplier = sizeSupplier; this.nonConstant = nonConstant; + /* + * Note the uniqueness of code locations is checked in + * CGlobalDataFeature#createCGlobalDataInfo. + */ + this.codeLocation = this.symbolName == null ? computeCodeLocation() : null; + } + + /** + * A CGlobal's code location is defined to be the caller of the {@link CGlobalDataFactory} used + * to create the instance. + */ + @Platforms(Platform.HOSTED_ONLY.class) + private static StackWalker.StackFrame computeCodeLocation() { + var walker = StackWalker.getInstance(EnumSet.of(StackWalker.Option.RETAIN_CLASS_REFERENCE)); + return walker.walk((stackStream) -> { + Optional result = stackStream.filter(stackFrame -> { + var declaringClass = stackFrame.getDeclaringClass(); + return declaringClass != CGlobalDataImpl.class && declaringClass != CGlobalDataFactory.class; + }).findFirst(); + return result.get(); + }); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/CGlobalDataNonConstantRegistry.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/CGlobalDataNonConstantRegistry.java index 364e6c456496..820f3e3c3e35 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/CGlobalDataNonConstantRegistry.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/c/CGlobalDataNonConstantRegistry.java @@ -24,9 +24,6 @@ */ package com.oracle.svm.core.c; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - import org.graalvm.collections.EconomicMap; import org.graalvm.collections.Equivalence; import org.graalvm.nativeimage.Platform; @@ -45,9 +42,6 @@ public class CGlobalDataNonConstantRegistry { private final EconomicMap, CGlobalDataInfo> cGlobalDataInfos = ImageHeapMap.create(Equivalence.IDENTITY, "cGlobalDataInfos"); - @Platforms(Platform.HOSTED_ONLY.class) // - private final Lock lock = new ReentrantLock(); - /** * Invoked at runtime via com.oracle.svm.hosted.c.CGlobalDataFeature#getCGlobalDataInfoMethod. */ @@ -62,11 +56,10 @@ public CGlobalDataInfo getCGlobalDataInfo(CGlobalDataImpl cGlobalData) { @Platforms(Platform.HOSTED_ONLY.class) public void registerNonConstantSymbol(CGlobalDataInfo cGlobalDataInfo) { - lock.lock(); - try { - cGlobalDataInfos.put(cGlobalDataInfo.getData(), cGlobalDataInfo); - } finally { - lock.unlock(); - } + /* + * Note at build time ImageHeapMaps are backed by a concurrent hash map, so this code is + * thread safe. + */ + cGlobalDataInfos.put(cGlobalDataInfo.getData(), cGlobalDataInfo); } } 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 e6bece627556..6eedbd5bf7ac 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 @@ -37,6 +37,11 @@ import com.oracle.svm.core.heap.UnknownPrimitiveField; import com.oracle.svm.core.util.VMError; +/** + * Stores build-specific information about a CGlobal. Static information is stored in + * {@link CGlobalDataImpl}. This separation of data is used to facilitate storing + * {@link CGlobalDataImpl} within static fields. + */ public final class CGlobalDataInfo { /** * Image heap object storing the base address of CGlobalData memory using a relocation. Before @@ -47,7 +52,15 @@ public final class CGlobalDataInfo { private final CGlobalDataImpl data; private final boolean isSymbolReference; + /** + * Denotes whether this CGlobal has been defined as a global in a prior layer. This also implies + * in a prior layer that the CGlobal was not a symbol reference. + */ + @Platforms(Platform.HOSTED_ONLY.class) private final boolean definedAsGlobalInPriorLayer; + + /** See CGlobalDataFeature#registerWithGlobalSymbol. */ @UnknownPrimitiveField(availability = AfterHostedUniverse.class) private boolean isGlobalSymbol; + /** See CGlobalDataFeature#registerWithGlobalHiddenSymbol. */ @UnknownPrimitiveField(availability = AfterHostedUniverse.class) private boolean isHiddenSymbol; @UnknownPrimitiveField(availability = AfterHeapLayout.class) private int offset = -1; @UnknownPrimitiveField(availability = AfterHeapLayout.class) private int size = -1; @@ -56,11 +69,12 @@ public final class CGlobalDataInfo { @Platforms(HOSTED_ONLY.class) private byte[] bytes; @Platforms(Platform.HOSTED_ONLY.class) - public CGlobalDataInfo(CGlobalDataImpl data) { + public CGlobalDataInfo(CGlobalDataImpl data, boolean definedAsGlobalInPriorLayer) { assert data != null; this.data = data; - this.isSymbolReference = (data.bytesSupplier == null && data.sizeSupplier == null); + this.isSymbolReference = data.isSymbolReference(); assert !this.isSymbolReference || data.symbolName != null; + this.definedAsGlobalInPriorLayer = definedAsGlobalInPriorLayer; } public CGlobalDataImpl getData() { @@ -100,7 +114,16 @@ public int getSize() { } public void makeGlobalSymbol() { - VMError.guarantee(!isSymbolReference && data.symbolName != null, "Cannot change the local/global status of a symbol reference"); + if (isSymbolReference) { + /* + * Only CGlobals assigned to global data chunks allocated by native image can be defined + * as global symbols. If the symbol was defined as a global symbol in a prior layer, + * this request is a no-op. + */ + VMError.guarantee(definedAsGlobalInPriorLayer, "Cannot change the local/global status of a symbol reference %s", data.symbolName); + return; + } + VMError.guarantee(data.symbolName != null, "No symbol name associated with data reference"); isGlobalSymbol = true; } diff --git a/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp b/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp index 50bec81d1590..4f799abba7a1 100644 --- a/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp +++ b/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp @@ -301,6 +301,7 @@ struct SharedLayerSnapshot { nodeClassMapLocation @20 :Text; sharedLayerBootLayerModules @21 :List(Text); layeredModule @22 :LayeredModule; + cGlobals @23 :List(CGlobalDataInfo); } struct StaticFinalFieldFoldingSingleton { @@ -351,6 +352,22 @@ struct PrimitiveArray { } } +struct CGlobalDataInfo { + isSymbolReference @0 :Bool; + isGlobalSymbol @1 :Bool; + nonConstant @2 :Bool; + layeredSymbolName @3 :Text; + linkingInfo :union { + originalSymbolName @4 :Text; + codeLocation @5 :CodeLocation; + } +} + +struct CodeLocation { + bytecodeIndex @0 :Int32; + stacktraceName @1 :Text; +} + struct DispatchSlotInfo { declaredHostedMethodIndex @0 :HostedMethodIndex; resolvedHostedMethodIndex @1 :HostedMethodIndex; 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 d225b4573bab..c2e532b4a054 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 @@ -203,6 +203,7 @@ import com.oracle.svm.hosted.annotation.SubstrateAnnotationExtractor; import com.oracle.svm.hosted.c.CAnnotationProcessorCache; import com.oracle.svm.hosted.c.CConstantValueSupportImpl; +import com.oracle.svm.hosted.c.CGlobalDataFeature; import com.oracle.svm.hosted.c.NativeLibraries; import com.oracle.svm.hosted.c.OffsetOfSupportImpl; import com.oracle.svm.hosted.c.SizeOfSupportImpl; @@ -1004,6 +1005,7 @@ protected void setupNativeImage(OptionValues options, Map isStaticBinaryMarker = CGlobalDataFactory.createWord(Word.unsigned(SubstrateOptions.StaticExecutable.getValue() ? 1 : 0), STATIC_BINARY_MARKER_SYMBOL_NAME); - CGlobalDataFeature.singleton().registerWithGlobalHiddenSymbol(isStaticBinaryMarker); + if (ImageLayerBuildingSupport.buildingImageLayer()) { + /* + * GR-55032: currently in layered images we must register this symbol as global so + * that it is visible from JvmFuncs.c linked in any layer. In the future we will + * ensure JvmFunc.c is linked in the initial layer. + */ + CGlobalDataFeature.singleton().registerWithGlobalSymbol(isStaticBinaryMarker); + } else { + CGlobalDataFeature.singleton().registerWithGlobalHiddenSymbol(isStaticBinaryMarker); + } } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/AppLayerCGlobalTracking.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/AppLayerCGlobalTracking.java new file mode 100644 index 000000000000..388286edae91 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/AppLayerCGlobalTracking.java @@ -0,0 +1,272 @@ +/* + * 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.hosted.c; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import com.oracle.svm.core.c.CGlobalData; +import com.oracle.svm.core.c.CGlobalDataFactory; +import com.oracle.svm.core.c.CGlobalDataImpl; +import com.oracle.svm.core.graal.code.CGlobalDataInfo; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.imagelayer.CodeLocation; +import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder; + +/** + * Discovers and links CGlobals that were also installed in a prior layer. This is needed to ensure + * CGlobals refer to a consistent location regardless of the layer in which the code was compiled + * in. In other words, if a CGlobal was assigned a chunk of static global data in a prior layer, + * then the CGlobal defined in this layer must be a symbol reference to the same data chunk. + */ +public class AppLayerCGlobalTracking { + record PriorLayerCGlobal(CGlobalDataImpl impl, + SharedLayerSnapshotCapnProtoSchemaHolder.CGlobalDataInfo.Reader persistedInfo) { + + } + + /** + * Keeps track of symbol names which were defined in prior layers. Used for matching + * {@link CGlobalDataImpl}s within {@link #getCanonicalRepresentation} + */ + private Map symbolNameToPriorLayerCGlobals; + /** + * Keeps track of code locations for {@link CGlobalDataImpl}s defined in prior layers. Used for + * matching {@link CGlobalDataImpl}s within {@link #getCanonicalRepresentation} + */ + private Map codeLocationToPriorLayerCGlobals; + /** Used for decoding CGlobal information from persisted graphs. */ + private List priorLayerCGlobals; + + /** + * Tracks CGlobals assigned a chunk of static global data in this layer that have references in + * prior layers. We use this collection to validate that these CGlobals have been registered in + * a way which allows linking to successfully complete. + */ + private Set> cGlobalsWithPriorLayerReferences; + /** + * Tracks which CGlobals are defined in this layer that were + * {@link CGlobalDataImpl#isSymbolReference()} in prior layers. + */ + private Map> cGlobalsWithPriorLayerReferencesMap = new ConcurrentHashMap<>(); + + /** Saves the results of {@link #getCanonicalRepresentation}. */ + private final Map, CGlobalDataImpl> canonicalizationCache = new ConcurrentHashMap<>(); + + /** + * Tracks which {@link CGlobalDataImpl} a {@link CodeLocation} is linked to in the current + * layer. This is used to ensure the same code location is not linked to multiple + * {@link CGlobalDataImpl}s. + */ + private final Map> linkedCodeLocations = new ConcurrentHashMap<>(); + + /** + * A map used within {@link #createCGlobalDataInfo} to initialize {@link CGlobalDataInfo}s + * appropriately. + */ + private Map, PriorLayerCGlobal> cGlobalToPriorLayerCGlobals; + + private final CGlobalDataFeature cGlobalDataFeature; + + AppLayerCGlobalTracking(CGlobalDataFeature cGlobalDataFeature) { + this.cGlobalDataFeature = cGlobalDataFeature; + } + + /** + * Registers a CGlobal which was a {@link CGlobalDataImpl#isSymbolReference()} in prior layers, + * but is assigned of chunk of static global data in this layer. + */ + public void registerCGlobalWithPriorLayerReference(CGlobalData info) { + /* + * Note this code will either need to be adjusted to work with 3+ layers or we must forbid + * this method from being called in intermediate layers. + */ + VMError.guarantee(cGlobalsWithPriorLayerReferencesMap != null, "registerCGlobalWithPriorLayerReference cannot be called after afterRegistration is complete."); + CGlobalDataImpl data = (CGlobalDataImpl) info; + VMError.guarantee(data.symbolName != null && !data.isSymbolReference(), + "registerCGlobalWithPriorLayerReference can only be used to register CGlobals which were symbol references in prior layers and are not in the current layer" + + ".%nIn addition, a symbol name must associated with the CGlobal so linking is possible.%nCGlobal: %s", + data.symbolName); + var prev = cGlobalsWithPriorLayerReferencesMap.put(data.symbolName, data); + VMError.guarantee(prev == null, "Multiple CGlobals registered with the same symbol name %s", data.symbolName); + } + + public CGlobalDataInfo registerOrGetCGlobalDataInfoByPersistedIndex(int index) { + var priorCGlobal = priorLayerCGlobals.get(index); + return cGlobalDataFeature.registerAsAccessedOrGet(priorCGlobal.impl(), false); + } + + public CGlobalDataImpl registerOrGetCGlobalDataImplByPersistedIndex(int index) { + var priorCGlobal = priorLayerCGlobals.get(index); + cGlobalDataFeature.registerAsAccessedOrGet(priorCGlobal.impl(), false); + return priorCGlobal.impl(); + } + + /** + * CGlobals with links to prior layers may also have + * {@code CGlobalDataInfo#definedAsGlobalInPriorLayer} set. + */ + CGlobalDataInfo createCGlobalDataInfo(CGlobalDataImpl impl) { + PriorLayerCGlobal info = cGlobalToPriorLayerCGlobals.get(impl); + if (info != null) { + boolean definedAsGlobalInPriorLayer = info.persistedInfo().getIsGlobalSymbol(); + if (!info.impl().isSymbolReference()) { + assert !info.persistedInfo().getIsGlobalSymbol() : info; + } + return cGlobalDataFeature.createCGlobalDataInfo(impl, definedAsGlobalInPriorLayer); + } + + return null; + } + + private CGlobalDataImpl getCanonicalRepresentationForPriorLayerCGlobal(CGlobalDataImpl input, PriorLayerCGlobal priorCGlobal) { + /* + * We currently expect the non-constant marker to be consistent across all layers and + * declaration. If desired, in the future we can relax this to !(input.nonConstant && + * !canonicalRepresentation.nonConstant). + * + * We also expect newly non-symbol references defined in this layer to be explicitly labeled + * via registerCGlobalWithPriorLayerReference. + */ + CGlobalDataImpl canonicalRepr = priorCGlobal.impl(); + VMError.guarantee(input.nonConstant == canonicalRepr.nonConstant); + if (!input.isSymbolReference() && priorCGlobal.persistedInfo().getIsSymbolReference()) { + VMError.guarantee(cGlobalsWithPriorLayerReferences.contains(canonicalRepr), + "Found CGlobal which was a symbol reference in a prior layer but is not in this layer: %s%n. If this is intentional please register via registerCGlobalWithPriorLayerReference", + input.symbolName); + } + return canonicalRepr; + } + + /** + * Returns the canonical representation for this CGlobal in this layer. This is needed because + * {@link CGlobalDataImpl} instances from the prior layer can be loaded via persisted graphs; + * without this canonicalization step it would be possible for multiple {@link CGlobalDataImpl} + * instances to be linked to the same symbol. + */ + CGlobalDataImpl getCanonicalRepresentation(CGlobalDataImpl input) { + CGlobalDataImpl result = canonicalizationCache.get(input); + if (result != null) { + return result; + } + + if (input.symbolName != null) { + var ref = symbolNameToPriorLayerCGlobals.get(input.symbolName); + if (ref != null) { + result = getCanonicalRepresentationForPriorLayerCGlobal(input, ref); + } + } + if (result == null && input.codeLocation != null) { + CodeLocation codeLocation = CodeLocation.fromStackFrame(input.codeLocation); + var ref = codeLocationToPriorLayerCGlobals.get(codeLocation); + if (ref != null) { + var prev = linkedCodeLocations.put(codeLocation, input); + VMError.guarantee(prev == null || prev == input, "Multiple inputs seen for same code location: %s %s %s", codeLocation, prev, input); + result = getCanonicalRepresentationForPriorLayerCGlobal(input, ref); + } + } + if (result == null) { + result = input; + } + + var prev = canonicalizationCache.putIfAbsent(input, result); + VMError.guarantee(prev == null || prev.equals(result), "Cache is providing inconsistent results: %s %s %s", input, result, prev); + return result; + } + + /** + * We must ensure that CGlobals registered via {@link #registerCGlobalWithPriorLayerReference} + * are set as global and not hidden. This is needed because symbols in prior layers must link to + * them. + */ + void validateCGlobals(Map, CGlobalDataInfo> map) { + for (var impl : cGlobalsWithPriorLayerReferences) { + CGlobalDataInfo info = map.get(impl); + boolean validState = info != null && info.isGlobalSymbol() && !info.isHiddenSymbol(); + VMError.guarantee(validState, "CGlobals registered via registerCGlobalWithPriorLayerReference must also be registered as global and cannot be registered as hidden: %s", impl.symbolName); + } + } + + /** Load all CGlobals registered in prior layers. */ + public void initializePriorLayerCGlobals() { + var loader = HostedImageLayerBuildingSupport.singleton().getLoader(); + Map newSymbolNameToPriorLayerCGlobals = new HashMap<>(); + Map newCodeLocationToPriorLayerCGlobals = new HashMap<>(); + ArrayList newPriorLayerCGlobals = new ArrayList<>(); + Set> newCGlobalsWithPriorLayerReferences = new HashSet<>(); + Map, PriorLayerCGlobal> newCGlobalToPriorLayerCGlobals = new HashMap<>(); + for (var persistedInfo : loader.getCGlobals()) { + String symbolName = persistedInfo.getLayeredSymbolName().toString(); + CGlobalDataImpl globalEntry = null; + if (persistedInfo.getLinkingInfo().hasOriginalSymbolName()) { + String originalSymbolName = persistedInfo.getLinkingInfo().getOriginalSymbolName().toString(); + globalEntry = cGlobalsWithPriorLayerReferencesMap.get(originalSymbolName); + if (globalEntry != null) { + newCGlobalsWithPriorLayerReferences.add(globalEntry); + VMError.guarantee(persistedInfo.getIsSymbolReference(), "We can only override CGlobals which were symbol references in prior layers %s", + originalSymbolName); + } + } + + if (globalEntry == null) { + globalEntry = (CGlobalDataImpl) CGlobalDataFactory.forSymbol(symbolName, persistedInfo.getNonConstant()); + } + var priorInfo = new PriorLayerCGlobal(globalEntry, persistedInfo); + + /* + * At this point we are not creating the CGlobalDataInfo. This is intentional so that we + * do not need to install all prior CGlobals as symbols in this layer. Instead, we + * create the CGlobalDataInfo upon the first reference to the CGlobalDataImpl. + */ + if (persistedInfo.getLinkingInfo().hasOriginalSymbolName()) { + String originalSymbolName = persistedInfo.getLinkingInfo().getOriginalSymbolName().toString(); + var previous = newSymbolNameToPriorLayerCGlobals.put(originalSymbolName, priorInfo); + VMError.guarantee(previous == null); + } else if (persistedInfo.getLinkingInfo().hasCodeLocation()) { + var callSiteInfo = persistedInfo.getLinkingInfo().getCodeLocation(); + int bci = callSiteInfo.getBytecodeIndex(); + String stacktrace = callSiteInfo.getStacktraceName().toString(); + var previous = newCodeLocationToPriorLayerCGlobals.put(new CodeLocation(bci, stacktrace), priorInfo); + VMError.guarantee(previous == null); + } + var previous = newCGlobalToPriorLayerCGlobals.put(globalEntry, priorInfo); + VMError.guarantee(previous == null); + newPriorLayerCGlobals.add(priorInfo); + } + priorLayerCGlobals = Collections.unmodifiableList(newPriorLayerCGlobals); + symbolNameToPriorLayerCGlobals = Collections.unmodifiableMap(newSymbolNameToPriorLayerCGlobals); + codeLocationToPriorLayerCGlobals = Collections.unmodifiableMap(newCodeLocationToPriorLayerCGlobals); + cGlobalsWithPriorLayerReferences = Collections.unmodifiableSet(newCGlobalsWithPriorLayerReferences); + cGlobalToPriorLayerCGlobals = Collections.unmodifiableMap(newCGlobalToPriorLayerCGlobals); + cGlobalsWithPriorLayerReferencesMap = null; // throw on late registrations + } +} 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 3a252a495609..a11d134779f3 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 @@ -31,6 +31,7 @@ import java.nio.ByteBuffer; import java.util.Comparator; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @@ -49,11 +50,18 @@ import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.graal.code.CGlobalDataInfo; import com.oracle.svm.core.graal.nodes.CGlobalDataLoadAddressNode; +import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; +import com.oracle.svm.core.traits.BuiltinTraits.BuildtimeAccessOnly; +import com.oracle.svm.core.traits.BuiltinTraits.NoLayeredCallbacks; +import com.oracle.svm.core.traits.SingletonLayeredInstallationKind.Independent; +import com.oracle.svm.core.traits.SingletonTraits; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.image.RelocatableBuffer; +import com.oracle.svm.hosted.imagelayer.CodeLocation; import com.oracle.svm.hosted.meta.HostedSnippetReflectionProvider; import com.oracle.svm.util.ReflectionUtil; +import jdk.graal.compiler.core.common.NumUtil; import jdk.graal.compiler.core.common.memory.BarrierType; import jdk.graal.compiler.core.common.memory.MemoryOrderMode; import jdk.graal.compiler.core.common.type.IntegerStamp; @@ -91,6 +99,7 @@ import jdk.vm.ci.meta.ResolvedJavaType; @AutomaticallyRegisteredFeature +@SingletonTraits(access = BuildtimeAccessOnly.class, layeredCallbacks = NoLayeredCallbacks.class, layeredInstallationKind = Independent.class) public class CGlobalDataFeature implements InternalFeature { private final Method getCGlobalDataInfoMethod = ReflectionUtil.lookupMethod(CGlobalDataNonConstantRegistry.class, "getCGlobalDataInfo", CGlobalDataImpl.class); @@ -103,6 +112,13 @@ public class CGlobalDataFeature implements InternalFeature { private final Map, CGlobalDataInfo> map = new ConcurrentHashMap<>(); private int totalSize = -1; + private final Set seenCodeLocations = ImageLayerBuildingSupport.buildingImageLayer() ? ConcurrentHashMap.newKeySet() : null; + + @SuppressWarnings("this-escape") // + private final InitialLayerCGlobalTracking initialLayerCGlobalTracking = ImageLayerBuildingSupport.buildingInitialLayer() ? new InitialLayerCGlobalTracking(this) : null; + @SuppressWarnings("this-escape") // + private final AppLayerCGlobalTracking appLayerCGlobalTracking = ImageLayerBuildingSupport.buildingApplicationLayer() ? new AppLayerCGlobalTracking(this) : null; + public static CGlobalDataFeature singleton() { return ImageSingletons.lookup(CGlobalDataFeature.class); } @@ -208,17 +224,57 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec }); } + CGlobalDataInfo getDataInfo(CGlobalDataImpl data) { + return map.get(data); + } + public CGlobalDataInfo registerAsAccessedOrGet(CGlobalData obj) { + return registerAsAccessedOrGet(obj, true); + } + + /** + * {@link #registerAsAccessedOrGet(CGlobalData)} should normally be used instead of this method. + */ + CGlobalDataInfo registerAsAccessedOrGet(CGlobalData obj, boolean tryCanonicalization) { CGlobalDataImpl data = (CGlobalDataImpl) obj; - VMError.guarantee(!isLaidOut() || map.containsKey(data), "CGlobalData instance must have been discovered/registered before or during analysis"); - return map.computeIfAbsent((CGlobalDataImpl) obj, - o -> { - CGlobalDataInfo cGlobalDataInfo = new CGlobalDataInfo(data); - if (data.nonConstant) { - nonConstantRegistry.registerNonConstantSymbol(cGlobalDataInfo); - } - return cGlobalDataInfo; - }); + if (tryCanonicalization && appLayerCGlobalTracking != null) { + data = appLayerCGlobalTracking.getCanonicalRepresentation(data); + } + + if (isLaidOut()) { + var info = map.get(data); + VMError.guarantee(info != null, "CGlobalData instance must have been discovered/registered before or during analysis"); + return info; + } else { + return map.computeIfAbsent(data, key -> { + if (appLayerCGlobalTracking != null) { + var result = appLayerCGlobalTracking.createCGlobalDataInfo(key); + if (result != null) { + return result; + } + } + var result = createCGlobalDataInfo(key, false); + if (initialLayerCGlobalTracking != null) { + initialLayerCGlobalTracking.registerCGlobal(key); + } + return result; + }); + } + } + + CGlobalDataInfo createCGlobalDataInfo(CGlobalDataImpl data, boolean definedAsGlobalInPriorLayer) { + if (data.codeLocation != null && seenCodeLocations != null) { + boolean added = seenCodeLocations.add(CodeLocation.fromStackFrame(data.codeLocation)); + VMError.guarantee(added, "Multiple elements seen at same code location: %s", data.codeLocation); + VMError.guarantee(!data.codeLocation.getDeclaringClass().isHidden(), + "We currently do not allow CGlobalData code locations to be in a hidden class. Please adapt the code accordingly. Location: %s", + data.codeLocation); + } + CGlobalDataInfo cGlobalDataInfo = new CGlobalDataInfo(data, definedAsGlobalInPriorLayer); + if (data.nonConstant) { + nonConstantRegistry.registerNonConstantSymbol(cGlobalDataInfo); + } + return cGlobalDataInfo; } /** @@ -252,10 +308,15 @@ public Set getGlobalHiddenSymbols() { } private Object replaceObject(Object obj) { - if (obj instanceof CGlobalDataImpl) { - registerAsAccessedOrGet((CGlobalData) obj); + if (obj instanceof CGlobalDataImpl cglobal) { + if (appLayerCGlobalTracking != null) { + cglobal = appLayerCGlobalTracking.getCanonicalRepresentation(cglobal); + } + registerAsAccessedOrGet(cglobal, false); + return cglobal; + } else { + return obj; } - return obj; } private static CGlobalDataInfo assignCGlobalDataSize(Map.Entry, CGlobalDataInfo> entry, int wordSize) { @@ -294,10 +355,8 @@ private void layout() { .sorted(Comparator.comparing(CGlobalDataInfo::getSize)) .reduce(0, (currentOffset, info) -> { info.assignOffset(currentOffset); - int nextOffset = currentOffset + info.getSize(); - int alignmentMask = -wordSize; - return (nextOffset + (wordSize - 1)) & alignmentMask; + return NumUtil.roundUp(nextOffset, wordSize); // align }, Integer::sum); assert isLaidOut(); } @@ -330,5 +389,19 @@ public void writeData(RelocatableBuffer buffer, SymbolConsumer createSymbol, Sym createSymbolReference.apply(info.getOffset(), data.symbolName, info.isGlobalSymbol()); } } + if (initialLayerCGlobalTracking != null) { + initialLayerCGlobalTracking.writeData(createSymbol, map); + } + if (appLayerCGlobalTracking != null) { + appLayerCGlobalTracking.validateCGlobals(map); + } + } + + public InitialLayerCGlobalTracking getInitialLayerCGlobalTracking() { + return Objects.requireNonNull(initialLayerCGlobalTracking); + } + + public AppLayerCGlobalTracking getAppLayerCGlobalTracking() { + return Objects.requireNonNull(appLayerCGlobalTracking); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/InitialLayerCGlobalTracking.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/InitialLayerCGlobalTracking.java new file mode 100644 index 000000000000..ee392a44ddef --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/InitialLayerCGlobalTracking.java @@ -0,0 +1,140 @@ +/* + * 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.hosted.c; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; + +import com.oracle.svm.core.c.CGlobalDataImpl; +import com.oracle.svm.core.graal.code.CGlobalDataInfo; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.imagelayer.CodeLocation; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder; + +/** + * Tracks CGlobals installed in the initial layer. This information is used to ensure CGlobals refer + * to a consistent location regardless of which layer the code was compiled in. + */ +public class InitialLayerCGlobalTracking { + + private static final String LAYERED_CGLOBAL_SYMBOL_PREFIX = "__svm_layered_cglobal"; + + private final Map, Integer> toPersistEncodedDataIdx = new ConcurrentHashMap<>(); + private final AtomicInteger nextIdx = new AtomicInteger(0); + + private Map toPersistLayeredSymbolNameMap; + + private final CGlobalDataFeature cGlobalDataFeature; + + InitialLayerCGlobalTracking(CGlobalDataFeature cGlobalDataFeature) { + this.cGlobalDataFeature = cGlobalDataFeature; + } + + public void registerCGlobal(CGlobalDataImpl data) { + toPersistEncodedDataIdx.computeIfAbsent(data, key -> nextIdx.getAndIncrement()); + } + + public int getEncodedIndex(CGlobalDataImpl data) { + return toPersistEncodedDataIdx.get(data); + } + + public CGlobalDataInfo[] getInfosOrderedByIndex() { + return toPersistEncodedDataIdx.entrySet().stream() + .sorted(Map.Entry.comparingByValue()) + .map(e -> { + var result = cGlobalDataFeature.getDataInfo(e.getKey()); + return Objects.requireNonNull(result); + }) + .toArray(CGlobalDataInfo[]::new); + } + + public void persistCGlobalInfo(CGlobalDataInfo info, Supplier builderSupplier) { + String layeredSymbolName = toPersistLayeredSymbolNameMap.get(info); + assert layeredSymbolName != null; + var builder = builderSupplier.get(); + builder.setLayeredSymbolName(layeredSymbolName); + CGlobalDataImpl data = info.getData(); + if (data.symbolName != null) { + builder.initLinkingInfo().setOriginalSymbolName(data.symbolName); + } else { + /* + * Note in layered image builds the uniqueness of creation sites is checked in + * CGlobalDataFeature#createCGlobalDataInfo. + */ + var location = builder.initLinkingInfo().initCodeLocation(); + CodeLocation codeLocation = CodeLocation.fromStackFrame(info.getData().codeLocation); + location.setBytecodeIndex(codeLocation.bci()); + location.setStacktraceName(codeLocation.name()); + } + builder.setNonConstant(data.nonConstant); + builder.setIsGlobalSymbol(info.isGlobalSymbol()); + builder.setIsSymbolReference(info.isSymbolReference()); + } + + void writeData(CGlobalDataFeature.SymbolConsumer createSymbol, + Map, CGlobalDataInfo> fullMap) { + VMError.guarantee(fullMap.size() == toPersistEncodedDataIdx.size()); + + toPersistLayeredSymbolNameMap = new HashMap<>(); + int symbolCount = 0; + for (CGlobalDataInfo info : fullMap.values()) { + assert toPersistEncodedDataIdx.containsKey(info.getData()) : info; + + String layeredSymbolName; + if (info.isSymbolReference()) { + /* + * Symbol references only refer to the actual data, so these can be freely recreated + * across layers. + */ + layeredSymbolName = Objects.requireNonNull(info.getData().symbolName); + } else { + /* + * CGlobals linked to a chunk of global data must be referred to by symbol + * references within other layers. If a CGlobal already has a global symbol, then we + * can simply refer to this global name. Otherwise, we must associate an internal + * global symbol with this CGlobal so that we can refer to it in subsequent layers. + * + * Note hidden global symbols also need a new symbol to be created. This is because + * hidden global symbols are not exported from the shared layer images (which are + * shared libraries) and hence are not visible for dynamic linking. + */ + if (info.isGlobalSymbol() && !info.isHiddenSymbol()) { + layeredSymbolName = info.getData().symbolName; + } else { + // create symbol name + layeredSymbolName = String.format("%s_%s", LAYERED_CGLOBAL_SYMBOL_PREFIX, symbolCount); + symbolCount++; + createSymbol.apply(info.getOffset(), layeredSymbolName, true); + } + } + var prev = toPersistLayeredSymbolNameMap.put(info, layeredSymbolName); + VMError.guarantee(prev == null); + } + } +} 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 4eda442b68c8..af246b4770a5 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 @@ -404,19 +404,15 @@ private boolean shouldWriteHeader(HostedMethod method) { return data instanceof CEntryPointData && ((CEntryPointData) data).getPublishAs() == Publish.SymbolAndHeader; } - private ObjectFile.Symbol defineDataSymbol(String name, Element section, long position) { - return objectFile.createDefinedSymbol(name, section, position, wordSize, false, SubstrateOptions.InternalSymbolsAreGlobal.getValue()); + private void defineDataSymbol(String name, Element section, long position) { + objectFile.createDefinedSymbol(name, section, position, wordSize, false, SubstrateOptions.InternalSymbolsAreGlobal.getValue()); } - private ObjectFile.Symbol defineRelocationForSymbol(String name, long position) { - ObjectFile.Symbol symbol = null; - if (objectFile.getSymbolTable().getSymbol(name) == null) { - symbol = objectFile.createUndefinedSymbol(name, 0, true); - } + private void defineRelocationForSymbol(String name, long position) { + objectFile.createUndefinedSymbol(name, true); ProgbitsSectionImpl baseSectionImpl = (ProgbitsSectionImpl) rwDataSection.getImpl(); int offsetInSection = Math.toIntExact(RWDATA_CGLOBALS_PARTITION_OFFSET + position); baseSectionImpl.markRelocationSite(offsetInSection, wordSize == 8 ? RelocationKind.DIRECT_8 : RelocationKind.DIRECT_4, name, 0L); - return symbol; } public static String getTextSectionStartSymbol() { @@ -741,7 +737,7 @@ private void markDataRelocationSiteFromText(RelocatableBuffer buffer, final Prog sectionImpl.markRelocationSite(offset, info.getRelocationKind(), rwDataSection.getName(), addend); if (dataInfo.isSymbolReference()) { // create relocation for referenced symbol if (objectFile.getSymbolTable().getSymbol(data.symbolName) == null) { - objectFile.createUndefinedSymbol(data.symbolName, 0, true); + objectFile.createUndefinedSymbol(data.symbolName, true); } ProgbitsSectionImpl baseSectionImpl = (ProgbitsSectionImpl) rwDataSection.getImpl(); int offsetInSection = Math.toIntExact(RWDATA_CGLOBALS_PARTITION_OFFSET + dataInfo.getOffset()); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/CodeLocation.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/CodeLocation.java new file mode 100644 index 000000000000..434161aa0032 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/CodeLocation.java @@ -0,0 +1,35 @@ +/* + * 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.hosted.imagelayer; + +/** + * Stores information used to match a given code location across layers. + */ +public record CodeLocation(int bci, String name) { + + public static CodeLocation fromStackFrame(StackWalker.StackFrame stackFrame) { + return new CodeLocation(stackFrame.getByteCodeIndex(), stackFrame.toString()); + } +} 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 index 3230729d69e2..42601b1b1cc1 100644 --- 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 @@ -149,7 +149,7 @@ public void defineSymbolsForPriorLayerMethods(ObjectFile objectFile) { * CFunctionPointer/MethodPointer, we still use symbols. Therefore, not all these symbol * entries are needed, but the command-line linker should remove any unnecessary ones. */ - priorLayerMethodSymbols.forEach(symbol -> objectFile.createUndefinedSymbol(symbol, 0, true)); + priorLayerMethodSymbols.forEach(symbol -> objectFile.createUndefinedSymbol(symbol, true)); } public void registerLibName(String lib) { 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 120c36d66f40..f69b7824e224 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 @@ -59,6 +59,7 @@ import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags; import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton; import com.oracle.svm.hosted.FeatureImpl; +import com.oracle.svm.hosted.c.AppLayerCGlobalTracking; import com.oracle.svm.hosted.c.CGlobalDataFeature; import com.oracle.svm.hosted.image.NativeImage; @@ -98,6 +99,7 @@ public final class ImageLayerSectionFeature implements InternalFeature, FeatureSingleton, UnsavedSingleton { private static final SectionName SVM_LAYER_SECTION = new SectionName.ProgbitsSectionName("svm_layer"); + private static final String LAYER_NAME_PREFIX = "__svm_vm_layer"; private static final int HEAP_BEGIN_OFFSET = 0; private static final int HEAP_END_OFFSET = 8; @@ -127,30 +129,13 @@ public boolean isInConfiguration(IsInConfigurationAccess access) { @Override public List> getRequiredFeatures() { - return List.of(HostedDynamicLayerInfoFeature.class, LoadImageSingletonFeature.class, CrossLayerConstantRegistryFeature.class); + return List.of(HostedDynamicLayerInfoFeature.class, LoadImageSingletonFeature.class, CrossLayerConstantRegistryFeature.class, CGlobalDataFeature.class); } @Override public void afterRegistration(AfterRegistrationAccess access) { - ImageSingletons.add(ImageLayerSection.class, createImageLayerSection()); - } - - private static byte[] createWords(int count, WordBase initialValue) { - Architecture arch = ConfigurationValues.getTarget().arch; - assert arch.getWordSize() == Long.BYTES : "currently hard-coded for 8 byte words"; - ByteBuffer buffer = ByteBuffer.allocate(count * Long.BYTES).order(arch.getByteOrder()); - for (int i = 0; i < count; i++) { - buffer.putLong(initialValue.rawValue()); - } - return buffer.array(); - } - - private static String getLayerName(int layerNumber) { - return String.format("__svm_layer_%s", layerNumber); - } - - private static ImageLayerSectionImpl createImageLayerSection() { CGlobalData initialSectionStart = ImageLayerBuildingSupport.buildingInitialLayer() ? CGlobalDataFactory.forSymbol(getLayerName(DynamicImageLayerInfo.getCurrentLayerNumber())) : null; + CGlobalData cachedImageFDs; CGlobalData cachedImageHeapOffsets; CGlobalData cachedImageHeapRelocations; @@ -163,13 +148,31 @@ private static ImageLayerSectionImpl createImageLayerSection() { cachedImageFDs = CGlobalDataFactory.createBytes(() -> createWords(DynamicImageLayerInfo.singleton().numLayers, UNASSIGNED_FD), CACHED_IMAGE_FDS_NAME); cachedImageHeapOffsets = CGlobalDataFactory.createBytes(() -> createWords(DynamicImageLayerInfo.singleton().numLayers, Word.zero()), CACHED_IMAGE_HEAP_OFFSETS_NAME); cachedImageHeapRelocations = CGlobalDataFactory.createBytes(() -> createWords(DynamicImageLayerInfo.singleton().numLayers, Word.zero()), CACHED_IMAGE_HEAP_RELOCATIONS_NAME); + AppLayerCGlobalTracking appLayerTracking = CGlobalDataFeature.singleton().getAppLayerCGlobalTracking(); + appLayerTracking.registerCGlobalWithPriorLayerReference(cachedImageFDs); + appLayerTracking.registerCGlobalWithPriorLayerReference(cachedImageHeapOffsets); + appLayerTracking.registerCGlobalWithPriorLayerReference(cachedImageHeapRelocations); } else { cachedImageFDs = null; cachedImageHeapOffsets = null; cachedImageHeapRelocations = null; } - return new ImageLayerSectionImpl(initialSectionStart, cachedImageFDs, cachedImageHeapOffsets, cachedImageHeapRelocations); + ImageSingletons.add(ImageLayerSection.class, new ImageLayerSectionImpl(initialSectionStart, cachedImageFDs, cachedImageHeapOffsets, cachedImageHeapRelocations)); + } + + private static byte[] createWords(int count, WordBase initialValue) { + Architecture arch = ConfigurationValues.getTarget().arch; + assert arch.getWordSize() == Long.BYTES : "currently hard-coded for 8 byte words"; + ByteBuffer buffer = ByteBuffer.allocate(count * Long.BYTES).order(arch.getByteOrder()); + for (int i = 0; i < count; i++) { + buffer.putLong(initialValue.rawValue()); + } + return buffer.array(); + } + + private static String getLayerName(int layerNumber) { + return String.format("%s_%s", LAYER_NAME_PREFIX, layerNumber); } @Override @@ -221,7 +224,7 @@ public void createSection(ObjectFile objectFile, ImageHeapLayoutInfo heapLayout) if (ImageLayerBuildingSupport.buildingSharedLayer()) { String nextLayerSymbolName = getLayerName(DynamicImageLayerInfo.singleton().nextLayerNumber); // this symbol will be defined in the next layer's layer section - objectFile.createUndefinedSymbol(nextLayerSymbolName, 0, false); + objectFile.createUndefinedSymbol(nextLayerSymbolName, false); layeredSectionData.markRelocationSite(NEXT_SECTION_OFFSET, ObjectFile.RelocationKind.DIRECT_8, nextLayerSymbolName, 0); } else { /* diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredDispatchTableFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredDispatchTableFeature.java index 31db8314d770..e7ca91083d80 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredDispatchTableFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredDispatchTableFeature.java @@ -551,7 +551,7 @@ public void defineDispatchTableSlotSymbols(ObjectFile objectFile, ObjectFile.Sec */ symbol = computeUnresolvedMethodSymbol(slotInfo, deduplicatedMethodMap, symbolNameSupplier); if (unresolvedVTableSymbolNames.add(symbol)) { - objectFile.createUndefinedSymbol(symbol, wordSize, true); + objectFile.createUndefinedSymbol(symbol, true); } } } else { 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 c9db1f9ca390..53834da5e175 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 @@ -84,7 +84,6 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.classinitialization.ClassInitializationInfo; -import com.oracle.svm.core.graal.code.CGlobalDataInfo; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; import com.oracle.svm.core.meta.MethodOffset; @@ -94,7 +93,6 @@ import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.SVMHost; -import com.oracle.svm.hosted.c.CGlobalDataFeature; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.code.CEntryPointCallStubSupport; import com.oracle.svm.hosted.code.CEntryPointData; @@ -1025,6 +1023,10 @@ public StructList.Reader getCGlobals() { + return snapshot.getCGlobals(); + } + public DynamicHubInfo.Reader getDynamicHubInfo(AnalysisType aType) { DynamicHubInfo.Reader result = CapnProtoAdapters.binarySearchUnique(getBaseLayerTypeId(aType), snapshot.getDynamicHubInfos(), DynamicHubInfo.Reader::getTypeId); assert result != null : aType; @@ -1089,10 +1091,7 @@ private EncodedGraph getEncodedGraph(AnalysisMethod analysisMethod, Text.Reader SVMImageLayerSnapshotUtil.AbstractSVMGraphDecoder decoder = imageLayerSnapshotUtil.getGraphDecoder(this, analysisMethod, universe.getSnippetReflection(), nodeClassMap); EncodedGraph encodedGraph = (EncodedGraph) ObjectCopier.decode(decoder, encodedAnalyzedGraph); for (int i = 0; i < encodedGraph.getNumObjects(); ++i) { - Object obj = encodedGraph.getObject(i); - if (obj instanceof CGlobalDataInfo cGlobalDataInfo) { - encodedGraph.setObject(i, CGlobalDataFeature.singleton().registerAsAccessedOrGet(cGlobalDataInfo.getData())); - } else if (buildingApplicationLayer && obj instanceof LoadImageSingletonDataImpl data) { + if (buildingApplicationLayer && encodedGraph.getObject(i) instanceof LoadImageSingletonDataImpl data) { data.setApplicationLayerConstant(); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerSnapshotUtil.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerSnapshotUtil.java index 0a2fdc7796be..a35b6ae03477 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerSnapshotUtil.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerSnapshotUtil.java @@ -58,7 +58,9 @@ import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; import com.oracle.graal.pointsto.meta.PointsToAnalysisType; import com.oracle.graal.pointsto.util.AnalysisError; +import com.oracle.svm.core.c.CGlobalDataImpl; import com.oracle.svm.core.c.struct.CInterfaceLocationIdentity; +import com.oracle.svm.core.graal.code.CGlobalDataInfo; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.hub.DynamicHubCompanion; import com.oracle.svm.core.option.HostedOptionValues; @@ -68,6 +70,9 @@ import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ImageClassLoader; import com.oracle.svm.hosted.VMFeature; +import com.oracle.svm.hosted.c.AppLayerCGlobalTracking; +import com.oracle.svm.hosted.c.CGlobalDataFeature; +import com.oracle.svm.hosted.c.InitialLayerCGlobalTracking; import com.oracle.svm.hosted.code.FactoryMethod; import com.oracle.svm.hosted.code.IncompatibleClassChangeFallbackMethod; import com.oracle.svm.hosted.meta.HostedArrayClass; @@ -350,6 +355,9 @@ public SVMGraphEncoder(Map externalValues, NodeClassMap nodeClass addBuiltin(new CInterfaceLocationIdentityBuiltIn()); addBuiltin(new FastThreadLocalLocationIdentityBuiltIn()); addBuiltin(new VMThreadLocalInfoBuiltIn()); + LayeredCGlobalTracking cGlobalTracking = new LayeredCGlobalTracking(CGlobalDataFeature.singleton().getInitialLayerCGlobalTracking(), null); + addBuiltin(new CGlobalDataImplBuiltIn(cGlobalTracking)); + addBuiltin(new CGlobalDataInfoBuiltIn(cGlobalTracking)); if (nodeClassMap != null) { addBuiltin(new NodeClassMapBuiltin(nodeClassMap)); } @@ -385,6 +393,9 @@ public AbstractSVMGraphDecoder(ClassLoader classLoader, SVMImageLayerLoader imag addBuiltin(new CInterfaceLocationIdentityBuiltIn()); addBuiltin(new FastThreadLocalLocationIdentityBuiltIn()); addBuiltin(new VMThreadLocalInfoBuiltIn()); + LayeredCGlobalTracking cGlobalTracking = new LayeredCGlobalTracking(null, CGlobalDataFeature.singleton().getAppLayerCGlobalTracking()); + addBuiltin(new CGlobalDataImplBuiltIn(cGlobalTracking)); + addBuiltin(new CGlobalDataInfoBuiltIn(cGlobalTracking)); if (nodeClassMap != null) { addBuiltin(new NodeClassMapBuiltin(nodeClassMap)); } @@ -766,6 +777,70 @@ protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, Obj } } + static final class LayeredCGlobalTracking { + private final InitialLayerCGlobalTracking initialLayerTracking; + private final AppLayerCGlobalTracking appLayerTracking; + + private LayeredCGlobalTracking(InitialLayerCGlobalTracking initialLayerTracking, AppLayerCGlobalTracking appLayerTracking) { + this.initialLayerTracking = initialLayerTracking; + this.appLayerTracking = appLayerTracking; + } + + int getEncodedIndex(CGlobalDataImpl data) { + return initialLayerTracking.getEncodedIndex(data); + } + + CGlobalDataImpl getCGlobalDataImpl(int index) { + return appLayerTracking.registerOrGetCGlobalDataImplByPersistedIndex(index); + } + + CGlobalDataInfo getCGlobalDataInfo(int index) { + return appLayerTracking.registerOrGetCGlobalDataInfoByPersistedIndex(index); + } + } + + private static class CGlobalDataImplBuiltIn extends ObjectCopier.Builtin { + private final LayeredCGlobalTracking cGlobalTracking; + + CGlobalDataImplBuiltIn(LayeredCGlobalTracking cGlobalTracking) { + super(CGlobalDataImpl.class); + this.cGlobalTracking = cGlobalTracking; + } + + @Override + protected void encode(ObjectCopier.Encoder encoder, ObjectCopierOutputStream stream, Object obj) throws IOException { + int id = cGlobalTracking.getEncodedIndex((CGlobalDataImpl) obj); + stream.writePackedUnsignedInt(id); + } + + @Override + protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, ObjectCopierInputStream stream) throws IOException { + int id = stream.readPackedUnsignedInt(); + return cGlobalTracking.getCGlobalDataImpl(id); + } + } + + private static class CGlobalDataInfoBuiltIn extends ObjectCopier.Builtin { + private final LayeredCGlobalTracking cGlobalTracking; + + CGlobalDataInfoBuiltIn(LayeredCGlobalTracking cGlobalTracking) { + super(CGlobalDataInfo.class); + this.cGlobalTracking = cGlobalTracking; + } + + @Override + protected void encode(ObjectCopier.Encoder encoder, ObjectCopierOutputStream stream, Object obj) throws IOException { + int id = cGlobalTracking.getEncodedIndex(((CGlobalDataInfo) obj).getData()); + stream.writePackedUnsignedInt(id); + } + + @Override + protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, ObjectCopierInputStream stream) throws IOException { + int id = stream.readPackedUnsignedInt(); + return cGlobalTracking.getCGlobalDataInfo(id); + } + } + private static void makeStaticFieldIds(ObjectCopier.Encoder encoder, ObjectCopier.ObjectPath objectPath, Object object) { Field staticField = encoder.getExternalValues().get(object); encoder.makeStringId(staticField.getDeclaringClass().getName(), objectPath); 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 0a281b3a35ef..ecdbc799d400 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 @@ -123,6 +123,8 @@ import com.oracle.svm.hosted.annotation.AnnotationMemberValue; import com.oracle.svm.hosted.annotation.AnnotationMetadata; import com.oracle.svm.hosted.annotation.CustomSubstitutionType; +import com.oracle.svm.hosted.c.CGlobalDataFeature; +import com.oracle.svm.hosted.c.InitialLayerCGlobalTracking; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.classinitialization.SimulateClassInitializerSupport; import com.oracle.svm.hosted.code.CEntryPointCallStubMethod; @@ -382,6 +384,9 @@ public void persistAnalysisInfo() { .toArray(AnalysisField[]::new); initSortedArray(snapshotBuilder::initFields, fieldsToPersist, this::persistField); + InitialLayerCGlobalTracking initialLayerCGlobalTracking = CGlobalDataFeature.singleton().getInitialLayerCGlobalTracking(); + initSortedArray(snapshotBuilder::initCGlobals, initialLayerCGlobalTracking.getInfosOrderedByIndex(), initialLayerCGlobalTracking::persistCGlobalInfo); + /* * Note the set of elements within the hosted method array are created as a side effect of * persisting methods and dynamic hubs, so it must persisted after these operations. 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 d17eb481a718..fb603fa3b55a 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 @@ -4803,7 +4803,7 @@ public final com.oracle.svm.shaded.org.capnproto.StructList.Reader { public Factory() { } @@ -5060,6 +5060,18 @@ public final void setLayeredModule(com.oracle.svm.hosted.imagelayer.SharedLayerS public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.LayeredModule.Builder initLayeredModule() { return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.LayeredModule.factory,14, 0); } + public final boolean hasCGlobals() { + return !_pointerFieldIsNull(15); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Builder getCGlobals() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CGlobalDataInfo.listFactory, 15, null, 0); + } + public final void setCGlobals(com.oracle.svm.shaded.org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CGlobalDataInfo.listFactory, 15, value); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Builder initCGlobals(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CGlobalDataInfo.listFactory, 15, size); + } } public static final class Reader extends com.oracle.svm.shaded.org.capnproto.StructReader { @@ -5204,6 +5216,13 @@ public com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.LayeredModule.factory,14,null, 0); } + public final boolean hasCGlobals() { + return !_pointerFieldIsNull(15); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Reader getCGlobals() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CGlobalDataInfo.listFactory, 15, null, 0); + } + } } @@ -6055,6 +6074,307 @@ public enum Which { } + public static class CGlobalDataInfo { + public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)1,(short)2); + public static final class Factory extends com.oracle.svm.shaded.org.capnproto.StructFactory { + public Factory() { + } + public final Reader constructReader(com.oracle.svm.shaded.org.capnproto.SegmentReader segment, int data,int pointers, int dataSize, short pointerCount, int nestingLimit) { + return new Reader(segment,data,pointers,dataSize,pointerCount,nestingLimit); + } + public final Builder constructBuilder(com.oracle.svm.shaded.org.capnproto.SegmentBuilder segment, int data,int pointers, int dataSize, short pointerCount) { + return new Builder(segment, data, pointers, dataSize, pointerCount); + } + public final com.oracle.svm.shaded.org.capnproto.StructSize structSize() { + return CGlobalDataInfo.STRUCT_SIZE; + } + public final Reader asReader(Builder builder) { + return builder.asReader(); + } + } + public static final Factory factory = new Factory(); + public static final com.oracle.svm.shaded.org.capnproto.StructList.Factory listFactory = + new com.oracle.svm.shaded.org.capnproto.StructList.Factory(factory); + public static final class Builder extends com.oracle.svm.shaded.org.capnproto.StructBuilder { + Builder(com.oracle.svm.shaded.org.capnproto.SegmentBuilder segment, int data, int pointers,int dataSize, short pointerCount){ + super(segment, data, pointers, dataSize, pointerCount); + } + public final Reader asReader() { + return new Reader(segment, data, pointers, dataSize, pointerCount, 0x7fffffff); + } + public final boolean getIsSymbolReference() { + return _getBooleanField(0); + } + public final void setIsSymbolReference(boolean value) { + _setBooleanField(0, value); + } + + public final boolean getIsGlobalSymbol() { + return _getBooleanField(1); + } + public final void setIsGlobalSymbol(boolean value) { + _setBooleanField(1, value); + } + + public final boolean getNonConstant() { + return _getBooleanField(2); + } + public final void setNonConstant(boolean value) { + _setBooleanField(2, value); + } + + public final boolean hasLayeredSymbolName() { + return !_pointerFieldIsNull(0); + } + public final com.oracle.svm.shaded.org.capnproto.Text.Builder getLayeredSymbolName() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, null, 0, 0); + } + public final void setLayeredSymbolName(com.oracle.svm.shaded.org.capnproto.Text.Reader value) { + _setPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, value); + } + public final void setLayeredSymbolName(String value) { + _setPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, new com.oracle.svm.shaded.org.capnproto.Text.Reader(value)); + } + public final com.oracle.svm.shaded.org.capnproto.Text.Builder initLayeredSymbolName(int size) { + return _initPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, size); + } + public final LinkingInfo.Builder getLinkingInfo() { + return new CGlobalDataInfo.LinkingInfo.Builder(segment, data, pointers, dataSize, pointerCount); + } + public final LinkingInfo.Builder initLinkingInfo() { + _setShortField(1,(short)0); + _clearPointerField(1); + return new CGlobalDataInfo.LinkingInfo.Builder(segment, data, pointers, dataSize, pointerCount); + } + + } + + public static final class Reader extends com.oracle.svm.shaded.org.capnproto.StructReader { + Reader(com.oracle.svm.shaded.org.capnproto.SegmentReader segment, int data, int pointers,int dataSize, short pointerCount, int nestingLimit){ + super(segment, data, pointers, dataSize, pointerCount, nestingLimit); + } + + public final boolean getIsSymbolReference() { + return _getBooleanField(0); + } + + public final boolean getIsGlobalSymbol() { + return _getBooleanField(1); + } + + public final boolean getNonConstant() { + return _getBooleanField(2); + } + + public boolean hasLayeredSymbolName() { + return !_pointerFieldIsNull(0); + } + public com.oracle.svm.shaded.org.capnproto.Text.Reader getLayeredSymbolName() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, null, 0, 0); + } + + public LinkingInfo.Reader getLinkingInfo() { + return new CGlobalDataInfo.LinkingInfo.Reader(segment, data, pointers, dataSize, pointerCount, nestingLimit); + } + + } + + public static class LinkingInfo { + public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)1,(short)2); + public static final class Factory extends com.oracle.svm.shaded.org.capnproto.StructFactory { + public Factory() { + } + public final Reader constructReader(com.oracle.svm.shaded.org.capnproto.SegmentReader segment, int data,int pointers, int dataSize, short pointerCount, int nestingLimit) { + return new Reader(segment,data,pointers,dataSize,pointerCount,nestingLimit); + } + public final Builder constructBuilder(com.oracle.svm.shaded.org.capnproto.SegmentBuilder segment, int data,int pointers, int dataSize, short pointerCount) { + return new Builder(segment, data, pointers, dataSize, pointerCount); + } + public final com.oracle.svm.shaded.org.capnproto.StructSize structSize() { + return CGlobalDataInfo.LinkingInfo.STRUCT_SIZE; + } + public final Reader asReader(Builder builder) { + return builder.asReader(); + } + } + public static final Factory factory = new Factory(); + public static final com.oracle.svm.shaded.org.capnproto.StructList.Factory listFactory = + new com.oracle.svm.shaded.org.capnproto.StructList.Factory(factory); + public static final class Builder extends com.oracle.svm.shaded.org.capnproto.StructBuilder { + Builder(com.oracle.svm.shaded.org.capnproto.SegmentBuilder segment, int data, int pointers,int dataSize, short pointerCount){ + super(segment, data, pointers, dataSize, pointerCount); + } + public Which which() { + switch(_getShortField(1)) { + case 0 : return Which.ORIGINAL_SYMBOL_NAME; + case 1 : return Which.CODE_LOCATION; + default: return Which._NOT_IN_SCHEMA; + } + } + public final Reader asReader() { + return new Reader(segment, data, pointers, dataSize, pointerCount, 0x7fffffff); + } + public final boolean isOriginalSymbolName() { + return which() == CGlobalDataInfo.LinkingInfo.Which.ORIGINAL_SYMBOL_NAME; + } + public final boolean hasOriginalSymbolName() { + if (which() != CGlobalDataInfo.LinkingInfo.Which.ORIGINAL_SYMBOL_NAME) return false; + return !_pointerFieldIsNull(1); + } + public final com.oracle.svm.shaded.org.capnproto.Text.Builder getOriginalSymbolName() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 1, null, 0, 0); + } + public final void setOriginalSymbolName(com.oracle.svm.shaded.org.capnproto.Text.Reader value) { + _setShortField(1, (short)CGlobalDataInfo.LinkingInfo.Which.ORIGINAL_SYMBOL_NAME.ordinal()); + _setPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 1, value); + } + public final void setOriginalSymbolName(String value) { + _setShortField(1, (short)CGlobalDataInfo.LinkingInfo.Which.ORIGINAL_SYMBOL_NAME.ordinal()); + _setPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 1, new com.oracle.svm.shaded.org.capnproto.Text.Reader(value)); + } + public final com.oracle.svm.shaded.org.capnproto.Text.Builder initOriginalSymbolName(int size) { + _setShortField(1, (short)CGlobalDataInfo.LinkingInfo.Which.ORIGINAL_SYMBOL_NAME.ordinal()); + return _initPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 1, size); + } + public final boolean isCodeLocation() { + return which() == CGlobalDataInfo.LinkingInfo.Which.CODE_LOCATION; + } + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CodeLocation.Builder getCodeLocation() { + assert which() == CGlobalDataInfo.LinkingInfo.Which.CODE_LOCATION: + "Must check which() before get()ing a union member."; + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CodeLocation.factory, 1, null, 0); + } + public final void setCodeLocation(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CodeLocation.Reader value) { + _setShortField(1, (short)CGlobalDataInfo.LinkingInfo.Which.CODE_LOCATION.ordinal()); + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CodeLocation.factory,1, value); + } + public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CodeLocation.Builder initCodeLocation() { + _setShortField(1, (short)CGlobalDataInfo.LinkingInfo.Which.CODE_LOCATION.ordinal()); + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CodeLocation.factory,1, 0); + } + } + + public static final class Reader extends com.oracle.svm.shaded.org.capnproto.StructReader { + Reader(com.oracle.svm.shaded.org.capnproto.SegmentReader segment, int data, int pointers,int dataSize, short pointerCount, int nestingLimit){ + super(segment, data, pointers, dataSize, pointerCount, nestingLimit); + } + + public Which which() { + switch(_getShortField(1)) { + case 0 : return Which.ORIGINAL_SYMBOL_NAME; + case 1 : return Which.CODE_LOCATION; + default: return Which._NOT_IN_SCHEMA; + } + } + public final boolean isOriginalSymbolName() { + return which() == CGlobalDataInfo.LinkingInfo.Which.ORIGINAL_SYMBOL_NAME; + } + public boolean hasOriginalSymbolName() { + if (which() != CGlobalDataInfo.LinkingInfo.Which.ORIGINAL_SYMBOL_NAME) return false; + return !_pointerFieldIsNull(1); + } + public com.oracle.svm.shaded.org.capnproto.Text.Reader getOriginalSymbolName() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 1, null, 0, 0); + } + + public final boolean isCodeLocation() { + return which() == CGlobalDataInfo.LinkingInfo.Which.CODE_LOCATION; + } + public boolean hasCodeLocation() { + return !_pointerFieldIsNull(1); + } + public com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CodeLocation.Reader getCodeLocation() { + assert which() == CGlobalDataInfo.LinkingInfo.Which.CODE_LOCATION: + "Must check which() before get()ing a union member."; + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CodeLocation.factory,1,null, 0); + } + + } + + public enum Which { + ORIGINAL_SYMBOL_NAME, + CODE_LOCATION, + _NOT_IN_SCHEMA, + } + } + + + } + + + public static class CodeLocation { + public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)1,(short)1); + public static final class Factory extends com.oracle.svm.shaded.org.capnproto.StructFactory { + public Factory() { + } + public final Reader constructReader(com.oracle.svm.shaded.org.capnproto.SegmentReader segment, int data,int pointers, int dataSize, short pointerCount, int nestingLimit) { + return new Reader(segment,data,pointers,dataSize,pointerCount,nestingLimit); + } + public final Builder constructBuilder(com.oracle.svm.shaded.org.capnproto.SegmentBuilder segment, int data,int pointers, int dataSize, short pointerCount) { + return new Builder(segment, data, pointers, dataSize, pointerCount); + } + public final com.oracle.svm.shaded.org.capnproto.StructSize structSize() { + return CodeLocation.STRUCT_SIZE; + } + public final Reader asReader(Builder builder) { + return builder.asReader(); + } + } + public static final Factory factory = new Factory(); + public static final com.oracle.svm.shaded.org.capnproto.StructList.Factory listFactory = + new com.oracle.svm.shaded.org.capnproto.StructList.Factory(factory); + public static final class Builder extends com.oracle.svm.shaded.org.capnproto.StructBuilder { + Builder(com.oracle.svm.shaded.org.capnproto.SegmentBuilder segment, int data, int pointers,int dataSize, short pointerCount){ + super(segment, data, pointers, dataSize, pointerCount); + } + public final Reader asReader() { + return new Reader(segment, data, pointers, dataSize, pointerCount, 0x7fffffff); + } + public final int getBytecodeIndex() { + return _getIntField(0); + } + public final void setBytecodeIndex(int value) { + _setIntField(0, value); + } + + public final boolean hasStacktraceName() { + return !_pointerFieldIsNull(0); + } + public final com.oracle.svm.shaded.org.capnproto.Text.Builder getStacktraceName() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, null, 0, 0); + } + public final void setStacktraceName(com.oracle.svm.shaded.org.capnproto.Text.Reader value) { + _setPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, value); + } + public final void setStacktraceName(String value) { + _setPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, new com.oracle.svm.shaded.org.capnproto.Text.Reader(value)); + } + public final com.oracle.svm.shaded.org.capnproto.Text.Builder initStacktraceName(int size) { + return _initPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, size); + } + } + + public static final class Reader extends com.oracle.svm.shaded.org.capnproto.StructReader { + Reader(com.oracle.svm.shaded.org.capnproto.SegmentReader segment, int data, int pointers,int dataSize, short pointerCount, int nestingLimit){ + super(segment, data, pointers, dataSize, pointerCount, nestingLimit); + } + + public final int getBytecodeIndex() { + return _getIntField(0); + } + + public boolean hasStacktraceName() { + return !_pointerFieldIsNull(0); + } + public com.oracle.svm.shaded.org.capnproto.Text.Reader getStacktraceName() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, null, 0, 0); + } + + } + + } + + public static class DispatchSlotInfo { public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)2,(short)1); public static final class Factory extends com.oracle.svm.shaded.org.capnproto.StructFactory {