Skip to content

Commit

Permalink
[GR-53704] Persist Layer Typecheck Info.
Browse files Browse the repository at this point in the history
PullRequest: graal/17636
  • Loading branch information
teshull committed May 1, 2024
2 parents 275b7d6 + 6ea5eec commit e8632d9
Show file tree
Hide file tree
Showing 11 changed files with 211 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ public final class DynamicHubSupport {
@UnknownPrimitiveField(availability = AfterHostedUniverse.class) private int maxTypeId;
@UnknownObjectField(availability = AfterHostedUniverse.class) private byte[] referenceMapEncoding;

public static DynamicHubSupport singleton() {
return ImageSingletons.lookup(DynamicHubSupport.class);
}

@Platforms(Platform.HOSTED_ONLY.class)
public DynamicHubSupport() {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
*/
package com.oracle.svm.core.layeredimagesingleton;

import java.util.List;

public interface ImageSingletonLoader {
int readInt(String keyName);

List<Integer> readIntList(String keyName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
*/
package com.oracle.svm.core.layeredimagesingleton;

import java.util.List;

public interface ImageSingletonWriter {
void writeInt(String keyName, int value);

void writeIntList(String keyName, List<Integer> value);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
*/
package com.oracle.svm.core.layeredimagesingleton;

import org.graalvm.nativeimage.ImageSingletons;

import java.util.Set;

public class LoadedLayeredImageSingletonInfo {
Expand All @@ -37,4 +39,8 @@ public LoadedLayeredImageSingletonInfo(Set<Class<?>> loadedKeys) {
public boolean handledDuringLoading(Class<?> key) {
return loadedKeys.contains(key);
}

public static LoadedLayeredImageSingletonInfo singleton() {
return ImageSingletons.lookup(LoadedLayeredImageSingletonInfo.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,44 @@
*/
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.List;
import java.util.Map;
import java.util.Objects;

import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.hosted.Feature;

import com.oracle.svm.core.SubstrateOptions;
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
import com.oracle.svm.core.feature.InternalFeature;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.hub.DynamicHubSupport;
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.LoadedLayeredImageSingletonInfo;
import com.oracle.svm.hosted.meta.HostedType;

import jdk.graal.compiler.debug.Assertions;

@AutomaticallyRegisteredFeature
public class OpenTypeWorldFeature implements InternalFeature {

@Override
public boolean isInConfiguration(Feature.IsInConfigurationAccess access) {
return !SubstrateOptions.closedTypeWorld();
}

@Override
public void beforeUniverseBuilding(BeforeUniverseBuildingAccess access) {
if (SVMImageLayerSupport.singleton().persistImageSingletons() && !LoadedLayeredImageSingletonInfo.singleton().handledDuringLoading(LayerTypeInfo.class)) {
ImageSingletons.add(LayerTypeInfo.class, new LayerTypeInfo());
}
}

@Override
Expand All @@ -49,4 +72,136 @@ public void beforeCompilation(BeforeCompilationAccess access) {
impl.registerAsImmutable(hub.getOpenTypeWorldTypeCheckSlots());
}
}

public static int loadTypeInfo(Collection<HostedType> types) {
if (ImageSingletons.contains(LayerTypeInfo.class) && SVMImageLayerSupport.singleton().loadAnalysis()) {
/*
* Load analysis must be enabled or otherwise the same Analysis Type id will not be
* reassigned across layers.
*/
return ImageSingletons.lookup(LayerTypeInfo.class).loadTypeID(types);
}

return 0;
}

public static void persistTypeInfo(Collection<HostedType> types) {
if (ImageSingletons.contains(LayerTypeInfo.class)) {
ImageSingletons.lookup(LayerTypeInfo.class).persistTypeInfo(types);
}
}

record TypeInfo(int typeID, int numClassTypes, int numInterfaceTypes, int[] typecheckSlots) {
private List<Integer> toIntList() {
ArrayList<Integer> list = new ArrayList<>();
list.add(typeID);
list.add(numClassTypes);
list.add(numInterfaceTypes);
Arrays.stream(typecheckSlots).forEach(list::add);

return list;
}

private static TypeInfo fromIntList(List<Integer> 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 TypeInfo(typeID, numClassTypes, numInterfaceTypes, typecheckSlots);
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
TypeInfo typeInfo = (TypeInfo) o;
return typeID == typeInfo.typeID && numClassTypes == typeInfo.numClassTypes && numInterfaceTypes == typeInfo.numInterfaceTypes && Arrays.equals(typecheckSlots, typeInfo.typecheckSlots);
}

@Override
public int hashCode() {
int result = Objects.hash(typeID, numClassTypes, numInterfaceTypes);
result = 31 * result + Arrays.hashCode(typecheckSlots);
return result;
}
}

private static class LayerTypeInfo implements LayeredImageSingleton {
Map<Integer, TypeInfo> identifierToTypeInfo = new HashMap<>();
int maxTypeID = 0;

public int loadTypeID(Collection<HostedType> types) {
ArrayList<Integer> usedIDs = new ArrayList<>();
for (HostedType type : types) {
int identifierID = type.getWrapped().getId();
TypeInfo info = identifierToTypeInfo.get(identifierID);
if (info != null) {
usedIDs.add(info.typeID);
type.loadTypeID(info.typeID);
}
}

return maxTypeID;
}

public void persistTypeInfo(Collection<HostedType> types) {
for (HostedType type : types) {
if (type.getTypeID() != -1) {
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 TypeInfo(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<ImageBuilderFlags> getImageBuilderFlags() {
return EnumSet.of(ImageBuilderFlags.BUILDTIME_ACCESS);
}

@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 identifierIDs = identifierToTypeInfo.keySet().stream().sorted().toList();
writer.writeIntList("identifierIDs", identifierIDs);
writer.writeInt("maxTypeID", DynamicHubSupport.singleton().getMaxTypeId());

for (int identifierID : identifierIDs) {
var typeInfo = identifierToTypeInfo.get(identifierID);
writer.writeIntList(Integer.toString(identifierID), typeInfo.toIntList());
}

return PersistFlags.CREATE;
}

@SuppressWarnings("unused")
public static Object createFromLoader(ImageSingletonLoader loader) {
var info = new LayerTypeInfo();
info.maxTypeID = loader.readInt("maxTypeID");
List<Integer> identifierIDs = loader.readIntList("identifierIDs");
for (var identifierID : identifierIDs) {
var previous = info.identifierToTypeInfo.put(identifierID, TypeInfo.fromIntList(loader.readIntList(Integer.toString(identifierID))));
assert previous == null : previous;
}
return info;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -260,4 +260,12 @@ public int readInt(String keyName) {
assert type.equals("I") : type;
return cast(value.get(1));
}

@Override
public List<Integer> readIntList(String keyName) {
List<Object> value = cast(keyStore.get(keyName));
String type = cast(value.get(0));
assert type.equals("I[]") : type;
return cast(value.get(1));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -250,4 +250,9 @@ EconomicMap<String, Object> getKeyValueStore() {
public void writeInt(String keyName, int value) {
keyValueStore.put(keyName, List.of("I", value));
}

@Override
public void writeIntList(String keyName, List<Integer> value) {
keyValueStore.put(keyName, List.of("I[]", value));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public void duringSetup(DuringSetupAccess c) {
@Override
public void beforeCompilation(BeforeCompilationAccess a) {
// Reserve slot 0 for error-catcher.
int mapSize = ImageSingletons.lookup(DynamicHubSupport.class).getMaxTypeId() + 1;
int mapSize = DynamicHubSupport.singleton().getMaxTypeId() + 1;

// Create trace-ID map with fixed size.
ImageSingletons.lookup(JfrTraceIdMap.class).initialize(mapSize);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public abstract class HostedType extends HostedElement implements SharedType, Wr
protected HostedType[] subTypes;
protected HostedField[] staticFields;

boolean loadedFromPriorLayer;
protected int typeID;
protected HostedType uniqueConcreteImplementation;
protected HostedMethod[] allDeclaredMethods;
Expand Down Expand Up @@ -263,6 +264,11 @@ public HostedType getUniqueConcreteImplementation() {
return uniqueConcreteImplementation;
}

public void loadTypeID(int newTypeID) {
this.typeID = newTypeID;
this.loadedFromPriorLayer = true;
}

@Override
public DynamicHub getHub() {
return universe.hostVM().dynamicHub(wrapped);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,11 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;

import org.graalvm.nativeimage.ImageSingletons;

import com.oracle.svm.core.SubstrateOptions;
import com.oracle.svm.core.graal.snippets.OpenTypeWorldSnippets;
import com.oracle.svm.core.hub.DynamicHubSupport;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.hosted.OpenTypeWorldFeature;

import jdk.graal.compiler.core.common.calc.UnsignedMath;

Expand Down Expand Up @@ -157,12 +156,15 @@ public final class TypeCheckBuilder {

public static int buildTypeMetadata(HostedUniverse hUniverse, Collection<HostedType> types, HostedType objectType, HostedType cloneableType, HostedType serializableType) {
var builder = new TypeCheckBuilder(types, objectType, cloneableType, serializableType);
builder.buildTypeInformation(hUniverse);
if (SubstrateOptions.closedTypeWorld()) {
builder.buildTypeInformation(hUniverse, 0);
builder.calculateClosedTypeWorldTypeMetadata();
return builder.getNumTypeCheckSlots();
} else {
int startingTypeID = OpenTypeWorldFeature.loadTypeInfo(builder.heightOrderedTypes);
builder.buildTypeInformation(hUniverse, startingTypeID);
builder.calculateOpenTypeWorldTypeMetadata();
OpenTypeWorldFeature.persistTypeInfo(builder.heightOrderedTypes);
return UNINITIALIZED_TYPECHECK_SLOTS;
}
}
Expand Down Expand Up @@ -447,18 +449,22 @@ private HostedType getHighestDimArrayType(HostedType type, int dimMax) {
*
* The stamps are calculated by performing a dataflow analysis of the {@link #subtypeMap}.
*/
public void buildTypeInformation(HostedUniverse hUniverse) {
public void buildTypeInformation(HostedUniverse hUniverse, int startingTypeID) {
hUniverse.orderedTypes = heightOrderedTypes;
ImageSingletons.lookup(DynamicHubSupport.class).setMaxTypeId(heightOrderedTypes.size());

for (int i = 0; i < heightOrderedTypes.size(); i++) {
HostedType type = heightOrderedTypes.get(i);
boolean uninitialized = type.typeID == -1 && type.subTypes == null;
VMError.guarantee(uninitialized, "Type initialized multiple times: %s", type);
type.typeID = i;
int nextTypeID = startingTypeID;
for (HostedType type : heightOrderedTypes) {
if (type.typeID != -1) {
assert type.loadedFromPriorLayer && type.typeID < startingTypeID : "Type initialized multiple times: " + type;
} else {
type.typeID = nextTypeID++;
}
VMError.guarantee(type.subTypes == null, "Type initialized multiple times: %s", type);
type.subTypes = subtypeMap.get(type).toArray(HostedType.EMPTY_ARRAY);
}

DynamicHubSupport.singleton().setMaxTypeId(nextTypeID);

/*
* Search through list in reverse order so that all of a type's subtypes are traversed
* before itself.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
import java.util.function.Function;
import java.util.stream.Collectors;

import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.c.function.CEntryPointLiteral;
import org.graalvm.nativeimage.c.function.CFunction;
Expand Down Expand Up @@ -94,6 +93,7 @@
import com.oracle.svm.hosted.NativeImageOptions;
import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport;
import com.oracle.svm.hosted.annotation.CustomSubstitutionMethod;
import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
import com.oracle.svm.hosted.config.DynamicHubLayout;
import com.oracle.svm.hosted.config.HybridLayout;
import com.oracle.svm.hosted.heap.PodSupport;
Expand Down Expand Up @@ -856,7 +856,7 @@ private void buildHubs() {
referenceMaps.put(type, referenceMap);
referenceMapEncoder.add(referenceMap);
}
ImageSingletons.lookup(DynamicHubSupport.class).setReferenceMapEncoding(referenceMapEncoder.encodeAll());
DynamicHubSupport.singleton().setReferenceMapEncoding(referenceMapEncoder.encodeAll());

ObjectLayout ol = ConfigurationValues.getObjectLayout();
DynamicHubLayout dynamicHubLayout = DynamicHubLayout.singleton();
Expand Down

0 comments on commit e8632d9

Please sign in to comment.