org.qbicc.plugin.serialization.BuildtimeHeap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of qbicc-plugin-serialization Show documentation
Show all versions of qbicc-plugin-serialization Show documentation
Support for serializing the build time heap
package org.qbicc.plugin.serialization;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import io.smallrye.common.constraint.Assert;
import org.jboss.logging.Logger;
import org.qbicc.context.AttachmentKey;
import org.qbicc.context.ClassContext;
import org.qbicc.context.CompilationContext;
import org.qbicc.graph.OffsetOfField;
import org.qbicc.graph.Value;
import org.qbicc.graph.literal.BooleanLiteral;
import org.qbicc.graph.literal.Literal;
import org.qbicc.graph.literal.LiteralFactory;
import org.qbicc.graph.literal.ObjectLiteral;
import org.qbicc.graph.literal.ZeroInitializerLiteral;
import org.qbicc.interpreter.Memory;
import org.qbicc.interpreter.VmArray;
import org.qbicc.interpreter.VmClass;
import org.qbicc.interpreter.VmObject;
import org.qbicc.interpreter.VmReferenceArray;
import org.qbicc.interpreter.VmReferenceArrayClass;
import org.qbicc.interpreter.memory.ByteArrayMemory;
import org.qbicc.object.Data;
import org.qbicc.object.DataDeclaration;
import org.qbicc.object.Function;
import org.qbicc.object.FunctionDeclaration;
import org.qbicc.object.Linkage;
import org.qbicc.object.ModuleSection;
import org.qbicc.object.ProgramModule;
import org.qbicc.object.ProgramObject;
import org.qbicc.object.Section;
import org.qbicc.plugin.constants.Constants;
import org.qbicc.plugin.coreclasses.CoreClasses;
import org.qbicc.plugin.layout.Layout;
import org.qbicc.plugin.layout.LayoutInfo;
import org.qbicc.pointer.IntegerAsPointer;
import org.qbicc.pointer.MemoryPointer;
import org.qbicc.pointer.Pointer;
import org.qbicc.pointer.ProgramObjectPointer;
import org.qbicc.pointer.StaticFieldPointer;
import org.qbicc.pointer.StaticMethodPointer;
import org.qbicc.type.ArrayType;
import org.qbicc.type.BooleanType;
import org.qbicc.type.ClassObjectType;
import org.qbicc.type.CompoundType;
import org.qbicc.type.FloatType;
import org.qbicc.type.IntegerType;
import org.qbicc.type.NullableType;
import org.qbicc.type.PhysicalObjectType;
import org.qbicc.type.PointerType;
import org.qbicc.type.PrimitiveArrayObjectType;
import org.qbicc.type.ReferenceArrayObjectType;
import org.qbicc.type.ReferenceType;
import org.qbicc.type.TypeSystem;
import org.qbicc.type.TypeType;
import org.qbicc.type.ValueType;
import org.qbicc.type.definition.DefinedTypeDefinition;
import org.qbicc.type.definition.LoadedTypeDefinition;
import org.qbicc.type.definition.element.ExecutableElement;
import org.qbicc.type.definition.element.FieldElement;
import org.qbicc.type.definition.element.GlobalVariableElement;
import org.qbicc.type.definition.element.StaticFieldElement;
import org.qbicc.type.definition.element.StaticMethodElement;
import org.qbicc.type.descriptor.TypeDescriptor;
import org.qbicc.type.generic.TypeSignature;
import static org.qbicc.graph.atomic.AccessModes.SinglePlain;
public class BuildtimeHeap {
private static final AttachmentKey KEY = new AttachmentKey<>();
private static final Logger slog = Logger.getLogger("org.qbicc.plugin.serialization.stats");
private final CompilationContext ctxt;
private final Layout layout;
private final CoreClasses coreClasses;
/**
* For lazy definition of native array types for literals
*/
private final HashMap arrayTypes = new HashMap<>();
/**
* For interning VmObjects
*/
private final IdentityHashMap vmObjects = new IdentityHashMap<>();
/**
* For interning native memory
*/
private final IdentityHashMap nativeMemory = new IdentityHashMap<>();
/**
* The array of root classes which is intended to be the first object in the initial heap
*/
private final ModuleSection classSection;
/**
* Objects associated with build-time interned Strings.
* These objects can be ignored by GC because (a) they are non-collectable and
* (b) are guaranteed to not contain pointers to objects outside of this section.
* This section includes:
* (a) The root array of all build-time interned Strings
* (b) The java.lang.String instances for all build-time interned Strings
* (c) The backing byte[] for all build-time interned Strings
*/
private final ModuleSection stringSection;
/**
* The rest of the objects in the initial heap
*/
private final ModuleSection objectSection;
/**
* The global array of root java.lang.Class instances
*/
private DataDeclaration rootClassesDecl;
/**
* The values, indexed by typeId to be serialized in the classArrayGlobal
*/
private Literal[] rootClasses;
/**
* The mapping from static fields to global variables
*/
private final Map staticFields = new ConcurrentHashMap<>();
private int literalCounter = 0;
private BuildtimeHeap(CompilationContext ctxt) {
this.ctxt = ctxt;
this.layout = Layout.get(ctxt);
this.coreClasses = CoreClasses.get(ctxt);
this.classSection = ctxt.getImplicitSection(ctxt.getBootstrapClassContext().findDefinedType("org/qbicc/runtime/main/InitialHeap$ClassSection").load());
this.stringSection = ctxt.getImplicitSection(ctxt.getBootstrapClassContext().findDefinedType("org/qbicc/runtime/main/InitialHeap$InternedStringSection").load());
this.objectSection = ctxt.getImplicitSection(ctxt.getBootstrapClassContext().findDefinedType("org/qbicc/runtime/main/InitialHeap$ObjectSection").load());
}
public static BuildtimeHeap get(CompilationContext ctxt) {
BuildtimeHeap heap = ctxt.getAttachment(KEY);
if (heap == null) {
heap = new BuildtimeHeap(ctxt);
BuildtimeHeap appearing = ctxt.putAttachmentIfAbsent(KEY, heap);
if (appearing != null) {
heap = appearing;
}
}
return heap;
}
public static void reportStats(CompilationContext ctxt) {
if (!slog.isDebugEnabled()) return;
BuildtimeHeap heap = ctxt.getAttachment(KEY);
slog.debugf("The initial heap contains %,d objects.", heap.vmObjects.size());
HashMap instanceCounts = new HashMap<>();
for (VmObject obj : heap.vmObjects.keySet()) {
LoadedTypeDefinition ltd = obj.getVmClass().getTypeDefinition();
instanceCounts.put(ltd, instanceCounts.getOrDefault(ltd, 0) + 1);
}
slog.debugf("The types with more than 5 instances are: ");
instanceCounts.entrySet().stream()
.filter(x -> x.getValue() > 5)
.sorted((x, y) -> y.getValue().compareTo(x.getValue()))
.forEach(e -> slog.debugf(" %,6d instances of %s", e.getValue(), e.getKey().getDescriptor()));
}
void initializeRootClassArray(int numTypeIds) {
LoadedTypeDefinition jlc = ctxt.getBootstrapClassContext().findDefinedType("java/lang/Class").load();
CompoundType jlcType = layout.getInstanceLayoutInfo(jlc).getCompoundType();
ArrayType rootArrayType = ctxt.getTypeSystem().getArrayType(jlcType, numTypeIds);
rootClassesDecl = classSection.getProgramModule().declareData(null, "qbicc_jlc_lookup_table", rootArrayType);
rootClasses = new Literal[numTypeIds];
rootClasses[0] = ctxt.getLiteralFactory().zeroInitializerLiteralOfType(jlc.getObjectType()); // TODO: Remove if we assign void typeId 0 instead of using 0 as an invalid typeId
}
void emitRootClassArray() {
Data d = classSection.addData(null, rootClassesDecl.getName(), ctxt.getLiteralFactory().literalOf((ArrayType) rootClassesDecl.getValueType(), List.of(rootClasses)));
d.setLinkage(Linkage.EXTERNAL);
}
void emitRootClassDictionaries(ArrayList rootClasses) {
LoadedTypeDefinition ih = ctxt.getBootstrapClassContext().findDefinedType("org/qbicc/runtime/main/InitialHeap").load();
ModuleSection section = ctxt.getImplicitSection(ih);
LoadedTypeDefinition jls_td = ctxt.getBootstrapClassContext().findDefinedType("java/lang/String").load();
LoadedTypeDefinition jlc_td = ctxt.getBootstrapClassContext().findDefinedType("java/lang/Class").load();
VmClass jls = jls_td.getVmClass();
VmClass jlc = jlc_td.getVmClass();
int nameIdx= jlc.indexOf(jlc_td.findField("name"));
rootClasses.sort(Comparator.comparing(x -> x.getTypeDefinition().getInternalName()));
// Construct and serialize the sorted VmReferenceArray of Strings that are class names
VmObject[] names = new VmObject[rootClasses.size()];
for (int i=0; i> thunk = () -> {
CompoundType.Member[] items = arrayCT.getMembers().toArray(CompoundType.Member[]::new);
for (int i = 0; i < items.length; i++) {
if (items[i] == contentMem) {
items[i] = realContentMem;
}
}
return Arrays.asList(items);
};
sizedArrayType = ts.getCompoundType(CompoundType.Tag.STRUCT, typeName, arrayCT.getSize() + sizedContentMem.getSize(), arrayCT.getAlign(), thunk);
arrayTypes.put(typeName, sizedArrayType);
}
return sizedArrayType;
}
private void serializeVmObject(LoadedTypeDefinition concreteType, LayoutInfo objLayout, VmObject value, ModuleSection into, int typeId, String name) {
Memory memory = value.getMemory();
LayoutInfo memLayout = layout.getInstanceLayoutInfo(concreteType);
CompoundType objType = objLayout.getCompoundType();
HashMap memberMap = new HashMap<>();
populateMemberMap(concreteType, objType, objLayout, memLayout, memory, memberMap, into);
// Define it!
if (typeId == -1) {
defineData(into, name, ctxt.getLiteralFactory().literalOf(objType, memberMap));
} else {
rootClasses[typeId] = ctxt.getLiteralFactory().literalOf(objType, memberMap);
}
}
private void populateMemberMap(final LoadedTypeDefinition concreteType, final CompoundType objType, final LayoutInfo objLayout, final LayoutInfo memLayout, final Memory memory,
final HashMap memberMap, ModuleSection into) {
LiteralFactory lf = ctxt.getLiteralFactory();
// Start by zero-initializing all members
for (CompoundType.Member m : objType.getMembers()) {
memberMap.put(m, lf.zeroInitializerLiteralOfType(m.getType()));
}
populateClearedMemberMap(concreteType, objLayout, memLayout, memory, memberMap, into);
}
private void populateClearedMemberMap(final LoadedTypeDefinition concreteType, final LayoutInfo objLayout, final LayoutInfo memLayout, final Memory memory,
final HashMap memberMap, ModuleSection into) {
if (concreteType.hasSuperClass()) {
populateClearedMemberMap(concreteType.getSuperClass(), objLayout, memLayout, memory, memberMap, into);
}
LiteralFactory lf = ctxt.getLiteralFactory();
// Iterate over declared instance fields and copy values from the backing Memory to the memberMap
int fc = concreteType.getFieldCount();
for (int i=0; i 0) {
throw new UnsupportedOperationException("Copying array data is not yet supported");
}
} else if (im.getType() instanceof ReferenceType rt) {
VmObject contents = memory.loadRef(im.getOffset(), SinglePlain);
if (contents == null) {
memberMap.put(om, lf.zeroInitializerLiteralOfType(om.getType()));
} else {
serializeVmObject(contents, into == classSection ? objectSection : into);
memberMap.put(om, referToSerializedVmObject(contents, rt, into.getProgramModule()));
}
} else if (im.getType() instanceof PointerType pt) {
Pointer pointer = memory.loadPointer(im.getOffset(), SinglePlain);
if (pointer == null) {
memberMap.put(om, lf.nullLiteralOfType(pt));
} else if (pointer instanceof StaticMethodPointer smp) {
// lower method pointers to their corresponding objects
StaticMethodElement method = smp.getStaticMethod();
ctxt.enqueue(method);
Function function = ctxt.getExactFunction(method);
FunctionDeclaration decl = into.getProgramModule().declareFunction(function);
memberMap.put(om, lf.bitcastLiteral(lf.literalOf(ProgramObjectPointer.of(decl)), smp.getType()));
} else if (pointer instanceof StaticFieldPointer sfp) {
// lower static field pointers to their corresponding program objects
StaticFieldElement sfe = sfp.getStaticField();
GlobalVariableElement global = getGlobalForStaticField(sfe);
DataDeclaration decl = into.getProgramModule().declareData(sfe, global.getName(), global.getType());
memberMap.put(om, lf.bitcastLiteral(lf.literalOf(ProgramObjectPointer.of(decl)), sfp.getType()));
} else if (pointer instanceof MemoryPointer mp) {
ctxt.error(f.getLocation(), "An object contains a memory pointer: %s", mp);
} else {
memberMap.put(om, lf.literalOf(pointer));
}
} else {
ctxt.warning("Serializing " + f + " as zero literal. Unsupported type");
memberMap.put(om, lf.zeroInitializerLiteralOfType(im.getType()));
}
}
}
private void serializeRefArray(ReferenceArrayObjectType at, CompoundType literalCT, int length, ModuleSection into, DataDeclaration sl, VmArray value) {
LoadedTypeDefinition jlo = ctxt.getBootstrapClassContext().findDefinedType("java/lang/Object").load();
LiteralFactory lf = ctxt.getLiteralFactory();
Layout layout = Layout.get(ctxt);
Memory memory = value.getMemory();
FieldElement contentField = coreClasses.getRefArrayContentField();
DefinedTypeDefinition concreteType = contentField.getEnclosingType();
LayoutInfo objLayout = layout.getInstanceLayoutInfo(concreteType);
LayoutInfo memLayout = this.layout.getInstanceLayoutInfo(concreteType);
CompoundType objType = objLayout.getCompoundType();
HashMap memberMap = new HashMap<>();
populateMemberMap(concreteType.load(), objType, objLayout, memLayout, memory, memberMap, into);
List elements = new ArrayList<>(length);
VmObject[] elementArray = ((VmReferenceArray) value).getArray();
for (int i=0; i elements = new ArrayList<>(length);
if (contentsField.equals(coreClasses.getBooleanArrayContentField())) {
boolean[] contents = (boolean[]) value.getArray();
for (int i=0; i memberMap = new HashMap<>();
populateMemberMap(concreteType.load(), objType, objLayout, memLayout, memory, memberMap, into);
// add the actual array contents
memberMap.put(literalCT.getMember(literalCT.getMemberCount() - 1), arrayContentsLiteral);
Data arrayData = defineData(into, nextLiteralName(into), ctxt.getLiteralFactory().literalOf(literalCT, memberMap));
return arrayData.getDeclaration();
}
private DataDeclaration serializeNativeMemory(byte[] bytes, ModuleSection into) {
DataDeclaration existing = nativeMemory.get(bytes);
if (existing != null) {
return existing;
}
LiteralFactory lf = ctxt.getLiteralFactory();
Literal memoryLiteral = lf.literalOf(ctxt.getTypeSystem().getArrayType(ctxt.getTypeSystem().getSignedInteger8Type(), bytes.length), bytes);
Data memoryData = defineData(into, nextLiteralName(into), memoryLiteral);
return memoryData.getDeclaration();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy