vmdefaultheap.java

来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 349 行

JAVA
349
字号
/*
 * $Id: VmDefaultHeap.java,v 1.5 2004/02/24 08:04:41 epr Exp $
 */
package org.jnode.vm.memmgr.def;

import org.jnode.vm.Address;
import org.jnode.vm.ObjectVisitor;
import org.jnode.vm.PragmaUninterruptible;
import org.jnode.vm.classmgr.ObjectFlags;
import org.jnode.vm.classmgr.ObjectLayout;
import org.jnode.vm.classmgr.VmClassType;
import org.jnode.vm.classmgr.VmNormalClass;
import org.jnode.vm.classmgr.VmType;
import org.jnode.vm.memmgr.HeapHelper;

/**
 * @author epr
 */
public class VmDefaultHeap extends VmAbstractHeap implements ObjectFlags {

    /** Offset within this heap of the next free memory block */
    private Address nextFreePtr;

    /** The allocation bitmap as object, so we won't throw it away in a GC cycle */
    private Object allocationBitmap;

    /** The total size of free space */
    private int freeSize;

    /** Offset (in bytes) from the start of an object to the size of an object */
    private int sizeOffset;

    /**
     * Initialize this instance
     * 
     * @param heapMgr
     */
    public VmDefaultHeap(DefaultHeapManager heapMgr) {
        super(heapMgr.getHelper());
    }

    /**
     * Setup the heap object according to the given start-address of the heap.
     * 
     * @param start
     * @param heapClass
     * @param slotSize
     * @return the heap
     */
    protected static VmAbstractHeap setupHeap(HeapHelper helper, Address start,
            VmNormalClass heapClass, int slotSize) {
        final int headerSize = ObjectLayout
                .objectAlign((ObjectLayout.HEADER_SLOTS + 1) * slotSize);
        //final int flagsOffset = ObjectLayout.FLAGS_SLOT * slotSize;
        final int vmtOffset = ObjectLayout.TIB_SLOT * slotSize;
        final int sizeOffset = -((ObjectLayout.HEADER_SLOTS + 1) * slotSize);
        final int flagsOffset = ObjectLayout.FLAGS_SLOT * slotSize;

        // Setup a heap object, so the heap can initialize itself.
        Address heapPtr = Address.add(start, headerSize);
        final int heapObjSize = ObjectLayout.objectAlign(heapClass
                .getObjectSize());
        helper.setInt(heapPtr, sizeOffset, heapObjSize);
        helper.setInt(heapPtr, flagsOffset, ObjectFlags.GC_DEFAULT_COLOR);
        helper.setObject(heapPtr, vmtOffset, heapClass.getTIB());
        helper.clear(heapPtr, heapObjSize);

        VmDefaultHeap heap = (VmDefaultHeap) helper.objectAt(heapPtr);
        heap.helper = helper;
        return heap;
    }

