org.qbicc.plugin.serialization.BuildtimeHeap Maven / Gradle / Ivy
package org.qbicc.plugin.serialization;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
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.CompilationContext;
import org.qbicc.graph.literal.BooleanLiteral;
import org.qbicc.graph.literal.Literal;
import org.qbicc.graph.literal.LiteralFactory;
import org.qbicc.graph.literal.ProgramObjectLiteral;
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.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.Section;
import org.qbicc.plugin.coreclasses.CoreClasses;
import org.qbicc.plugin.layout.Layout;
import org.qbicc.plugin.layout.LayoutInfo;
import org.qbicc.pointer.Pointer;
import org.qbicc.pointer.ProgramObjectPointer;
import org.qbicc.pointer.StaticMethodPointer;
import org.qbicc.type.ArrayType;
import org.qbicc.type.ClassObjectType;
import org.qbicc.type.CompoundType;
import org.qbicc.type.FloatType;
import org.qbicc.type.IntegerType;
import org.qbicc.type.PhysicalObjectType;
import org.qbicc.type.PointerType;
import org.qbicc.type.Primitive;
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.WordType;
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.MethodElement;
import static org.qbicc.graph.atomic.AccessModes.SinglePlain;
public class BuildtimeHeap {
private static final AttachmentKey KEY = new AttachmentKey<>();
private static final String prefix = "qbicc_initial_heap_obj_";
private static final Logger slog = Logger.getLogger("org.qbicc.plugin.serialization.stats");
private final CompilationContext ctxt;
private final Layout interpreterLayout;
private final CoreClasses coreClasses;
/**
* For lazy definition of native array types for literals
*/
private final HashMap arrayTypes = new HashMap<>();
/**
* For interning java.lang.Class instances
*/
private final HashMap classObjects = new HashMap<>();
/**
* For interning java.lang.Class instances that correspond to Primitives
*/
private final HashMap primitiveClassObjects = new HashMap<>();
/**
* For interning VmObjects
*/
private final IdentityHashMap vmObjects = new IdentityHashMap<>();
/**
* The initial heap
*/
private final Section heapSection;
/**
* The global array of java.lang.Class instances that is part of the serialized heap
*/
private GlobalVariableElement classArrayGlobal;
private int literalCounter = 0;
private BuildtimeHeap(CompilationContext ctxt) {
this.ctxt = ctxt;
this.interpreterLayout = Layout.get(ctxt);
this.coreClasses = CoreClasses.get(ctxt);
LoadedTypeDefinition ih = ctxt.getBootstrapClassContext().findDefinedType("org/qbicc/runtime/main/InitialHeap").load();
this.heapSection = ctxt.getOrAddProgramModule(ih).getOrAddSection(ctxt.IMPLICIT_SECTION_NAME); // TODO: use ctxt.INITIAL_HEAP_SECTION_NAME
}
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 setClassArrayGlobal(GlobalVariableElement g) {
this.classArrayGlobal = g;
}
public GlobalVariableElement getAndRegisterGlobalClassArray(ExecutableElement originalElement) {
Assert.assertNotNull(classArrayGlobal);
if (!classArrayGlobal.getEnclosingType().equals(originalElement.getEnclosingType())) {
Section section = ctxt.getImplicitSection(originalElement.getEnclosingType());
section.declareData(null, classArrayGlobal.getName(), classArrayGlobal.getType());
}
return classArrayGlobal;
}
public ProgramObjectLiteral getSerializedVmObject(VmObject value) {
return vmObjects.get(value);
}
public synchronized ProgramObjectLiteral serializeVmObject(VmObject value) {
if (vmObjects.containsKey(value)) {
return vmObjects.get(value);
}
Layout layout = Layout.get(ctxt);
PhysicalObjectType ot = value.getObjectType();
ProgramObjectLiteral sl;
if (ot instanceof ClassObjectType) {
// Could be part of a cyclic object graph; must record the symbol for this object before we serialize its fields
LoadedTypeDefinition concreteType = ot.getDefinition().load();
LayoutInfo objLayout = layout.getInstanceLayoutInfo(concreteType);
String name = nextLiteralName();
// declare it
DataDeclaration decl = heapSection.declareData(null, name, objLayout.getCompoundType());
decl.setAddrspace(1);
sl = ctxt.getLiteralFactory().literalOf(decl);
vmObjects.put(value, sl);
serializeVmObject(concreteType, objLayout, sl, value);
} else if (ot instanceof ReferenceArrayObjectType) {
// Could be part of a cyclic object graph; must record the symbol for this array before we serialize its elements
FieldElement contentsField = coreClasses.getRefArrayContentField();
LayoutInfo info = layout.getInstanceLayoutInfo(contentsField.getEnclosingType());
Memory memory = value.getMemory();
int length = memory.load32(info.getMember(coreClasses.getArrayLengthField()).getOffset(), SinglePlain);
CompoundType literalCT = arrayLiteralType(contentsField, length);
// declare it
DataDeclaration decl = heapSection.declareData(null, nextLiteralName(), literalCT);
decl.setAddrspace(1);
sl = ctxt.getLiteralFactory().literalOf(decl);
vmObjects.put(value, sl);
serializeRefArray((ReferenceArrayObjectType) ot, literalCT, length, sl, (VmArray)value);
} else {
// Can't be cyclic; ok to serialize then record the ref.
sl = serializePrimArray((PrimitiveArrayObjectType) ot, (VmArray)value);
vmObjects.put(value, sl);
}
vmObjects.put(value, sl);
return sl;
}
public synchronized ProgramObjectLiteral serializeClassObject(Primitive primitive) {
if (primitiveClassObjects.containsKey(primitive.getName())) {
return primitiveClassObjects.get(primitive.getName());
}
ProgramObjectLiteral sl = serializeVmObject(ctxt.getVm().getPrimitiveClass(primitive));
if (sl != null) {
primitiveClassObjects.put(primitive.getName(), sl);
}
return sl;
}
public synchronized ProgramObjectLiteral serializeClassObject(LoadedTypeDefinition type) {
if (classObjects.containsKey(type)) {
return classObjects.get(type);
}
VmClass vmClass = type.load().getVmClass();
ProgramObjectLiteral sl = serializeVmObject(vmClass);
if (sl != null) {
classObjects.put(type, sl);
}
return sl;
}
private String nextLiteralName() {
return prefix + (this.literalCounter++);
}
private Data defineData(String name, Literal value) {
Data d = heapSection.addData(null, name, value);
d.setLinkage(Linkage.EXTERNAL);
d.setAddrspace(1);
return d;
}
private CompoundType arrayLiteralType(FieldElement contents, int length) {
LoadedTypeDefinition ltd = contents.getEnclosingType().load();
String typeName = ltd.getInternalName() + "_" + length;
CompoundType sizedArrayType = arrayTypes.get(typeName);
Layout layout = Layout.get(ctxt);
if (sizedArrayType == null) {
TypeSystem ts = ctxt.getTypeSystem();
LayoutInfo objLayout = layout.getInstanceLayoutInfo(ltd);
CompoundType arrayCT = objLayout.getCompoundType();
CompoundType.Member contentMem = objLayout.getMember(contents);
ArrayType sizedContentMem = ts.getArrayType(((ArrayType) contents.getType()).getElementType(), length);
CompoundType.Member realContentMem = ts.getCompoundTypeMember(contentMem.getName(), sizedContentMem, contentMem.getOffset(), contentMem.getAlign());
Supplier> 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, ProgramObjectLiteral sl, VmObject value) {
Memory memory = value.getMemory();
LayoutInfo memLayout = interpreterLayout.getInstanceLayoutInfo(concreteType);
CompoundType objType = objLayout.getCompoundType();
HashMap memberMap = new HashMap<>();
populateMemberMap(concreteType, objType, objLayout, memLayout, memory, memberMap);
// Define it!
defineData(sl.getName(), 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) {
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);
}
private void populateClearedMemberMap(final LoadedTypeDefinition concreteType, final LayoutInfo objLayout, final LayoutInfo memLayout, final Memory memory, final HashMap memberMap) {
if (concreteType.hasSuperClass()) {
populateClearedMemberMap(concreteType.getSuperClass(), objLayout, memLayout, memory, memberMap);
}
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) {
VmObject contents = memory.loadRef(im.getOffset(), SinglePlain);
if (contents == null) {
memberMap.put(om, lf.zeroInitializerLiteralOfType(om.getType()));
} else {
memberMap.put(om, lf.bitcastLiteral(serializeVmObject(contents), (WordType) om.getType()));
}
} 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
MethodElement method = smp.getStaticMethod();
ctxt.enqueue(method);
Function function = ctxt.getExactFunction(method);
FunctionDeclaration decl = heapSection.declareFunction(function);
memberMap.put(om, lf.bitcastLiteral(lf.literalOf(ProgramObjectPointer.of(decl)), smp.getType()));
} else {
memberMap.put(om, lf.literalOf(pointer));
}
} else {
throw new UnsupportedOperationException("Serialization of unsupported member type: " + im.getType());
}
}
}
private void serializeRefArray(ReferenceArrayObjectType at, CompoundType literalCT, int length, ProgramObjectLiteral 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 = interpreterLayout.getInstanceLayoutInfo(concreteType);
CompoundType objType = objLayout.getCompoundType();
HashMap memberMap = new HashMap<>();
populateMemberMap(concreteType.load(), objType, objLayout, memLayout, memory, memberMap);
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);
// add the actual array contents
memberMap.put(literalCT.getMember(literalCT.getMemberCount() - 1), arrayContentsLiteral);
Data arrayData = defineData(nextLiteralName(), ctxt.getLiteralFactory().literalOf(literalCT, memberMap));
return lf.literalOf(arrayData);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy