diff --git a/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp b/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp index 36c7352dd3b2..de5e607d35f7 100644 --- a/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp +++ b/substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp @@ -8,6 +8,7 @@ using MethodId = Int32; using FieldId = Int32; using ConstantId = Int32; using SingletonObjId = Int32; +using HostedMethodIndex = Int32; struct PersistedAnalysisType { id @0 :TypeId; @@ -75,8 +76,8 @@ struct PersistedAnalysisMethod { argumentTypeIds @6 :List(TypeId); returnTypeId @7 :TypeId; modifiers @8 :Int32; - code @9 :Data; - codeSize @10 :Int32; + bytecode @9 :Data; + bytecodeSize @10 :Int32; isConstructor @11 :Bool; isSynthetic @12 :Bool; canBeStaticallyBound @13 :Bool; @@ -92,32 +93,33 @@ struct PersistedAnalysisMethod { analysisGraphLocation @23 :Text; analysisGraphIsIntrinsic @24 :Bool; strengthenedGraphLocation @25 :Text; + hostedMethodIndex @26 :HostedMethodIndex; wrappedMethod :union { - none @26 :Void; # default + none @27 :Void; # default factoryMethod :group { - targetConstructorId @27 :MethodId; - throwAllocatedObject @28 :Bool; - instantiatedTypeId @29 :TypeId; + targetConstructorId @28 :MethodId; + throwAllocatedObject @29 :Bool; + instantiatedTypeId @30 :TypeId; } outlinedSB :group { - methodTypeReturn @30 :Text; - methodTypeParameters @31 :List(Text); + methodTypeReturn @31 :Text; + methodTypeParameters @32 :List(Text); } cEntryPointCallStub :group { - originalMethodId @32 :MethodId; - notPublished @33 :Bool; + originalMethodId @33 :MethodId; + notPublished @34 :Bool; } wrappedMember :group { union { - reflectionExpandSignature @34 :Void; - javaCallVariantWrapper @35 :Void; + reflectionExpandSignature @35 :Void; + javaCallVariantWrapper @36 :Void; } - name @36 :Text; - declaringClassName @37 :Text; - argumentTypeNames @38 :List(Text); + name @37 :Text; + declaringClassName @38 :Text; + argumentTypeNames @39 :List(Text); } polymorphicSignature :group { - callers @39 :List(MethodId); + callers @40 :List(MethodId); } } } @@ -273,6 +275,8 @@ struct SharedLayerSnapshot { staticFinalFieldFoldingSingleton @15 :StaticFinalFieldFoldingSingleton; registeredJNILibraries @16 :List(Text); layeredRuntimeMetadataSingleton @17 :LayeredRuntimeMetadataSingleton; + dynamicHubInfos @18 :List(DynamicHubInfo); + hostedMethods @19 :List(PersistedHostedMethod); } struct StaticFinalFieldFoldingSingleton { @@ -305,3 +309,33 @@ struct PrimitiveArray { d @7 :List(Float64); } } + +struct DispatchSlotInfo { + declaredHostedMethodIndex @0 :HostedMethodIndex; + resolvedHostedMethodIndex @1 :HostedMethodIndex; + slotIndex @2 :Int32; + resolutionStatus @3 :Int32; + slotSymbolName @4 :Text; +} + +struct PersistedHostedMethod { + index @0 :Int32; + methodId @1 :MethodId; + vTableIndex @2 :Int32; + installedOffset @3 :Int32; + isVirtualCallTarget @4 :Bool; + symbolName @5 :Text; + hostedMethodName @6 :Text; + hostedMethodUniqueName @7 :Text; +} + +struct DynamicHubInfo { + typeId @0 :TypeId; + installed @1 :Bool; + typecheckId @2 :Int32; + numClassTypes @3 :Int32; + numInterfaceTypes @4 :Int32; + typecheckSlotValues @5 :List(Int32); + locallyDeclaredSlotsHostedMethodIndexes @6 :List(HostedMethodIndex); + dispatchTableSlotValues @7 :List(DispatchSlotInfo); +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/OpenTypeWorldFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/OpenTypeWorldFeature.java index 666492ca80f4..308652eef020 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/OpenTypeWorldFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/OpenTypeWorldFeature.java @@ -24,15 +24,10 @@ */ package com.oracle.svm.hosted; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.EnumSet; -import java.util.HashMap; import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; import java.util.Set; import org.graalvm.nativeimage.ImageSingletons; @@ -50,6 +45,8 @@ import com.oracle.svm.core.layeredimagesingleton.ImageSingletonWriter; import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton; import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags; +import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport; +import com.oracle.svm.hosted.imagelayer.SVMImageLayerLoader; import com.oracle.svm.hosted.meta.HostedType; import jdk.graal.compiler.debug.Assertions; @@ -65,7 +62,7 @@ public boolean isInConfiguration(Feature.IsInConfigurationAccess access) { @Override public void beforeUniverseBuilding(BeforeUniverseBuildingAccess access) { if (ImageLayerBuildingSupport.buildingInitialLayer()) { - ImageSingletons.add(LayerTypeCheckInfo.class, new LayerTypeCheckInfo()); + ImageSingletons.add(LayerTypeCheckInfo.class, new LayerTypeCheckInfo(0)); } } @@ -112,63 +109,64 @@ public static int loadTypeInfo(Collection types) { } } - public static void persistTypeInfo(Collection types) { - if (ImageLayerBuildingSupport.buildingImageLayer()) { - ImageSingletons.lookup(LayerTypeCheckInfo.class).persistTypeInfo(types); - } - } - - record TypeCheckInfo(int typeID, int numClassTypes, int numInterfaceTypes, int[] typecheckSlots) { - private List toIntList() { - ArrayList list = new ArrayList<>(); - list.add(typeID); - list.add(numClassTypes); - list.add(numInterfaceTypes); - Arrays.stream(typecheckSlots).forEach(list::add); - - return list; - } + @SuppressWarnings("unused") + public static boolean validateTypeInfo(Collection types) { + if (ImageLayerBuildingSupport.buildingExtensionLayer()) { + var loader = HostedImageLayerBuildingSupport.singleton().getLoader(); + for (HostedType type : types) { + if (type.getWrapped().isInBaseLayer()) { + var priorInfo = getTypecheckInfo(loader, type); + if (!priorInfo.installed()) { + // no need to validate this hub, as it was not installed + continue; + } + int typeID = type.getTypeID(); + int numClassTypes = type.getNumClassTypes(); + int numInterfaceTypes = type.getNumInterfaceTypes(); + int[] typecheckSlots = type.getOpenTypeWorldTypeCheckSlots(); + boolean matches = typeID == priorInfo.typeID && numClassTypes == priorInfo.numClassTypes && numInterfaceTypes == priorInfo.numInterfaceTypes && + Arrays.equals(typecheckSlots, priorInfo.typecheckSlots); + if (!matches) { + var typeInfo = new TypeCheckInfo(true, typeID, numClassTypes, numInterfaceTypes, typecheckSlots); + assert false : Assertions.errorMessage("Mismatch for ", type, priorInfo, typeInfo, Arrays.toString(priorInfo.typecheckSlots), + Arrays.toString(typeInfo.typecheckSlots)); - private static TypeCheckInfo fromIntList(List list) { - int typeID = list.get(0); - int numClassTypes = list.get(1); - int numInterfaceTypes = list.get(2); - int[] typecheckSlots = list.subList(3, list.size()).stream().mapToInt(i -> i).toArray(); - return new TypeCheckInfo(typeID, numClassTypes, numInterfaceTypes, typecheckSlots); + } + } + } } + return true; + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; + static TypeCheckInfo getTypecheckInfo(SVMImageLayerLoader loader, HostedType hType) { + if (hType.getWrapped().isInBaseLayer()) { + var hubInfo = loader.getDynamicHubInfo(hType.getWrapped()); + var valuesReader = hubInfo.getTypecheckSlotValues(); + int[] typecheckSlots = new int[valuesReader.size()]; + for (int i = 0; i < typecheckSlots.length; i++) { + typecheckSlots[i] = valuesReader.get(i); } - TypeCheckInfo typeCheckInfo = (TypeCheckInfo) o; - return typeID == typeCheckInfo.typeID && numClassTypes == typeCheckInfo.numClassTypes && numInterfaceTypes == typeCheckInfo.numInterfaceTypes && - Arrays.equals(typecheckSlots, typeCheckInfo.typecheckSlots); + return new TypeCheckInfo(hubInfo.getInstalled(), hubInfo.getTypecheckId(), hubInfo.getNumClassTypes(), hubInfo.getNumInterfaceTypes(), typecheckSlots); + } else { + return null; } + } - @Override - public int hashCode() { - int result = Objects.hash(typeID, numClassTypes, numInterfaceTypes); - result = 31 * result + Arrays.hashCode(typecheckSlots); - return result; - } + record TypeCheckInfo(boolean installed, int typeID, int numClassTypes, int numInterfaceTypes, int[] typecheckSlots) { } private static final class LayerTypeCheckInfo implements LayeredImageSingleton { - Map identifierToTypeInfo = new HashMap<>(); - int maxTypeID = 0; + final int maxTypeID; + + LayerTypeCheckInfo(int maxTypeID) { + this.maxTypeID = maxTypeID; + } public int loadTypeID(Collection types) { - ArrayList usedIDs = new ArrayList<>(); + var loader = HostedImageLayerBuildingSupport.singleton().getLoader(); for (HostedType type : types) { - int identifierID = type.getWrapped().getId(); - TypeCheckInfo info = identifierToTypeInfo.get(identifierID); + TypeCheckInfo info = getTypecheckInfo(loader, type); if (info != null) { - usedIDs.add(info.typeID); type.loadTypeID(info.typeID); } } @@ -176,72 +174,21 @@ public int loadTypeID(Collection types) { return maxTypeID; } - public void persistTypeInfo(Collection types) { - for (HostedType type : types) { - /* - * Currently we are calculating type id information for all types. However, for - * types not tracked across layers, the type ID may not be the same in different - * layers. - */ - assert type.getTypeID() != -1 : type; - if (type.getWrapped().isTrackedAcrossLayers()) { - int identifierID = type.getWrapped().getId(); - int typeID = type.getTypeID(); - int numClassTypes = type.getNumClassTypes(); - int numInterfaceTypes = type.getNumInterfaceTypes(); - int[] typecheckSlots = type.getOpenTypeWorldTypeCheckSlots(); - var priorInfo = identifierToTypeInfo.get(identifierID); - var newTypeInfo = new TypeCheckInfo(typeID, numClassTypes, numInterfaceTypes, typecheckSlots); - if (priorInfo == null) { - identifierToTypeInfo.put(identifierID, newTypeInfo); - } else { - assert newTypeInfo.equals(priorInfo) : Assertions.errorMessage("Mismatch for ", type, priorInfo, newTypeInfo, Arrays.toString(priorInfo.typecheckSlots), - Arrays.toString(newTypeInfo.typecheckSlots)); - } - } - } - } - @Override public EnumSet getImageBuilderFlags() { return LayeredImageSingletonBuilderFlags.BUILDTIME_ACCESS_ONLY; } - private static String getTypeInfoKey(int id) { - return String.format("TypeInfo-%s", id); - } - @Override public PersistFlags preparePersist(ImageSingletonWriter writer) { - /* - * Note all that is strictly needed to restore the typecheck information is the - * (identifierID -> typeID) mappings. In the future we can compact the amount of - * information we store. - */ - var typeIdentifierIds = identifierToTypeInfo.keySet().stream().sorted().toList(); - writer.writeIntList("typeIdentifierIds", typeIdentifierIds); writer.writeInt("maxTypeID", DynamicHubSupport.currentLayer().getMaxTypeId()); - for (int identifierID : typeIdentifierIds) { - var typeInfo = identifierToTypeInfo.get(identifierID); - assert typeInfo != null; - writer.writeIntList(getTypeInfoKey(identifierID), typeInfo.toIntList()); - } - return PersistFlags.CREATE; } @SuppressWarnings("unused") public static Object createFromLoader(ImageSingletonLoader loader) { - var info = new LayerTypeCheckInfo(); - info.maxTypeID = loader.readInt("maxTypeID"); - List typeIdentifierIds = loader.readIntList("typeIdentifierIds"); - for (var identifierID : typeIdentifierIds) { - Object previous = info.identifierToTypeInfo.put(identifierID, TypeCheckInfo.fromIntList(loader.readIntList(getTypeInfoKey(identifierID)))); - assert previous == null : previous; - } - - return info; + return new LayerTypeCheckInfo(loader.readInt("maxTypeID")); } } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java index 9f91009a9435..d60cf2813caa 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java @@ -71,7 +71,7 @@ import com.oracle.svm.hosted.ProgressReporter; import com.oracle.svm.hosted.diagnostic.HostedHeapDumpFeature; import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport; -import com.oracle.svm.hosted.imagelayer.LayeredDispatchTableSupport; +import com.oracle.svm.hosted.imagelayer.LayeredDispatchTableFeature; import com.oracle.svm.hosted.imagelayer.SVMImageLayerLoader; import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.HostedUniverse; @@ -188,7 +188,7 @@ public record UnpublishedTrivialMethods(CompilationGraph unpublishedGraph, boole private final ConcurrentMap unpublishedTrivialMethods = new ConcurrentHashMap<>(); - private final LayeredDispatchTableSupport layeredDispatchTableSupport = ImageLayerBuildingSupport.buildingSharedLayer() ? LayeredDispatchTableSupport.singleton() : null; + private final LayeredDispatchTableFeature layeredDispatchTableSupport = ImageLayerBuildingSupport.buildingSharedLayer() ? LayeredDispatchTableFeature.singleton() : null; public abstract static class CompileReason { /** diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/MethodPointerRelocationProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/MethodPointerRelocationProvider.java index dbcbaeecff31..329e5e0a32cf 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/MethodPointerRelocationProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/MethodPointerRelocationProvider.java @@ -31,7 +31,7 @@ import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; import com.oracle.svm.core.meta.MethodPointer; -import com.oracle.svm.hosted.imagelayer.LayeredDispatchTableSupport; +import com.oracle.svm.hosted.imagelayer.LayeredDispatchTableFeature; import com.oracle.svm.hosted.meta.HostedMethod; public class MethodPointerRelocationProvider { @@ -46,7 +46,7 @@ public void markMethodPointerRelocation(ObjectFile.ProgbitsSectionImpl section, long addend, MethodPointer methodPointer, boolean isInjectedNotCompiled) { String symbolName; if (imageLayer) { - symbolName = LayeredDispatchTableSupport.singleton().getSymbolName(methodPointer, target, isInjectedNotCompiled); + symbolName = LayeredDispatchTableFeature.singleton().getSymbolName(methodPointer, target, isInjectedNotCompiled); } else { symbolName = NativeImage.localSymbolNameForMethod(target); } 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 b8d88d02e708..be811082665a 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 @@ -111,7 +111,7 @@ import com.oracle.svm.hosted.image.RelocatableBuffer.Info; import com.oracle.svm.hosted.imagelayer.HostedDynamicLayerInfo; import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport; -import com.oracle.svm.hosted.imagelayer.LayeredDispatchTableSupport; +import com.oracle.svm.hosted.imagelayer.LayeredDispatchTableFeature; import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.HostedType; @@ -545,7 +545,7 @@ public void build(String imageName, DebugContext debug) { HostedDynamicLayerInfo.singleton().defineSymbolsForPriorLayerMethods(objectFile); } if (ImageLayerBuildingSupport.buildingImageLayer()) { - LayeredDispatchTableSupport.singleton().defineDispatchTableSlotSymbols(objectFile, textSection, codeCache, metaAccess); + LayeredDispatchTableFeature.singleton().defineDispatchTableSlotSymbols(objectFile, textSection, codeCache, metaAccess); } // Mark the sections with the relocations from the maps. @@ -787,7 +787,7 @@ private static String getUniqueShortName(ResolvedJavaMethod sm) { if (sm instanceof HostedMethod hMethod) { if (hMethod.isCompiledInPriorLayer()) { // ensure we use a consistent symbol name across layers - name = HostedDynamicLayerInfo.singleton().loadMethodNameInfo(hMethod.getWrapped()).uniqueShortName(); + name = HostedDynamicLayerInfo.loadMethodNameInfo(hMethod.getWrapped()).uniqueShortName(); } else { name = hMethod.getUniqueShortName(); } 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 d1cb0f06e50d..e88cc998339d 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 @@ -63,7 +63,7 @@ import com.oracle.svm.hosted.config.HybridLayout; import com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo; import com.oracle.svm.hosted.imagelayer.CrossLayerConstantRegistryFeature; -import com.oracle.svm.hosted.imagelayer.LayeredDispatchTableSupport; +import com.oracle.svm.hosted.imagelayer.LayeredDispatchTableFeature; import com.oracle.svm.hosted.meta.HostedClass; import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedInstanceClass; @@ -425,7 +425,7 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { instanceFields = instanceFields.filter(field -> !dynamicHubLayout.isIgnoredField(field)); if (imageLayer) { - LayeredDispatchTableSupport.singleton().registerWrittenDynamicHub((DynamicHub) info.getObject(), heap.aUniverse, heap.hUniverse, vTable); + LayeredDispatchTableFeature.singleton().registerWrittenDynamicHub((DynamicHub) info.getObject(), heap.aUniverse, heap.hUniverse, vTable); } } else if (heap.getHybridLayout(clazz) != null) { 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 dda1d9348674..63b5f01764be 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 @@ -27,16 +27,13 @@ import static com.oracle.svm.hosted.image.NativeImage.localSymbolNameForMethod; import java.util.ArrayList; -import java.util.BitSet; -import java.util.Collection; +import java.util.Collections; import java.util.EnumSet; -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 java.util.stream.Collectors; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.word.PointerBase; @@ -46,8 +43,8 @@ import com.oracle.svm.core.BuildPhaseProvider; import com.oracle.svm.core.c.CGlobalData; import com.oracle.svm.core.c.CGlobalDataFactory; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; +import com.oracle.svm.core.imagelayer.BuildingImageLayerPredicate; import com.oracle.svm.core.imagelayer.DynamicImageLayerInfo; import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; import com.oracle.svm.core.layeredimagesingleton.ImageSingletonLoader; @@ -55,35 +52,29 @@ import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton; import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags; import com.oracle.svm.core.meta.SharedMethod; -import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.c.CGlobalDataFeature; import com.oracle.svm.hosted.image.NativeImage; import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.HostedMethodNameFactory.MethodNameInfo; -import jdk.graal.compiler.debug.Assertions; - +@AutomaticallyRegisteredImageSingleton(value = DynamicImageLayerInfo.class, onlyWith = BuildingImageLayerPredicate.class) public class HostedDynamicLayerInfo extends DynamicImageLayerInfo implements LayeredImageSingleton { - private final Map methodIdToOffsetMap; - private final ConcurrentHashMap methodIdToNameInfoMap; private final CGlobalData cGlobalData; private final Set priorLayerMethodSymbols = new HashSet<>(); private final List libNames; - private boolean persisted = false; + private final Map priorInstalledOffsetCache = ImageLayerBuildingSupport.buildingExtensionLayer() ? new ConcurrentHashMap<>() : null; HostedDynamicLayerInfo() { - this(0, null, new HashMap<>(), new ConcurrentHashMap<>(), new ArrayList<>()); + this(0, null, new ArrayList<>()); } public static HostedDynamicLayerInfo singleton() { return (HostedDynamicLayerInfo) ImageSingletons.lookup(DynamicImageLayerInfo.class); } - private HostedDynamicLayerInfo(int layerNumber, String codeSectionStartSymbol, Map methodIdToOffsetMap, ConcurrentHashMap methodIdToNameInfoMap, + private HostedDynamicLayerInfo(int layerNumber, String codeSectionStartSymbol, List libNames) { super(layerNumber); - this.methodIdToOffsetMap = methodIdToOffsetMap; - this.methodIdToNameInfoMap = methodIdToNameInfoMap; this.libNames = new ArrayList<>(libNames); this.cGlobalData = codeSectionStartSymbol == null ? null : CGlobalDataFactory.forSymbol(codeSectionStartSymbol); } @@ -91,42 +82,52 @@ private HostedDynamicLayerInfo(int layerNumber, String codeSectionStartSymbol, M @Override public PriorLayerMethodLocation getPriorLayerMethodLocation(SharedMethod sMethod) { assert ImageLayerBuildingSupport.buildingExtensionLayer() : "This should only be called within extension images. Within the initial layer the direct calls can be performed"; - HostedMethod method = (HostedMethod) sMethod; - assert method.wrapped.isInBaseLayer() && methodIdToOffsetMap.containsKey(method.getWrapped().getId()) : method; + HostedMethod hMethod = (HostedMethod) sMethod; + int compiledOffset = getPriorInstalledOffset(hMethod.getWrapped()); + assert hMethod.wrapped.isInBaseLayer() && compiledOffset != HostedMethod.INVALID_CODE_ADDRESS_OFFSET; var basePointer = CGlobalDataFeature.singleton().registerAsAccessedOrGet(cGlobalData); - var offset = methodIdToOffsetMap.get(method.getWrapped().getId()); - return new PriorLayerMethodLocation(basePointer, offset); + return new PriorLayerMethodLocation(basePointer, compiledOffset); } public boolean compiledInPriorLayer(AnalysisMethod aMethod) { assert !BuildPhaseProvider.isCompileQueueFinished(); - return methodIdToOffsetMap.containsKey(aMethod.getId()); + return getPriorInstalledOffset(aMethod) != HostedMethod.INVALID_CODE_ADDRESS_OFFSET; } - public MethodNameInfo loadMethodNameInfo(AnalysisMethod method) { - return methodIdToNameInfoMap.get(method.getId()); + private int getPriorInstalledOffset(AnalysisMethod aMethod) { + if (aMethod.isInBaseLayer()) { + return priorInstalledOffsetCache.computeIfAbsent(aMethod, method -> { + var methodData = HostedImageLayerBuildingSupport.singleton().getLoader(); + return methodData.getHostedMethodData(aMethod).getInstalledOffset(); + }); + } else { + return HostedMethod.INVALID_CODE_ADDRESS_OFFSET; + } } - public void recordPersistedMethod(HostedMethod hMethod) { - assert !persisted : "Too late to record this information"; - MethodNameInfo info = new MethodNameInfo(hMethod.getName(), hMethod.getUniqueShortName()); - var prev = methodIdToNameInfoMap.put(hMethod.getWrapped().getId(), info); - // will have to change for multiple layers - assert prev == null : prev; + public static MethodNameInfo loadMethodNameInfo(AnalysisMethod aMethod) { + if (aMethod.isInBaseLayer()) { + var loader = HostedImageLayerBuildingSupport.singleton().getLoader(); + var methodData = loader.getHostedMethodData(aMethod); + return new MethodNameInfo(methodData.getHostedMethodName().toString(), methodData.getHostedMethodUniqueName().toString()); + } else { + return null; + } } public Set getReservedNames() { - return methodIdToNameInfoMap.values().stream().map(MethodNameInfo::uniqueShortName).collect(Collectors.toUnmodifiableSet()); - } - - void registerCompilation(HostedMethod method) { - assert BuildPhaseProvider.isCompileQueueFinished(); - int offset = method.getCodeAddressOffset(); - int methodID = method.getWrapped().getId(); - - assert !methodIdToOffsetMap.containsKey(methodID) : Assertions.errorMessage("Duplicate entry", methodID, offset); - methodIdToOffsetMap.put(methodID, offset); + /* + * Note we only need to ensure method names for persisted analysis methods are reserved. + */ + Set reservedNames = new HashSet<>(); + var methods = HostedImageLayerBuildingSupport.singleton().getLoader().getHostedMethods(); + for (var methodData : methods) { + if (methodData.getMethodId() != LayeredDispatchTableFeature.PriorDispatchMethod.UNPERSISTED_METHOD_ID) { + reservedNames.add(methodData.getHostedMethodUniqueName().toString()); + } + } + return Collections.unmodifiableSet(reservedNames); } public void registerHostedMethod(HostedMethod hMethod) { @@ -157,26 +158,8 @@ public EnumSet getImageBuilderFlags() { return LayeredImageSingletonBuilderFlags.BUILDTIME_ACCESS_ONLY; } - /** - * Verifies each method has been mapped to a unique offset. - */ - boolean verifyUniqueOffsets(Collection methods) { - BitSet seenOffsets = new BitSet(); - for (var entry : methodIdToOffsetMap.entrySet()) { - if (seenOffsets.get(entry.getValue())) { - var method = methods.stream().filter(m -> ((HostedMethod) m).getWrapped().getId() == entry.getKey()).findAny(); - assert false : Assertions.errorMessage("Value has already been found", method, entry.getKey(), entry.getValue()); - } - - seenOffsets.set(entry.getValue()); - } - - return true; - } - @Override public PersistFlags preparePersist(ImageSingletonWriter writer) { - persisted = true; /* * When there are multiple shared layers we will need to store the starting code offset of * each layer. @@ -194,31 +177,6 @@ public PersistFlags preparePersist(ImageSingletonWriter writer) { */ writer.writeString("codeSectionStartSymbol", NativeImage.getTextSectionStartSymbol()); - /* - * Write out all method offsets. - */ - List offsets = new ArrayList<>(methodIdToOffsetMap.size()); - List methodOffsetIds = new ArrayList<>(methodIdToOffsetMap.size()); - methodIdToOffsetMap.forEach((key, value) -> { - methodOffsetIds.add(key); - offsets.add(value); - }); - writer.writeIntList("methodOffsetIDs", methodOffsetIds); - writer.writeIntList("offsets", offsets); - - /* - * Write out all persisted method names - */ - List methodNameIds = new ArrayList<>(methodIdToNameInfoMap.size()); - List names = new ArrayList<>(methodIdToNameInfoMap.size() * 2); - methodIdToNameInfoMap.forEach((key, value) -> { - methodNameIds.add(key); - names.add(value.name()); - names.add(value.uniqueShortName()); - }); - writer.writeIntList("methodNameIDs", methodNameIds); - writer.writeStringList("names", names); - writer.writeStringList("libNames", libNames); return PersistFlags.CREATE; @@ -226,81 +184,14 @@ public PersistFlags preparePersist(ImageSingletonWriter writer) { @SuppressWarnings("unused") public static Object createFromLoader(ImageSingletonLoader loader) { - assert loader.readIntList("offsets").size() == loader.readIntList("methodOffsetIDs").size() : Assertions.errorMessage("Offsets and methodIDs are incompatible", loader.readIntList("offsets"), - loader.readIntList("methodIDs")); var snapshotReader = ((SVMImageLayerSingletonLoader.ImageSingletonLoaderImpl) loader).getSnapshotReader(); int layerNumber = snapshotReader.getNextLayerNumber(); String codeSectionStartSymbol = loader.readString("codeSectionStartSymbol"); - /* - * Load the offsets of all methods in the prior layers. - */ - var offsets = loader.readIntList("offsets").iterator(); - var methodOffsetIds = loader.readIntList("methodOffsetIDs").iterator(); - Map initialMethodIdToOffsetMap = new HashMap<>(); - - while (offsets.hasNext()) { - int methodId = methodOffsetIds.next(); - int offset = offsets.next(); - var prev = initialMethodIdToOffsetMap.put(methodId, offset); - assert prev == null; - } - - /* - * Load the names of all methods in the prior layers. - */ - var names = loader.readStringList("names").iterator(); - var methodNameIds = loader.readIntList("methodNameIDs").iterator(); - ConcurrentHashMap initialMethodIdToMethodNameMap = new ConcurrentHashMap<>(); - - while (methodNameIds.hasNext()) { - int methodId = methodNameIds.next(); - String name = names.next(); - String uniqueShortName = names.next(); - var prev = initialMethodIdToMethodNameMap.put(methodId, new MethodNameInfo(name, uniqueShortName)); - assert prev == null; - } - var libNames = loader.readStringList("libNames"); - return new HostedDynamicLayerInfo(layerNumber, codeSectionStartSymbol, initialMethodIdToOffsetMap, initialMethodIdToMethodNameMap, libNames); - } -} - -@AutomaticallyRegisteredFeature -class HostedDynamicLayerInfoFeature implements InternalFeature { - - @Override - public boolean isInConfiguration(IsInConfigurationAccess access) { - return ImageLayerBuildingSupport.buildingImageLayer(); - } - - @Override - public void afterRegistration(AfterRegistrationAccess access) { - if (ImageLayerBuildingSupport.buildingInitialLayer()) { - ImageSingletons.add(DynamicImageLayerInfo.class, new HostedDynamicLayerInfo()); - } - } - - @Override - public void afterCompilation(AfterCompilationAccess access) { - /* - * Store all compiled method offsets into the singleton. - */ - - if (ImageLayerBuildingSupport.buildingApplicationLayer()) { - // This is the last layer; no need to store anything - return; - } - - var config = (FeatureImpl.AfterCompilationAccessImpl) access; - - assert HostedDynamicLayerInfo.singleton().verifyUniqueOffsets(config.getMethods()); - - for (var entry : config.getCodeCache().getOrderedCompilations()) { - HostedDynamicLayerInfo.singleton().registerCompilation(entry.getLeft()); - } + return new HostedDynamicLayerInfo(layerNumber, codeSectionStartSymbol, libNames); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredDispatchTableSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredDispatchTableFeature.java similarity index 65% rename from substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredDispatchTableSupport.java rename to substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredDispatchTableFeature.java index f6ded55bfc7a..7835ad49242e 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredDispatchTableSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredDispatchTableFeature.java @@ -25,9 +25,9 @@ package com.oracle.svm.hosted.imagelayer; import java.lang.reflect.Array; -import java.util.ArrayList; import java.util.Arrays; -import java.util.EnumSet; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; @@ -35,10 +35,12 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; -import java.util.stream.Collectors; +import java.util.function.Supplier; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.hosted.Feature; import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; @@ -53,10 +55,7 @@ import com.oracle.svm.core.graal.snippets.OpenTypeWorldDispatchTableSnippets; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; -import com.oracle.svm.core.layeredimagesingleton.ImageSingletonLoader; -import com.oracle.svm.core.layeredimagesingleton.ImageSingletonWriter; -import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton; -import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags; +import com.oracle.svm.core.layeredimagesingleton.FeatureSingleton; import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.util.VMError; @@ -92,9 +91,10 @@ * * We call {@link #recordVirtualCallTarget} to register a virtual call that must be added as a root * in a subsequent layer. The logic for installing roots in subsequent layers is performed in - * {@link LayeredDispatchTableSupportFeature#beforeAnalysis}. + * {@link #beforeAnalysis}. */ -public class LayeredDispatchTableSupport implements LayeredImageSingleton { +@AutomaticallyRegisteredFeature +public class LayeredDispatchTableFeature implements FeatureSingleton, InternalFeature { public static final class Options { @Option(help = "Log discrepancies between layered open world type information. This is an experimental option which will be removed.")// public static final HostedOptionKey LogLayeredDispatchTableDiscrepancies = new HostedOptionKey<>(false); @@ -103,36 +103,122 @@ public static final class Options { public static final HostedOptionKey ErrorOnLayeredDispatchTableDiscrepancies = new HostedOptionKey<>(false); } - final Set priorUnresolvedSymbols; - final Map priorDispatchTables; - /** - * Map from typeId to set of names generated via {@link #generateFormattedMethodName}. - */ - final Map> priorVirtualCallTargets; + final Map priorDispatchTableCache = ImageLayerBuildingSupport.buildingExtensionLayer() ? new ConcurrentHashMap<>() : null; + final Map priorDispatchMethodCache = ImageLayerBuildingSupport.buildingExtensionLayer() ? new ConcurrentHashMap<>() : null; - final Map methodPointerToDispatchSlot = new IdentityHashMap<>(); - final Map typeToDispatchTable = new HashMap<>(); final Set virtualCallTargets = ImageLayerBuildingSupport.buildingSharedLayer() ? ConcurrentHashMap.newKeySet() : null; + final boolean generateUnresolvedSymbolNames = ImageLayerBuildingSupport.buildingSharedLayer(); + Map persistedHostedMethodIndexMap = ImageLayerBuildingSupport.buildingSharedLayer() ? new ConcurrentHashMap<>() : null; - private final boolean generateUnresolvedSymbolNames = ImageLayerBuildingSupport.buildingSharedLayer(); + final Map methodPointerToDispatchSlot = new IdentityHashMap<>(); + final Map typeToDispatchTable = new HashMap<>(); /** - * Cache of builderModules. Set in {@link LayeredDispatchTableSupportFeature#beforeCompilation}. + * Cache of builderModules. Set in {@link #beforeCompilation}. */ private Set builderModules; - public LayeredDispatchTableSupport() { - this(Map.of(), Set.of(), Map.of()); + static final int INVALID_HOSTED_METHOD_INDEX = -1; + + @Override + public boolean isInConfiguration(Feature.IsInConfigurationAccess access) { + return ImageLayerBuildingSupport.buildingImageLayer(); + } + + @Override + public void beforeAnalysis(Feature.BeforeAnalysisAccess access) { + if (ImageLayerBuildingSupport.buildingExtensionLayer()) { + var config = (FeatureImpl.BeforeAnalysisAccessImpl) access; + getPriorVirtualCallTargets().forEach(aMethod -> { + config.registerAsRoot(aMethod, false, "in prior layer dispatch table"); + }); + } + } + + @Override + public void beforeCompilation(Feature.BeforeCompilationAccess a) { + BeforeCompilationAccessImpl access = (BeforeCompilationAccessImpl) a; + installBuilderModules(access.getImageClassLoader().getBuilderModules()); + } + + private PriorDispatchMethod createPriorDispatchMethodInfo(int index) { + return priorDispatchMethodCache.computeIfAbsent(index, i -> { + var loader = HostedImageLayerBuildingSupport.singleton().getLoader(); + var reader = loader.getHostedMethodData(i); + return new PriorDispatchMethod(reader.getMethodId(), reader.getSymbolName().toString(), reader.getVTableIndex(), reader.getIsVirtualCallTarget()); + }); + } + + private PriorDispatchTable createPriorDispatchTable(HostedType hType) { + var loader = HostedImageLayerBuildingSupport.singleton().getLoader(); + var hubInfo = loader.getDynamicHubInfo(hType.getWrapped()); + var localSlotIds = hubInfo.getLocallyDeclaredSlotsHostedMethodIndexes(); + PriorDispatchMethod[] locallyDeclaredSlots = new PriorDispatchMethod[hubInfo.getLocallyDeclaredSlotsHostedMethodIndexes().size()]; + for (int i = 0; i < locallyDeclaredSlots.length; i++) { + locallyDeclaredSlots[i] = createPriorDispatchMethodInfo(localSlotIds.get(i)); + } + + PriorDispatchSlot[] dispatchSlots; + if (hubInfo.hasDispatchTableSlotValues()) { + var dispatchSlotsReader = hubInfo.getDispatchTableSlotValues(); + dispatchSlots = new PriorDispatchSlot[dispatchSlotsReader.size()]; + for (int i = 0; i < dispatchSlots.length; i++) { + var slotInfo = dispatchSlotsReader.get(i); + PriorDispatchMethod declaredMethod = createPriorDispatchMethodInfo(slotInfo.getDeclaredHostedMethodIndex()); + PriorDispatchMethod resolvedMethod = null; + if (slotInfo.getResolvedHostedMethodIndex() != INVALID_HOSTED_METHOD_INDEX) { + resolvedMethod = createPriorDispatchMethodInfo(slotInfo.getResolvedHostedMethodIndex()); + } + SlotResolutionStatus status = SlotResolutionStatus.values()[slotInfo.getResolutionStatus()]; + String slotSymbolName = slotInfo.getSlotSymbolName().toString(); + var dispatchSlot = new PriorDispatchSlot(declaredMethod, resolvedMethod, slotInfo.getSlotIndex(), status, slotSymbolName); + dispatchSlots[i] = dispatchSlot; + } + } else { + dispatchSlots = PriorDispatchSlot.EMPTY_ARRAY; + } + return new PriorDispatchTable(hubInfo.getTypeId(), hubInfo.getInstalled(), locallyDeclaredSlots, dispatchSlots); + } + + private PriorDispatchTable getPriorDispatchTable(HostedType hType) { + if (hType.getWrapped().isInBaseLayer()) { + return priorDispatchTableCache.computeIfAbsent(hType, this::createPriorDispatchTable); + } else { + return null; + } + } + + private static Set getPriorUnresolvedSymbols() { + Set unresolvedSymbols = new HashSet<>(); + var hubInfos = HostedImageLayerBuildingSupport.singleton().getLoader().getDynamicHubInfos(); + for (var hubInfo : hubInfos) { + if (hubInfo.getInstalled()) { + assert hubInfo.hasDispatchTableSlotValues(); + var dispatchSlots = hubInfo.getDispatchTableSlotValues(); + for (var slotInfo : dispatchSlots) { + SlotResolutionStatus status = SlotResolutionStatus.values()[slotInfo.getResolutionStatus()]; + String slotSymbolName = slotInfo.getSlotSymbolName().toString(); + if (status == SlotResolutionStatus.UNRESOLVED || status == SlotResolutionStatus.NOT_COMPILED) { + assert !slotSymbolName.equals(PriorDispatchSlot.INVALID_SYMBOL_NAME); + unresolvedSymbols.add(slotSymbolName); + } + } + } + } + return Collections.unmodifiableSet(unresolvedSymbols); } - private LayeredDispatchTableSupport(Map priorDispatchTables, Set priorUnresolvedSymbols, Map> priorVirtualCallTargets) { - this.priorDispatchTables = priorDispatchTables; - this.priorUnresolvedSymbols = priorUnresolvedSymbols; - this.priorVirtualCallTargets = priorVirtualCallTargets; + static Stream getPriorVirtualCallTargets() { + var loader = HostedImageLayerBuildingSupport.singleton().getLoader(); + var methods = loader.getHostedMethods(); + return StreamSupport.stream(methods.spliterator(), false).filter(SharedLayerSnapshotCapnProtoSchemaHolder.PersistedHostedMethod.Reader::getIsVirtualCallTarget).map(data -> { + assert data.getMethodId() != PriorDispatchMethod.UNPERSISTED_METHOD_ID; + return loader.getAnalysisMethodForBaseLayerId(data.getMethodId()); + }); } - public static LayeredDispatchTableSupport singleton() { - return ImageSingletons.lookup(LayeredDispatchTableSupport.class); + public static LayeredDispatchTableFeature singleton() { + return ImageSingletons.lookup(LayeredDispatchTableFeature.class); } void installBuilderModules(Set newCoreTypes) { @@ -152,11 +238,6 @@ public void recordVirtualCallTarget(HostedMethod caller, HostedMethod callee) { } } - // GR-59009 remove once we persist more methods - static String generateFormattedMethodName(AnalysisMethod method) { - return method.format("%n(%P)%R"); - } - public void registerDeclaredDispatchInfo(HostedType type, List declaredMethods) { var dispatchTable = new HostedDispatchTable(); dispatchTable.type = type; @@ -183,7 +264,7 @@ public void registerArrayDispatchTable(HostedType arrayType, HostedType objectTy arraySlotInfo.dispatchTable = arrayDispatchTable; arraySlotInfo.declaredMethod = objSlotInfo.declaredMethod; arraySlotInfo.resolvedMethod = objSlotInfo.resolvedMethod; - arraySlotInfo.slotNum = objSlotInfo.slotNum; + arraySlotInfo.slotIndex = objSlotInfo.slotIndex; arraySlotInfo.status = objSlotInfo.status; return arraySlotInfo; @@ -210,7 +291,7 @@ public void registerNonArrayDispatchTable(HostedType type, boolean[] validTarget for (int i = 0; i < length; i++) { HostedDispatchSlot slot = new HostedDispatchSlot(); slot.dispatchTable = dispatchTable; - slot.slotNum = i; + slot.slotIndex = i; slot.resolvedMethod = validTarget[i] ? resolvedMethods[i] : null; slot.declaredMethod = targetMethods[i]; slot.status = validTarget[i] ? SlotResolutionStatus.COMPUTED : SlotResolutionStatus.UNRESOLVED; @@ -224,7 +305,7 @@ public void registerNonArrayDispatchTable(HostedType type, boolean[] validTarget private void injectPriorLayerInfo(HostedType type, HostedDispatchTable dispatchTable) { if (type.getWrapped().isInBaseLayer()) { - var priorInfo = priorDispatchTables.get(type.getWrapped().getId()); + var priorInfo = getPriorDispatchTable(type); if (priorInfo != null) { compareTypeInfo(dispatchTable, priorInfo); dispatchTable.status = priorInfo.installed ? HubStatus.INSTALLED_PRIOR_LAYER : HubStatus.COMPUTED_PRIOR_LAYER; @@ -248,7 +329,7 @@ private static String compareMethod(HostedMethod curMethod, PriorDispatchMethod String errorMessage = ""; int priorId = priorMethod.methodId(); int curId = curMethod.getWrapped().getId(); - if (priorId != PriorDispatchMethod.UNKNOWN_ID) { + if (priorId != PriorDispatchMethod.UNPERSISTED_METHOD_ID) { if (curId != priorId) { errorMessage += String.format("mismatch in id %s %s%n", curId, priorId); } @@ -261,8 +342,8 @@ private static String compareMethod(HostedMethod curMethod, PriorDispatchMethod } int priorVTableIdx = priorMethod.vtableIndex; - int curVTableIdx = curMethod.hasVTableIndex() ? curMethod.getVTableIndex() : PriorDispatchMethod.UNKNOWN_VTABLE_IDX; - if (priorVTableIdx != PriorDispatchMethod.UNKNOWN_VTABLE_IDX && curVTableIdx != PriorDispatchMethod.UNKNOWN_VTABLE_IDX && priorVTableIdx != curVTableIdx) { + int curVTableIdx = curMethod.hasVTableIndex() ? curMethod.getVTableIndex() : HostedMethod.MISSING_VTABLE_IDX; + if (priorVTableIdx != HostedMethod.MISSING_VTABLE_IDX && curVTableIdx != HostedMethod.MISSING_VTABLE_IDX && priorVTableIdx != curVTableIdx) { errorMessage += String.format("mismatch in vtable index %s %s%n", curVTableIdx, priorVTableIdx); } if (!errorMessage.isEmpty()) { @@ -363,7 +444,7 @@ private static String computeUnresolvedMethodSymbol(HostedDispatchSlot slotInfo, unresolvedTableSymbol = methodToSymbolMap.computeIfAbsent(resolvedMethod, k -> String.format("%s_unresolvedVTableSym", NativeImage.localSymbolNameForMethod(k))); } else { unresolvedTableSymbol = SubstrateOptions.ImageSymbolsPrefix.getValue() + - String.format("unresolvedVTableSym_typeid%s_slot%s", slotInfo.dispatchTable.type.getWrapped().getId(), slotInfo.slotNum); + String.format("unresolvedVTableSym_typeid%s_slot%s", slotInfo.dispatchTable.type.getWrapped().getId(), slotInfo.slotIndex); } return unresolvedTableSymbol; } @@ -425,8 +506,8 @@ public void defineDispatchTableSlotSymbols(ObjectFile objectFile, ObjectFile.Sec * Now that this method has been compiled we must define it. */ - var priorInfo = priorDispatchTables.get(slotInfo.dispatchTable.type.getWrapped().getId()); - var symName = priorInfo.slots[slotInfo.slotNum].slotSymbolName; + var priorInfo = getPriorDispatchTable(slotInfo.dispatchTable.type); + var symName = priorInfo.slots[slotInfo.slotIndex].slotSymbolName; var prev = resolvedPriorVTableMap.put(symName, slotInfo.resolvedMethod); /* * All slots with the same symbol name should have the same resolved method. @@ -451,7 +532,7 @@ public void defineDispatchTableSlotSymbols(ObjectFile objectFile, ObjectFile.Sec * are defined to be linked to the invalid method handler. */ if (ImageLayerBuildingSupport.buildingApplicationLayer()) { - priorUnresolvedSymbols.forEach(symbol -> { + getPriorUnresolvedSymbols().forEach(symbol -> { if (!resolvedPriorVTableMap.containsKey(symbol)) { CompilationResult result = codeCache.compilationResultFor(invalidMethod); @@ -483,181 +564,79 @@ public String getSymbolName(MethodPointer methodPointer, HostedMethod target, @S return symbol; } - @Override - public EnumSet getImageBuilderFlags() { - return LayeredImageSingletonBuilderFlags.BUILDTIME_ACCESS_ONLY; + public HostedMethod[] acquireHostedMethodArray() { + return persistedHostedMethodIndexMap.entrySet().stream() + .sorted(Comparator.comparingInt(Map.Entry::getValue)) + .map(Map.Entry::getKey) + .toArray(HostedMethod[]::new); } - @Override - public PersistFlags preparePersist(ImageSingletonWriter writer) { - - /* - * To reduce redundancy, we maintain a separate table of all methods we refer to within the - * dispatch tables. - */ - Map methodToOffsetMap = new HashMap<>(); - List methodBooleans = new ArrayList<>(); - List methodInts = new ArrayList<>(); - List methodStrings = new ArrayList<>(); - Function methodToOffsetMapper = (hMethod) -> { - int offset; - if (methodToOffsetMap.containsKey(hMethod)) { - offset = methodToOffsetMap.get(hMethod); - } else { - offset = methodToOffsetMap.size(); - methodToOffsetMap.put(hMethod, offset); - methodInts.add(hMethod.getWrapped().isTrackedAcrossLayers() ? hMethod.wrapped.getId() : PriorDispatchMethod.UNKNOWN_ID); - methodInts.add(hMethod.hasVTableIndex() ? hMethod.getVTableIndex() : PriorDispatchMethod.UNKNOWN_VTABLE_IDX); - methodBooleans.add(virtualCallTargets.contains(hMethod)); - methodStrings.add(NativeImage.localSymbolNameForMethod(hMethod)); - methodStrings.add(generateFormattedMethodName(hMethod.getWrapped())); - } - return offset; - }; - - /* - * Write out dispatch tables for persisted types. - */ - List dispatchTableInts = new ArrayList<>(); - List dispatchTableBooleans = new ArrayList<>(); - List dispatchSlotInts = new ArrayList<>(); - List dispatchSlotStrings = new ArrayList<>(); - int nextSlotIdx = 0; - for (HostedDispatchTable info : typeToDispatchTable.values()) { - if (!info.type.getWrapped().isTrackedAcrossLayers()) { - // if a type contains target of a virtual call, then it should be persisted - assert Arrays.stream(info.locallyDeclaredSlots).noneMatch(virtualCallTargets::contains) : "Type should be persisted: " + info.type; - continue; - } - - List localTargets = new ArrayList<>(); - List slotOffsets = new ArrayList<>(); - - for (var hMethod : info.locallyDeclaredSlots) { - localTargets.add(methodToOffsetMapper.apply(hMethod)); - } - - boolean hubInstalled = info.status == HubStatus.INSTALLED_CURRENT_LAYER; - if (info.slots != null) { - for (var slotInfo : info.slots) { - var symbolName = hubInstalled ? slotInfo.symbol : PriorDispatchSlot.INVALID_SYMBOL_NAME; - dispatchSlotStrings.add(symbolName); - dispatchSlotInts.add(slotInfo.slotNum); - dispatchSlotInts.add(slotInfo.status.ordinal()); - dispatchSlotInts.add(methodToOffsetMapper.apply(slotInfo.declaredMethod)); - if (slotInfo.status.isResolved()) { - assert slotInfo.resolvedMethod != null; - dispatchSlotInts.add(methodToOffsetMapper.apply(slotInfo.resolvedMethod)); - } else { - dispatchSlotInts.add(PriorDispatchSlot.UNKNOWN_METHOD); - } - slotOffsets.add(nextSlotIdx++); - } - } + public void releaseHostedMethodArray() { + persistedHostedMethodIndexMap = null; + } - dispatchTableInts.add(info.type.getWrapped().getId()); - dispatchTableInts.add(localTargets.size()); - dispatchTableInts.add(slotOffsets.size()); - dispatchTableInts.addAll(localTargets); - dispatchTableInts.addAll(slotOffsets); - dispatchTableBooleans.add(hubInstalled); + public void persistHostedMethod(HostedMethod hMethod, Supplier methodInfoBuilderSupplier) { + assert persistedHostedMethodIndexMap.containsKey(hMethod); + + boolean persistedMethod = hMethod.getWrapped().isTrackedAcrossLayers(); + var builder = methodInfoBuilderSupplier.get(); + builder.setIndex(persistedHostedMethodIndexMap.get(hMethod)); + builder.setMethodId(persistedMethod ? hMethod.getWrapped().getId() : PriorDispatchMethod.UNPERSISTED_METHOD_ID); + builder.setSymbolName(NativeImage.localSymbolNameForMethod(hMethod)); + builder.setVTableIndex(hMethod.hasVTableIndex() ? hMethod.getVTableIndex() : HostedMethod.MISSING_VTABLE_IDX); + builder.setIsVirtualCallTarget(virtualCallTargets.contains(hMethod)); + builder.setInstalledOffset(hMethod.isCodeAddressOffsetValid() ? hMethod.getCodeAddressOffset() : HostedMethod.INVALID_CODE_ADDRESS_OFFSET); + if (persistedMethod) { + builder.setHostedMethodName(hMethod.getName()); + builder.setHostedMethodUniqueName(hMethod.getUniqueShortName()); } - - writer.writeIntList("dispatchTableInts", dispatchTableInts); - writer.writeBoolList("dispatchTableBooleans", dispatchTableBooleans); - writer.writeIntList("dispatchSlotInts", dispatchSlotInts); - writer.writeStringList("dispatchSlotStrings", dispatchSlotStrings); - writer.writeBoolList("methodBooleans", methodBooleans); - writer.writeIntList("methodInts", methodInts); - writer.writeStringList("methodStrings", methodStrings); - - return PersistFlags.CREATE; } - @SuppressWarnings("unused") - public static Object createFromLoader(ImageSingletonLoader loader) { - List dispatchTableInts = loader.readIntList("dispatchTableInts"); - List dispatchTableBooleans = loader.readBoolList("dispatchTableBooleans"); - List dispatchSlotInts = loader.readIntList("dispatchSlotInts"); - List dispatchSlotStrings = loader.readStringList("dispatchSlotStrings"); - List methodBooleans = loader.readBoolList("methodBooleans"); - List methodInts = loader.readIntList("methodInts"); - List methodStrings = loader.readStringList("methodStrings"); - - Set unresolvedSymbols = new HashSet<>(); - Map priorTypes = new HashMap<>(); - Map> priorVirtualCallTargets = new HashMap<>(); - - ArrayList priorMethods = new ArrayList<>(); - var intIterator = methodInts.iterator(); - var stringIterator = methodStrings.iterator(); - var boolIterator = methodBooleans.iterator(); - while (stringIterator.hasNext()) { - String symbol = stringIterator.next(); - String formattedName = stringIterator.next(); - int methodId = intIterator.next(); - int vtableIndex = intIterator.next(); - boolean isVirtualCallTarget = boolIterator.next(); - - var target = new PriorDispatchMethod(methodId, symbol, vtableIndex, formattedName, isVirtualCallTarget); - priorMethods.add(target); - } + public int getPersistedHostedMethodIndex(HostedMethod hMethod) { + int nextIdx = persistedHostedMethodIndexMap.size(); + persistedHostedMethodIndexMap.putIfAbsent(hMethod, nextIdx); + return persistedHostedMethodIndexMap.get(hMethod); + } - ArrayList priorDispatchSlots = new ArrayList<>(); - intIterator = dispatchSlotInts.iterator(); - stringIterator = dispatchSlotStrings.iterator(); - while (stringIterator.hasNext()) { - String slotSymbolName = stringIterator.next(); - int slotNum = intIterator.next(); - SlotResolutionStatus status = SlotResolutionStatus.values()[intIterator.next()]; - PriorDispatchMethod declaredMethod = priorMethods.get(intIterator.next()); - PriorDispatchMethod resolvedMethod = null; - int index = intIterator.next(); - if (index != PriorDispatchSlot.UNKNOWN_METHOD) { - resolvedMethod = priorMethods.get(index); + public void persistDynamicHubInfo(HostedType hType, Supplier typeInfoBuilderSupplier) { + var typeInfoBuilder = typeInfoBuilderSupplier.get(); + typeInfoBuilder.setTypeId(hType.getWrapped().getId()); + + // typecheck info + typeInfoBuilder.setTypecheckId(hType.getTypeID()); + typeInfoBuilder.setNumClassTypes(hType.getNumClassTypes()); + typeInfoBuilder.setNumInterfaceTypes(hType.getNumInterfaceTypes()); + SVMImageLayerWriter.initInts(typeInfoBuilder::initTypecheckSlotValues, Arrays.stream(hType.getOpenTypeWorldTypeCheckSlots())); + + // dispatch table info + HostedDispatchTable hDispatchTable = typeToDispatchTable.get(hType); + if (hDispatchTable != null) { + boolean hubInstalled = hDispatchTable.status == HubStatus.INSTALLED_CURRENT_LAYER; + typeInfoBuilder.setInstalled(hubInstalled); + + SVMImageLayerWriter.initInts(typeInfoBuilder::initLocallyDeclaredSlotsHostedMethodIndexes, + Arrays.stream(hDispatchTable.locallyDeclaredSlots).mapToInt(this::getPersistedHostedMethodIndex)); + + assert !(hDispatchTable.status == HubStatus.UNINITIALIZED && hDispatchTable.slots != null) : hType; + if (hDispatchTable.slots != null) { + SVMImageLayerWriter.initSortedArray(typeInfoBuilder::initDispatchTableSlotValues, hDispatchTable.slots, (dispatchSlot, dispatchSlotInfoSupplier) -> { + persistDynamicSlot(dispatchSlot, dispatchSlotInfoSupplier, hubInstalled); + }); } - - var slotInfo = new PriorDispatchSlot(declaredMethod, resolvedMethod, slotNum, status, slotSymbolName); - priorDispatchSlots.add(slotInfo); + } else { + assert hType.isPrimitive() : hType; } + } - intIterator = dispatchTableInts.iterator(); - boolIterator = dispatchTableBooleans.iterator(); - while (intIterator.hasNext()) { - int typeId = intIterator.next(); - boolean hubInstalled = boolIterator.next(); - int locallyDeclaredMethodsSize = intIterator.next(); - int allSlotsSize = intIterator.next(); - PriorDispatchMethod[] locallyDeclaredSlots = new PriorDispatchMethod[locallyDeclaredMethodsSize]; - PriorDispatchSlot[] dispatchTableSlots = new PriorDispatchSlot[allSlotsSize]; - for (int i = 0; i < locallyDeclaredMethodsSize; i++) { - locallyDeclaredSlots[i] = priorMethods.get(intIterator.next()); - } - for (int i = 0; i < allSlotsSize; i++) { - dispatchTableSlots[i] = priorDispatchSlots.get(intIterator.next()); - if (hubInstalled) { - var status = dispatchTableSlots[i].status; - if (status == SlotResolutionStatus.UNRESOLVED || status == SlotResolutionStatus.NOT_COMPILED) { - assert !dispatchTableSlots[i].slotSymbolName.equals(PriorDispatchSlot.INVALID_SYMBOL_NAME); - unresolvedSymbols.add(dispatchTableSlots[i].slotSymbolName); - } - - } - } + private void persistDynamicSlot(HostedDispatchSlot dispatchSlot, Supplier dispatchSlotInfoSupplier, boolean hubInstalled) { + var dispatchSlotBuilder = dispatchSlotInfoSupplier.get(); - var priorDispatchTable = new PriorDispatchTable(typeId, hubInstalled, locallyDeclaredSlots, dispatchTableSlots); - Object prev = priorTypes.put(typeId, priorDispatchTable); - assert prev == null : prev; + dispatchSlotBuilder.setSlotIndex(dispatchSlot.slotIndex); + dispatchSlotBuilder.setResolutionStatus(dispatchSlot.status.ordinal()); - Set priorVirtualCallNames = Arrays.stream(locallyDeclaredSlots).filter(PriorDispatchMethod::isVirtualCallTarget).map(PriorDispatchMethod::formattedName) - .collect(Collectors.toSet()); - if (!priorVirtualCallNames.isEmpty()) { - prev = priorVirtualCallTargets.put(typeId, priorVirtualCallNames); - assert prev == null : prev; - } - } - - return new LayeredDispatchTableSupport(priorTypes, unresolvedSymbols, priorVirtualCallTargets); + dispatchSlotBuilder.setDeclaredHostedMethodIndex(getPersistedHostedMethodIndex(dispatchSlot.declaredMethod)); + dispatchSlotBuilder.setResolvedHostedMethodIndex(dispatchSlot.status.isResolved() ? getPersistedHostedMethodIndex(dispatchSlot.resolvedMethod) : INVALID_HOSTED_METHOD_INDEX); + dispatchSlotBuilder.setSlotSymbolName(hubInstalled ? dispatchSlot.symbol : PriorDispatchSlot.INVALID_SYMBOL_NAME); } enum HubStatus { @@ -696,7 +675,7 @@ static class HostedDispatchSlot { HostedDispatchTable dispatchTable; HostedMethod declaredMethod; HostedMethod resolvedMethod; - int slotNum; + int slotIndex; SlotResolutionStatus status; /** @@ -718,62 +697,18 @@ record PriorDispatchTable(int typeID, boolean installed, record PriorDispatchSlot( PriorDispatchMethod declaredMethod, PriorDispatchMethod resolvedMethod, - int slotNum, SlotResolutionStatus status, String slotSymbolName) { - static final int UNKNOWN_METHOD = -1; + int slotIndex, SlotResolutionStatus status, String slotSymbolName) { static final String INVALID_SYMBOL_NAME = "invalid"; + + static final PriorDispatchSlot[] EMPTY_ARRAY = new PriorDispatchSlot[0]; } /** * Because methods are currently only persisted when a method is implementation invoked, it is * not always possible to match on method id. When it is not possible, we store - * {@link PriorDispatchMethod#UNKNOWN_ID} as the value. - * - * GR-59009 will resolve this issue. As part of this we will also remove - * {@link PriorDispatchMethod#formattedName}. + * {@link PriorDispatchMethod#UNPERSISTED_METHOD_ID} as the value. */ - record PriorDispatchMethod(int methodId, String symbolName, int vtableIndex, String formattedName, boolean isVirtualCallTarget) { - static final int UNKNOWN_ID = -1; - static final int UNKNOWN_VTABLE_IDX = -1; - } -} - -@AutomaticallyRegisteredFeature -final class LayeredDispatchTableSupportFeature implements InternalFeature { - - @Override - public boolean isInConfiguration(IsInConfigurationAccess access) { - return ImageLayerBuildingSupport.buildingImageLayer(); - } - - @Override - public void duringSetup(DuringSetupAccess access) { - if (ImageLayerBuildingSupport.buildingInitialLayer()) { - ImageSingletons.add(LayeredDispatchTableSupport.class, new LayeredDispatchTableSupport()); - } - } - - @Override - public void beforeAnalysis(BeforeAnalysisAccess access) { - if (ImageLayerBuildingSupport.buildingExtensionLayer()) { - var config = (FeatureImpl.BeforeAnalysisAccessImpl) access; - var loader = HostedImageLayerBuildingSupport.singleton().getLoader(); - var singleton = LayeredDispatchTableSupport.singleton(); - for (var entry : singleton.priorVirtualCallTargets.entrySet()) { - AnalysisType type = loader.getAnalysisTypeForBaseLayerId(entry.getKey()); - var methods = type.getOrCalculateOpenTypeWorldDispatchTableMethods(); - var virtualCallTargets = entry.getValue(); - methods.forEach(aMethod -> { - if (virtualCallTargets.contains(LayeredDispatchTableSupport.generateFormattedMethodName(aMethod))) { - config.registerAsRoot(aMethod, false, "in prior layer dispatch table"); - } - }); - } - } - } - - @Override - public void beforeCompilation(BeforeCompilationAccess a) { - BeforeCompilationAccessImpl access = (BeforeCompilationAccessImpl) a; - LayeredDispatchTableSupport.singleton().installBuilderModules(access.getImageClassLoader().getBuilderModules()); + record PriorDispatchMethod(int methodId, String symbolName, int vtableIndex, boolean isVirtualCallTarget) { + static final int UNPERSISTED_METHOD_ID = -1; } } 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 3feb75dd1741..c7f5d052c035 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 @@ -99,6 +99,7 @@ import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.DynamicHubInfo; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisField; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedAnalysisMethod.WrappedMethod; @@ -870,14 +871,14 @@ private static Executable lookupMethodByReflection(String name, Class clazz, private void createBaseLayerMethod(PersistedAnalysisMethod.Reader md, int mid, String name, AnalysisType[] parameterTypes, AnalysisType returnType) { AnalysisType type = getAnalysisTypeForBaseLayerId(md.getDeclaringTypeId()); ResolvedSignature signature = ResolvedSignature.fromArray(parameterTypes, returnType); - byte[] code = md.hasCode() ? md.getCode().toArray() : null; + byte[] code = md.hasBytecode() ? md.getBytecode().toArray() : null; IntrinsicMethod methodHandleIntrinsic = !md.hasMethodHandleIntrinsicName() ? null : IntrinsicMethod.valueOf(md.getMethodHandleIntrinsicName().toString()); Annotation[] annotations = getAnnotations(md.getAnnotationList()); baseLayerMethods.computeIfAbsent(mid, methodId -> new BaseLayerMethod(mid, type, name, md.getIsVarArgs(), md.getIsBridge(), signature, md.getCanBeStaticallyBound(), md.getIsConstructor(), - md.getModifiers(), md.getIsSynthetic(), code, md.getCodeSize(), methodHandleIntrinsic, annotations)); + md.getModifiers(), md.getIsSynthetic(), code, md.getBytecodeSize(), methodHandleIntrinsic, annotations)); BaseLayerMethod baseLayerMethod = baseLayerMethods.get(mid); universe.lookup(baseLayerMethod); @@ -924,6 +925,31 @@ private PersistedAnalysisMethod.Reader getMethodData(AnalysisMethod analysisMeth return (id != null) ? findMethod(id) : null; } + public StructList.Reader getDynamicHubInfos() { + return snapshot.getDynamicHubInfos(); + } + + public DynamicHubInfo.Reader getDynamicHubInfo(AnalysisType aType) { + DynamicHubInfo.Reader result = binarySearchUnique(aType.getId(), snapshot.getDynamicHubInfos(), DynamicHubInfo.Reader::getTypeId); + assert result != null : aType; + return result; + } + + public StructList.Reader getHostedMethods() { + return snapshot.getHostedMethods(); + } + + public SharedLayerSnapshotCapnProtoSchemaHolder.PersistedHostedMethod.Reader getHostedMethodData(int hMethodIndex) { + var reader = snapshot.getHostedMethods().get(hMethodIndex); + assert reader.getIndex() == hMethodIndex; + return reader; + } + + public SharedLayerSnapshotCapnProtoSchemaHolder.PersistedHostedMethod.Reader getHostedMethodData(AnalysisMethod aMethod) { + var aMethodData = getMethodData(aMethod); + return getHostedMethodData(aMethodData.getHostedMethodIndex()); + } + /** * See * {@link SVMImageLayerWriter#persistAnalysisParsedGraph(AnalysisMethod, AnalysisParsedGraph)} 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 f5c88d6198bb..713e8b576468 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 @@ -122,6 +122,7 @@ import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.AnnotationValue; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.CEntryPointLiteralReference; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ConstantReference; +import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.DynamicHubInfo; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonKey; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.ImageSingletonObject; import com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.KeyStoreEntry; @@ -352,17 +353,36 @@ public void persistAnalysisInfo() { polymorphicSignatureSealed = true; - List typesToPersist = aUniverse.getTypes().stream().filter(AnalysisType::isTrackedAcrossLayers).toList(); - List methodsToPersist = aUniverse.getMethods().stream().filter(AnalysisMethod::isTrackedAcrossLayers).toList(); - List fieldsToPersist = aUniverse.getFields().stream().filter(AnalysisField::isTrackedAcrossLayers).toList(); + AnalysisType[] typesToPersist = aUniverse.getTypes().stream().filter(AnalysisType::isTrackedAcrossLayers).sorted(Comparator.comparingInt(AnalysisType::getId)) + .toArray(AnalysisType[]::new); + initSortedArray(snapshotBuilder::initTypes, typesToPersist, this::persistType); + var dispatchTableSingleton = LayeredDispatchTableFeature.singleton(); + initSortedArray(snapshotBuilder::initDynamicHubInfos, typesToPersist, + (AnalysisType aType, Supplier builderSupplier) -> dispatchTableSingleton + .persistDynamicHubInfo(hUniverse.lookup(aType), builderSupplier)); - initSortedList(snapshotBuilder::initTypes, typesToPersist, Comparator.comparingInt(AnalysisType::getId), this::persistType); - initSortedList(snapshotBuilder::initMethods, methodsToPersist, Comparator.comparingInt(AnalysisMethod::getId), this::persistMethod); - initSortedList(snapshotBuilder::initFields, fieldsToPersist, Comparator.comparingInt(AnalysisField::getId), this::persistField); + AnalysisMethod[] methodsToPersist = aUniverse.getMethods().stream().filter(AnalysisMethod::isTrackedAcrossLayers).sorted(Comparator.comparingInt(AnalysisMethod::getId)) + .toArray(AnalysisMethod[]::new); + initSortedArray(snapshotBuilder::initMethods, methodsToPersist, this::persistMethod); + AnalysisField[] fieldsToPersist = aUniverse.getFields().stream().filter(AnalysisField::isTrackedAcrossLayers).sorted(Comparator.comparingInt(AnalysisField::getId)) + .toArray(AnalysisField[]::new); + initSortedArray(snapshotBuilder::initFields, fieldsToPersist, this::persistField); + + /* + * 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. + */ + HostedMethod[] hMethodsToPersist = dispatchTableSingleton.acquireHostedMethodArray(); + initSortedArray(snapshotBuilder::initHostedMethods, hMethodsToPersist, dispatchTableSingleton::persistHostedMethod); + dispatchTableSingleton.releaseHostedMethodArray(); + + @SuppressWarnings({"unchecked", "cast"}) + Map.Entry[] constantsToPersist = (Map.Entry[]) constantsMap.entrySet().stream() + .sorted(Comparator.comparingInt(a -> ImageHeapConstant.getConstantID(a.getKey()))) + .toArray(Map.Entry[]::new); Set constantsToRelink = new HashSet<>(); - initSortedList(snapshotBuilder::initConstants, constantsMap.entrySet(), - Comparator.comparingInt(a -> ImageHeapConstant.getConstantID(a.getKey())), + initSortedArray(snapshotBuilder::initConstants, constantsToPersist, (entry, bsupplier) -> persistConstant(entry.getKey(), entry.getValue(), bsupplier.get(), constantsToRelink)); initInts(snapshotBuilder::initConstantsToRelink, constantsToRelink.stream().mapToInt(i -> i).sorted()); } @@ -383,14 +403,10 @@ public static void initStringList(IntFunction builderSupplier, } } - private static void initSortedList(IntFunction> init, Collection objects, Comparator comparator, BiConsumer> action) { - @SuppressWarnings("unchecked") - T[] array = (T[]) objects.toArray(); - Arrays.sort(array, comparator); - - StructList.Builder builder = init.apply(objects.size()); + public static void initSortedArray(IntFunction> init, T[] sortedArray, BiConsumer> action) { + StructList.Builder builder = init.apply(sortedArray.length); Iterator iterator = builder.iterator(); - for (T t : array) { + for (T t : sortedArray) { action.accept(t, iterator::next); } AnalysisError.guarantee(!iterator.hasNext(), "all created struct builders must have been used"); @@ -564,9 +580,9 @@ private void persistMethod(AnalysisMethod method, Supplier { public Factory() { } @@ -4782,6 +4793,30 @@ public final void setLayeredRuntimeMetadataSingleton(com.oracle.svm.hosted.image public final com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.LayeredRuntimeMetadataSingleton.Builder initLayeredRuntimeMetadataSingleton() { return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.LayeredRuntimeMetadataSingleton.factory,9, 0); } + public final boolean hasDynamicHubInfos() { + return !_pointerFieldIsNull(10); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Builder getDynamicHubInfos() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.DynamicHubInfo.listFactory, 10, null, 0); + } + public final void setDynamicHubInfos(com.oracle.svm.shaded.org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.DynamicHubInfo.listFactory, 10, value); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Builder initDynamicHubInfos(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.DynamicHubInfo.listFactory, 10, size); + } + public final boolean hasHostedMethods() { + return !_pointerFieldIsNull(11); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Builder getHostedMethods() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedHostedMethod.listFactory, 11, null, 0); + } + public final void setHostedMethods(com.oracle.svm.shaded.org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedHostedMethod.listFactory, 11, value); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Builder initHostedMethods(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedHostedMethod.listFactory, 11, size); + } } public static final class Reader extends com.oracle.svm.shaded.org.capnproto.StructReader { @@ -4891,6 +4926,20 @@ public com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.LayeredRuntimeMetadataSingleton.factory,9,null, 0); } + public final boolean hasDynamicHubInfos() { + return !_pointerFieldIsNull(10); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Reader getDynamicHubInfos() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.DynamicHubInfo.listFactory, 10, null, 0); + } + + public final boolean hasHostedMethods() { + return !_pointerFieldIsNull(11); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Reader getHostedMethods() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.PersistedHostedMethod.listFactory, 11, null, 0); + } + } } @@ -5464,5 +5513,424 @@ public enum Which { } + 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 { + 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 DispatchSlotInfo.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 getDeclaredHostedMethodIndex() { + return _getIntField(0); + } + public final void setDeclaredHostedMethodIndex(int value) { + _setIntField(0, value); + } + + public final int getResolvedHostedMethodIndex() { + return _getIntField(1); + } + public final void setResolvedHostedMethodIndex(int value) { + _setIntField(1, value); + } + + public final int getSlotIndex() { + return _getIntField(2); + } + public final void setSlotIndex(int value) { + _setIntField(2, value); + } + + public final int getResolutionStatus() { + return _getIntField(3); + } + public final void setResolutionStatus(int value) { + _setIntField(3, value); + } + + public final boolean hasSlotSymbolName() { + return !_pointerFieldIsNull(0); + } + public final com.oracle.svm.shaded.org.capnproto.Text.Builder getSlotSymbolName() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, null, 0, 0); + } + public final void setSlotSymbolName(com.oracle.svm.shaded.org.capnproto.Text.Reader value) { + _setPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, value); + } + public final void setSlotSymbolName(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 initSlotSymbolName(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 getDeclaredHostedMethodIndex() { + return _getIntField(0); + } + + public final int getResolvedHostedMethodIndex() { + return _getIntField(1); + } + + public final int getSlotIndex() { + return _getIntField(2); + } + + public final int getResolutionStatus() { + return _getIntField(3); + } + + public boolean hasSlotSymbolName() { + return !_pointerFieldIsNull(0); + } + public com.oracle.svm.shaded.org.capnproto.Text.Reader getSlotSymbolName() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, null, 0, 0); + } + + } + + } + + + public static class PersistedHostedMethod { + public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)3,(short)3); + 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 PersistedHostedMethod.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 getIndex() { + return _getIntField(0); + } + public final void setIndex(int value) { + _setIntField(0, value); + } + + public final int getMethodId() { + return _getIntField(1); + } + public final void setMethodId(int value) { + _setIntField(1, value); + } + + public final int getVTableIndex() { + return _getIntField(2); + } + public final void setVTableIndex(int value) { + _setIntField(2, value); + } + + public final int getInstalledOffset() { + return _getIntField(3); + } + public final void setInstalledOffset(int value) { + _setIntField(3, value); + } + + public final boolean getIsVirtualCallTarget() { + return _getBooleanField(128); + } + public final void setIsVirtualCallTarget(boolean value) { + _setBooleanField(128, value); + } + + public final boolean hasSymbolName() { + return !_pointerFieldIsNull(0); + } + public final com.oracle.svm.shaded.org.capnproto.Text.Builder getSymbolName() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, null, 0, 0); + } + public final void setSymbolName(com.oracle.svm.shaded.org.capnproto.Text.Reader value) { + _setPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, value); + } + public final void setSymbolName(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 initSymbolName(int size) { + return _initPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, size); + } + public final boolean hasHostedMethodName() { + return !_pointerFieldIsNull(1); + } + public final com.oracle.svm.shaded.org.capnproto.Text.Builder getHostedMethodName() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 1, null, 0, 0); + } + public final void setHostedMethodName(com.oracle.svm.shaded.org.capnproto.Text.Reader value) { + _setPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 1, value); + } + public final void setHostedMethodName(String value) { + _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 initHostedMethodName(int size) { + return _initPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 1, size); + } + public final boolean hasHostedMethodUniqueName() { + return !_pointerFieldIsNull(2); + } + public final com.oracle.svm.shaded.org.capnproto.Text.Builder getHostedMethodUniqueName() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 2, null, 0, 0); + } + public final void setHostedMethodUniqueName(com.oracle.svm.shaded.org.capnproto.Text.Reader value) { + _setPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 2, value); + } + public final void setHostedMethodUniqueName(String value) { + _setPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 2, new com.oracle.svm.shaded.org.capnproto.Text.Reader(value)); + } + public final com.oracle.svm.shaded.org.capnproto.Text.Builder initHostedMethodUniqueName(int size) { + return _initPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 2, 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 getIndex() { + return _getIntField(0); + } + + public final int getMethodId() { + return _getIntField(1); + } + + public final int getVTableIndex() { + return _getIntField(2); + } + + public final int getInstalledOffset() { + return _getIntField(3); + } + + public final boolean getIsVirtualCallTarget() { + return _getBooleanField(128); + } + + public boolean hasSymbolName() { + return !_pointerFieldIsNull(0); + } + public com.oracle.svm.shaded.org.capnproto.Text.Reader getSymbolName() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 0, null, 0, 0); + } + + public boolean hasHostedMethodName() { + return !_pointerFieldIsNull(1); + } + public com.oracle.svm.shaded.org.capnproto.Text.Reader getHostedMethodName() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 1, null, 0, 0); + } + + public boolean hasHostedMethodUniqueName() { + return !_pointerFieldIsNull(2); + } + public com.oracle.svm.shaded.org.capnproto.Text.Reader getHostedMethodUniqueName() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.Text.factory, 2, null, 0, 0); + } + + } + + } + + + public static class DynamicHubInfo { + public static final com.oracle.svm.shaded.org.capnproto.StructSize STRUCT_SIZE = new com.oracle.svm.shaded.org.capnproto.StructSize((short)3,(short)3); + 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 DynamicHubInfo.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 getTypeId() { + return _getIntField(0); + } + public final void setTypeId(int value) { + _setIntField(0, value); + } + + public final boolean getInstalled() { + return _getBooleanField(32); + } + public final void setInstalled(boolean value) { + _setBooleanField(32, value); + } + + public final int getTypecheckId() { + return _getIntField(2); + } + public final void setTypecheckId(int value) { + _setIntField(2, value); + } + + public final int getNumClassTypes() { + return _getIntField(3); + } + public final void setNumClassTypes(int value) { + _setIntField(3, value); + } + + public final int getNumInterfaceTypes() { + return _getIntField(4); + } + public final void setNumInterfaceTypes(int value) { + _setIntField(4, value); + } + + public final boolean hasTypecheckSlotValues() { + return !_pointerFieldIsNull(0); + } + public final com.oracle.svm.shaded.org.capnproto.PrimitiveList.Int.Builder getTypecheckSlotValues() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.PrimitiveList.Int.factory, 0, null, 0); + } + public final void setTypecheckSlotValues(com.oracle.svm.shaded.org.capnproto.PrimitiveList.Int.Reader value) { + _setPointerField(com.oracle.svm.shaded.org.capnproto.PrimitiveList.Int.factory, 0, value); + } + public final com.oracle.svm.shaded.org.capnproto.PrimitiveList.Int.Builder initTypecheckSlotValues(int size) { + return _initPointerField(com.oracle.svm.shaded.org.capnproto.PrimitiveList.Int.factory, 0, size); + } + public final boolean hasLocallyDeclaredSlotsHostedMethodIndexes() { + return !_pointerFieldIsNull(1); + } + public final com.oracle.svm.shaded.org.capnproto.PrimitiveList.Int.Builder getLocallyDeclaredSlotsHostedMethodIndexes() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.PrimitiveList.Int.factory, 1, null, 0); + } + public final void setLocallyDeclaredSlotsHostedMethodIndexes(com.oracle.svm.shaded.org.capnproto.PrimitiveList.Int.Reader value) { + _setPointerField(com.oracle.svm.shaded.org.capnproto.PrimitiveList.Int.factory, 1, value); + } + public final com.oracle.svm.shaded.org.capnproto.PrimitiveList.Int.Builder initLocallyDeclaredSlotsHostedMethodIndexes(int size) { + return _initPointerField(com.oracle.svm.shaded.org.capnproto.PrimitiveList.Int.factory, 1, size); + } + public final boolean hasDispatchTableSlotValues() { + return !_pointerFieldIsNull(2); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Builder getDispatchTableSlotValues() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.DispatchSlotInfo.listFactory, 2, null, 0); + } + public final void setDispatchTableSlotValues(com.oracle.svm.shaded.org.capnproto.StructList.Reader value) { + _setPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.DispatchSlotInfo.listFactory, 2, value); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Builder initDispatchTableSlotValues(int size) { + return _initPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.DispatchSlotInfo.listFactory, 2, 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 getTypeId() { + return _getIntField(0); + } + + public final boolean getInstalled() { + return _getBooleanField(32); + } + + public final int getTypecheckId() { + return _getIntField(2); + } + + public final int getNumClassTypes() { + return _getIntField(3); + } + + public final int getNumInterfaceTypes() { + return _getIntField(4); + } + + public final boolean hasTypecheckSlotValues() { + return !_pointerFieldIsNull(0); + } + public final com.oracle.svm.shaded.org.capnproto.PrimitiveList.Int.Reader getTypecheckSlotValues() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.PrimitiveList.Int.factory, 0, null, 0); + } + + public final boolean hasLocallyDeclaredSlotsHostedMethodIndexes() { + return !_pointerFieldIsNull(1); + } + public final com.oracle.svm.shaded.org.capnproto.PrimitiveList.Int.Reader getLocallyDeclaredSlotsHostedMethodIndexes() { + return _getPointerField(com.oracle.svm.shaded.org.capnproto.PrimitiveList.Int.factory, 1, null, 0); + } + + public final boolean hasDispatchTableSlotValues() { + return !_pointerFieldIsNull(2); + } + public final com.oracle.svm.shaded.org.capnproto.StructList.Reader getDispatchTableSlotValues() { + return _getPointerField(com.oracle.svm.hosted.imagelayer.SharedLayerSnapshotCapnProtoSchemaHolder.DispatchSlotInfo.listFactory, 2, null, 0); + } + + } + + } + + } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java index 60f022dc4037..536b1832ebc8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java @@ -61,6 +61,7 @@ import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; import jdk.graal.compiler.api.replacements.Snippet; +import jdk.graal.compiler.debug.Assertions; import jdk.graal.compiler.debug.JavaMethodContext; import jdk.graal.compiler.java.StableMethodNameFormatter; import jdk.internal.vm.annotation.ForceInline; @@ -82,6 +83,9 @@ public final class HostedMethod extends HostedElement implements SharedMethod, W public static final String METHOD_NAME_COLLISION_SEPARATOR = "%"; + public static final int MISSING_VTABLE_IDX = -1; + public static final int INVALID_CODE_ADDRESS_OFFSET = -1; + public final AnalysisMethod wrapped; private final HostedType holder; @@ -95,14 +99,13 @@ public final class HostedMethod extends HostedElement implements SharedMethod, W * However, within the open type world, each type and interface has a unique table, so this * index is relative to the start of the appropriate table. */ - int vtableIndex = -1; + int vtableIndex = MISSING_VTABLE_IDX; /** * The address offset of the compiled code relative to the code of the first method in the * buffer. */ - private int codeAddressOffset; - private boolean codeAddressOffsetValid; + private int codeAddressOffset = INVALID_CODE_ADDRESS_OFFSET; private boolean compiled; private boolean compiledInPriorLayer; @@ -227,10 +230,9 @@ public String getQualifiedName() { public void setCodeAddressOffset(int address) { assert isCompiled(); - assert !codeAddressOffsetValid; + assert codeAddressOffset == INVALID_CODE_ADDRESS_OFFSET && address != INVALID_CODE_ADDRESS_OFFSET : Assertions.errorMessage(codeAddressOffset, address); codeAddressOffset = address; - codeAddressOffsetValid = true; } /** @@ -238,14 +240,14 @@ public void setCodeAddressOffset(int address) { * the buffer. */ public int getCodeAddressOffset() { - if (!codeAddressOffsetValid) { + if (!isCodeAddressOffsetValid()) { throw VMError.shouldNotReachHere(format("%H.%n(%p)") + ": has no code address offset set."); } return codeAddressOffset; } public boolean isCodeAddressOffsetValid() { - return codeAddressOffsetValid; + return codeAddressOffset != INVALID_CODE_ADDRESS_OFFSET; } public void setCompiled() { @@ -347,12 +349,12 @@ public boolean isSnippet() { } public boolean hasVTableIndex() { - return vtableIndex != -1; + return vtableIndex != MISSING_VTABLE_IDX; } @Override public int getVTableIndex() { - assert vtableIndex != -1 : "Missing vtable index for method " + this.format("%H.%n(%p)"); + assert vtableIndex != MISSING_VTABLE_IDX : "Missing vtable index for method " + this.format("%H.%n(%p)"); return vtableIndex; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethodNameFactory.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethodNameFactory.java index cc4fbcd36665..48175743e9b0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethodNameFactory.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethodNameFactory.java @@ -51,8 +51,8 @@ public static final class Options { private Map methodNameCount = new ConcurrentHashMap<>(); private Set uniqueShortNames = ConcurrentHashMap.newKeySet(); private final boolean buildingExtensionLayer = ImageLayerBuildingSupport.buildingExtensionLayer(); - private Set reservedUniqueShortNames = buildingExtensionLayer ? HostedDynamicLayerInfo.singleton().getReservedNames() : null; private final boolean logUniqueNameInconsistencies = Options.LogUniqueNameInconsistencies.getValue(); + private Set reservedUniqueShortNames; public record MethodNameInfo(String name, String uniqueShortName) { } @@ -68,7 +68,7 @@ public static HostedMethodNameFactory singleton() { } MethodNameInfo createNames(NameGenerator generator, AnalysisMethod aMethod) { - MethodNameInfo result = buildingExtensionLayer ? HostedDynamicLayerInfo.singleton().loadMethodNameInfo(aMethod) : null; + MethodNameInfo result = buildingExtensionLayer ? HostedDynamicLayerInfo.loadMethodNameInfo(aMethod) : null; if (result != null) { assert reservedUniqueShortNames.contains(result.uniqueShortName()) : result; if (logUniqueNameInconsistencies) { @@ -107,6 +107,11 @@ MethodNameInfo createNames(NameGenerator generator, AnalysisMethod aMethod) { return result; } + @Override + public void afterAnalysis(AfterAnalysisAccess access) { + reservedUniqueShortNames = buildingExtensionLayer ? HostedDynamicLayerInfo.singleton().getReservedNames() : null; + } + @Override public void afterCompilation(AfterCompilationAccess access) { methodNameCount = null; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedType.java index fd263f73841b..bfdd7004d9a3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedType.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedType.java @@ -45,6 +45,8 @@ public abstract class HostedType extends HostedElement implements SharedType, WrappedJavaType, OriginalClassProvider { + public static final int INVALID_TYPECHECK_ID = -1; + public static final HostedType[] EMPTY_ARRAY = new HostedType[0]; protected final HostedUniverse universe; @@ -147,7 +149,7 @@ public HostedType(HostedUniverse universe, AnalysisType wrapped, JavaKind kind, this.storageKind = storageKind; this.superClass = superClass; this.interfaces = interfaces; - this.typeID = -1; + this.typeID = INVALID_TYPECHECK_ID; } public HostedType getStrengthenStampType() { @@ -180,7 +182,7 @@ public HostedMethod[] getVTable() { @Override public int getTypeID() { - assert typeID != -1; + assert typeID != INVALID_TYPECHECK_ID; return typeID; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/TypeCheckBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/TypeCheckBuilder.java index a1f8b16f3b44..05325eb950ee 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/TypeCheckBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/TypeCheckBuilder.java @@ -165,7 +165,8 @@ public static int buildTypeMetadata(HostedUniverse hUniverse, Collection generateDispatchTable(HostedType type, int startingIn } if (openHubUtils.shouldRegisterType(type)) { - LayeredDispatchTableSupport.singleton().registerDeclaredDispatchInfo(type, table); + LayeredDispatchTableFeature.singleton().registerDeclaredDispatchInfo(type, table); } return table; @@ -287,7 +287,7 @@ private void generateOpenTypeWorldDispatchTable(HostedInstanceClass type, Map