    /**
     * Initialize this heap
     * 
     * @param start
     *            Start address of this heap
     * @param end
     *            End address of this heap (first address after this heap)
     * @param slotSize
     */
    protected void initialize(Address start, Address end, int slotSize) {

        // Set my variables
        this.start = start;
        this.end = end;
        initializeAbstract(slotSize);
        this.sizeOffset = -((ObjectLayout.HEADER_SLOTS + 1) * slotSize);
        this.headerSize = ObjectLayout.objectAlign(this.headerSize + slotSize);
        final int size = getSize();

        final int mySize = helper.getInt(this, sizeOffset);
        final Address myAddr = helper.addressOf(this);
        Address firstObject;
        if (inHeap(myAddr)) {
            firstObject = Address.add(myAddr, mySize + headerSize);
        } else {
            firstObject = Address.add(start, headerSize);
        }

        // Initialize an allocation bitmap
        final int allocationBits = size / ObjectLayout.OBJECT_ALIGN;
        final int allocationBitmapSize = ObjectLayout
                .objectAlign((allocationBits + 7) / 8);
        this.allocationBitmapPtr = firstObject;
        // Make the bitmap an object, so it is easy to manipulate.
        helper.setInt(allocationBitmapPtr, sizeOffset, allocationBitmapSize);
        helper.setInt(allocationBitmapPtr, flagsOffset, GC_DEFAULT_COLOR);
        helper.setObject(allocationBitmapPtr, tibOffset, VmType
                .getObjectClass().getTIB());
        firstObject = Address.add(firstObject, allocationBitmapSize
                + headerSize);
        helper.clear(allocationBitmapPtr, allocationBitmapSize);
        this.allocationBitmap = helper.objectAt(allocationBitmapPtr);

        // Mark this heap in the allocation bitmap
        setAllocationBit(this, true);
        // Mark the allocation bitmap in the allocation bitmap
        setAllocationBit(allocationBitmap, true);

        // Initialize the remaining space as free object.
        final int remainingSize = (int) Address.distance(end, firstObject);
        final Address ptr = firstObject;
        helper.setInt(ptr, sizeOffset, remainingSize);
        helper.setObject(ptr, tibOffset, FREE);
        this.nextFreePtr = ptr;
        this.freeSize = remainingSize;
    }

    /**
     * Allocate a new instance for the given class. Not that this method cannot
     * be synchronized, since the synchronization is handled in VmHeap.
     * 
     * @param vmClass
     * @param alignedSize
     * @return Object Null if no space is left.
     */
    protected Object alloc(VmClassType vmClass, int alignedSize) {

        if (nextFreePtr == null) { /* This heap is full */
        return null; }

        final int totalSize = alignedSize + headerSize;
        final Object tib = vmClass.getTIB();
        //final int size = getSize();
        final int tibOffset = this.tibOffset;
        final int headerSize = this.headerSize;

        Address objectPtr = null;
        lock();
        try {
            // Search for the first free block that is large enough
            //Screen.debug("a");
            while (objectPtr == null) {
                final Address ptr = nextFreePtr;
                final int objSize = helper.getInt(ptr, sizeOffset);
                final Object objVmt = helper.getObject(ptr, tibOffset);
                final Address nextPtr = Address.add(ptr, objSize + headerSize);
                if ((objVmt == FREE) && (alignedSize <= objSize)) {
                    objectPtr = ptr;
                } else {
                    if (!inHeap(nextPtr)) {
                        // No large enough free space has been found
                        // A collect may recover smaller free spaces in this
                        // heap, but we leave that to a GC iteration.
                        nextFreePtr = null;
                        //Screen.debug("B");
                        return null;
                    } else {
                        this.nextFreePtr = nextPtr;
                    }
                }
            }
            //Screen.debug("A");

            final int curFreeSize = helper.getInt(objectPtr, sizeOffset);
            if (curFreeSize > totalSize) {
                // Block is larger then we need, split it up.
                final int newFreeSize = curFreeSize - totalSize;
                final Address newFreePtr = Address.add(objectPtr, totalSize);
                // Set the header for the remaining free block
                helper.setInt(newFreePtr, sizeOffset, newFreeSize);
                helper.setInt(newFreePtr, flagsOffset, 0);
                helper.setObject(newFreePtr, tibOffset, FREE);
                // Set the next free offset
                nextFreePtr = newFreePtr;
            } else {
                // The block is not large enough to split up, make the
                // new object the size of the free block.
                alignedSize = curFreeSize;
            }

            // Create the object header
            helper.setInt(objectPtr, sizeOffset, alignedSize);
            helper.setInt(objectPtr, flagsOffset, 0);
            helper.setObject(objectPtr, tibOffset, tib);
            // Mark the object in the allocation bitmap
            setAllocationBit(objectPtr, true);

            // Fix the freeSize
            freeSize -= alignedSize;
        } finally {
            unlock();
        }

        // Clear the contents of the object.
        helper.clear(objectPtr, alignedSize);

        return helper.objectAt(objectPtr);
    }

    /**
     * Mark the given object as free space.
     * 
     * @param object
     */
    protected final void free(Object object) {
        lock();
        try {
            final int objSize = helper.getInt(object, sizeOffset);
            helper.setObject(object, tibOffset, FREE);
            setAllocationBit(object, false);
            freeSize += objSize;
        } finally {
            unlock();
        }
    }

    /**
     * @see VmAbstractHeap#getFreeSize()
     * @return The free size
     */
    protected int getFreeSize() {
        return freeSize;
    }

    /**
     * Join all adjacent free spaces.
     * 
     * @throws PragmaUninterruptible
     */
    protected final void defragment() throws PragmaUninterruptible {
        final int size = getSize();
        int offset = headerSize;

        lock();
        try {
            Address firstFreePtr = null;
            while (offset < size) {
                final Address ptr = Address.add(start, offset);
                final Object object = helper.objectAt(ptr);
                final int objSize = helper.getInt(object, sizeOffset);
                final int nextOffset = offset + objSize + headerSize;
                final Object vmt = helper.getObject(object, tibOffset);
                if ((firstFreePtr == null) && (vmt == FREE)) {
                    firstFreePtr = ptr;
                }
                if ((vmt == FREE) && (nextOffset < size)) {
                    final Object nextObject;
                    final Object nextVmt;
                    nextObject = helper
                            .objectAt(Address.add(start, nextOffset));
                    nextVmt = helper.getObject(nextObject, tibOffset);
                    if (nextVmt == FREE) {
                        // Combine two free spaces
                        int nextObjSize = helper.getInt(nextObject, sizeOffset);
                        int newObjSize = objSize + headerSize + nextObjSize;
                        helper.setInt(object, sizeOffset, newObjSize);
                        // Do not increment offset here, because there may be
                        // another next free object, which we will combine
                        // in the next loop.
                    } else {
                        offset = nextOffset;
                    }
                } else {
                    offset = nextOffset;
                }
            }
            // Set the address of the next free block, to the first free block
            this.nextFreePtr = firstFreePtr;
        } finally {
            unlock();
        }
    }

    /**
     * Let all objects in this heap make a visit to the given visitor.
     * 
     * @param visitor
     * @param locking
     *            If true, use lock/unlock while proceeding to the next object.
     */
    protected final void walk(ObjectVisitor visitor, boolean locking,
            int flagsMask, int flagsValue) {
        // Go through the heap and call visit on each object
        final int headerSize = this.headerSize;
        final int sizeOffset = this.sizeOffset;
        final Object FREE = this.FREE;
        int offset = headerSize;
        final int size = getSize();

        if (locking) {
            while (offset < size) {
                final Object tib;
                final Object object;
                final int objSize;
                final int flags;

                lock();
                try {
                    final Address ptr = Address.add(start, offset);
                    object = helper.objectAt(ptr);
                    tib = helper.getObject(object, tibOffset);
                    objSize = helper.getInt(object, sizeOffset);
                    flags = (flagsMask == 0) ? 0 : (helper.getObjectFlags(object) & flagsMask);
                } finally {
                    unlock();
                }
                if (tib != FREE) {
                    if (flags == flagsValue) {
                        if (!visitor.visit(object)) {
                            // Stop
                            offset = size;
                        }
                    }
                }
                offset += objSize + headerSize;
            }
        } else {
            while (offset < size) {
                final Address ptr = Address.add(start, offset);
                final Object object = helper.objectAt(ptr);
                final Object tib = helper.getObject(object, tibOffset);
                final int objSize = helper.getInt(object, sizeOffset);
                final int flags = (flagsMask == 0) ? 0 : (helper.getObjectFlags(object) & flagsMask);
                if (tib != FREE) {
                    if (flags == flagsValue) {
                        if (!visitor.visit(object)) {
                            // Stop
                            offset = size;
                        }
                    }
                }
                offset += objSize + headerSize;
            }
        }
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?