All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.qbicc.plugin.serialization.BuildtimeHeap Maven / Gradle / Ivy

There is a newer version: 0.77.0
Show newest version
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