Package org.jnode.vm.memmgr.def

Source Code of org.jnode.vm.memmgr.def.VmDefaultHeap

/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.vm.memmgr.def;

import org.jnode.vm.VmMagic;
import org.jnode.annotation.Inline;
import org.jnode.annotation.MagicPermission;
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.facade.ObjectVisitor;
import org.jnode.vm.memmgr.HeapHelper;
import org.vmmagic.pragma.UninterruptiblePragma;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.Extent;
import org.vmmagic.unboxed.ObjectReference;
import org.vmmagic.unboxed.Offset;
import org.vmmagic.unboxed.Word;

/**
* @author epr
*/
@MagicPermission
final 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 Extent freeSize;

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

    /**
     * The next heap (linked list)
     */
    private VmDefaultHeap next;

    /**
     * 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 VmDefaultHeap setupHeap(HeapHelper helper, Address start,
                                             VmNormalClass<VmDefaultHeap> heapClass, int slotSize) {
        final int headerSize = ObjectLayout
            .objectAlign((ObjectLayout.HEADER_SLOTS + 1) * slotSize);
        final Offset vmtOffset = Offset.fromIntSignExtend(ObjectLayout.TIB_SLOT * slotSize);
        final Offset sizeOffset = Offset.fromIntSignExtend(-((ObjectLayout.HEADER_SLOTS + 1) * slotSize));
        final Offset flagsOffset = Offset.fromIntSignExtend(ObjectLayout.FLAGS_SLOT * slotSize);

        // Setup a heap object, so the heap can initialize itself.
        final Address heapPtr = start.add(headerSize);
        final Word heapObjSize = Word.fromIntZeroExtend(ObjectLayout.objectAlign(heapClass
            .getObjectSize()));
        final Word flags = Word.fromIntZeroExtend(ObjectFlags.GC_DEFAULT_COLOR);
        heapPtr.store(heapObjSize, sizeOffset);
        heapPtr.store(flags, flagsOffset);
        heapPtr.store(ObjectReference.fromObject(heapClass.getTIB()), vmtOffset);
        helper.clear(heapPtr, heapObjSize.toInt());

        VmDefaultHeap heap = (VmDefaultHeap) heapPtr.toObjectReference().toObject();
        heap.helper = helper;
        return heap;
    }

    /**
     * Append a new heap to the end of the linked list of heaps.
     *
     * @param newHeap
     */
    protected final void append(VmDefaultHeap newHeap) {
        VmDefaultHeap heap = this;
        while (heap.next != null) {
            heap = heap.next;
        }
        heap.next = newHeap;
    }

    /**
     * Gets the next heap in the linked list of heaps.
     *
     * @return Next heap
     */
    @Inline
    public final VmDefaultHeap getNext() {
        return next;
    }

    /**
     * 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 = Offset.fromIntSignExtend(-((ObjectLayout.HEADER_SLOTS + 1) * slotSize));
        this.headerSize = ObjectLayout.objectAlign(this.headerSize + slotSize);
        final int size = getSize();

        final Address myAddr = ObjectReference.fromObject(this).toAddress();
        final Word mySize = myAddr.loadWord(sizeOffset);
        Address firstObject;
        if (inHeap(myAddr)) {
            firstObject = myAddr.add(mySize).add(headerSize);
        } else {
            firstObject = start.add(headerSize);
        }

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

        // 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 Word remainingSize = end.toWord().sub(firstObject.toWord());
        final Address ptr = firstObject;
        ptr.store(remainingSize, sizeOffset);
        ptr.store(ObjectReference.fromObject(FREE), tibOffset);
        this.nextFreePtr = ptr;
        this.freeSize = remainingSize.toExtent();
    }

    /**
     * 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.EQ(Address.zero())) { /* This heap is full */
            return null;
        }

        final Offset tibOffset = this.tibOffset;
        final Word headerSize = Word.fromIntZeroExtend(this.headerSize);
        final Offset flagsOffset = this.flagsOffset;
        final Offset sizeOffset = this.sizeOffset;

        Word alignedSizeW = Word.fromIntZeroExtend(alignedSize);
        final Word totalSize = alignedSizeW.add(headerSize);
        final Object tib = vmClass.getTIB();
        if (tib == null) {
            throw new IllegalArgumentException("vmClass.TIB is null");
        }
        //final int size = getSize();
        Address objectPtr = Address.zero();
        lock();
        try {
            // Search for the first free block that is large enough
            //Screen.debug("a");
            while (objectPtr == null) {
                final Address ptr = nextFreePtr;
                final Word objSize = ptr.loadWord(sizeOffset);
                final Object objVmt = ptr.loadObjectReference(tibOffset);
                final Address nextPtr = ptr.add(objSize.add(headerSize));
                if ((objVmt == FREE) && alignedSizeW.LE(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 = Address.zero();
                        //Screen.debug("B");
                        return null;
                    } else {
                        this.nextFreePtr = nextPtr;
                    }
                }
            }
            //Screen.debug("A");

            final Word curFreeSize = objectPtr.loadWord(sizeOffset);
            if (curFreeSize.GT(totalSize)) {
                // Block is larger then we need, split it up.
                final Word newFreeSize = curFreeSize.sub(totalSize);
                /*if (newFreeSize <= headerSize) {
                    Unsafe.debug("Block splitup failed");
                    Unsafe.debug("\ncurFreeSize "); Unsafe.debug(curFreeSize);
                    Unsafe.debug("\ntotalSize   "); Unsafe.debug(totalSize);
                    Unsafe.debug("\nnewFreeSize "); Unsafe.debug(newFreeSize);
                    Unsafe.debug("\nheaderSize  "); Unsafe.debug(headerSize);
                    throw new Error("Block splitup failed");
                }*/
                final Address newFreePtr = objectPtr.add(totalSize);
                // Set the header for the remaining free block
                newFreePtr.store(newFreeSize, sizeOffset);
                newFreePtr.store(0, flagsOffset);
                newFreePtr.store(ObjectReference.fromObject(FREE), tibOffset);
                // 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.
                alignedSizeW = curFreeSize;
            }

            // Create the object header
            objectPtr.store(alignedSizeW, sizeOffset);
            objectPtr.store(0, flagsOffset);
            objectPtr.store(ObjectReference.fromObject(tib), tibOffset);
            // Mark the object in the allocation bitmap
            setAllocationBit(objectPtr, true);

            // Fix the freeSize
            freeSize = freeSize.sub(alignedSizeW);
        } finally {
            unlock();
        }

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

        return objectPtr.toObjectReference().toObject();
    }

    /**
     * Mark the given object as free space.
     *
     * @param object
     */
    @Inline
    final void free(Object object) {
        final Address ptr = ObjectReference.fromObject(object).toAddress();
        final Word objSize = ptr.loadWord(sizeOffset);
        ptr.store(ObjectReference.fromObject(FREE), tibOffset);
        setAllocationBit(object, false);
        freeSize = freeSize.add(objSize);
    }

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

    /**
     * Join all adjacent free spaces.
     *
     * @throws UninterruptiblePragma
     */
    protected final void defragment() throws UninterruptiblePragma {
        final Word size = Word.fromIntZeroExtend(getSize());
        final Word headerSize = Word.fromIntZeroExtend(this.headerSize);
        Word offset = headerSize;
        final Offset sizeOffset = this.sizeOffset;
        final Offset tibOffset = this.tibOffset;


        lock();
        try {
            Address firstFreePtr = Address.zero();
            while (offset.LT(size)) {
                final Address ptr = start.add(offset);
                final Word objSize = ptr.loadWord(sizeOffset);
                final Word nextOffset = offset.add(objSize).add(headerSize);
                final Object vmt = ptr.loadObjectReference(tibOffset);
                if ((firstFreePtr == null) && (vmt == FREE)) {
                    firstFreePtr = ptr;
                }
                if ((vmt == FREE) && (nextOffset.LT(size))) {
                    final Object nextVmt;
                    final Address nextObjectPtr = start.add(nextOffset);
                    nextVmt = nextObjectPtr.loadObjectReference(tibOffset);
                    if (nextVmt == FREE) {
                        // Combine two free spaces
                        Word nextObjSize = nextObjectPtr.loadWord(sizeOffset);
                        Word newObjSize = objSize.add(headerSize).add(nextObjSize);
                        ptr.store(newObjSize, sizeOffset);
                        // 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,
                              Word flagsMask, Word flagsValue) {
        // Go through the heap and call visit on each object
        final Word headerSize = Word.fromIntZeroExtend(this.headerSize);
        final Offset sizeOffset = this.sizeOffset;
        final Offset tibOffset = this.tibOffset;
        final Object FREE = this.FREE;
        Word offset = headerSize;
        final Word size = Word.fromIntZeroExtend(getSize());

        if (locking) {
            while (offset.LT(size)) {
                final Object tib;
                final Object object;
                final Word objSize;
                final Word flags;

                lock();
                try {
                    final Address ptr = start.add(offset);
                    object = ptr.toObjectReference().toObject();
                    tib = ptr.loadObjectReference(tibOffset);
                    objSize = ptr.loadWord(sizeOffset);
                    flags = (flagsMask.isZero()) ? Word.zero() : VmMagic.getObjectFlags(object).and(flagsMask);
                } finally {
                    unlock();
                }
                if (tib != FREE) {
                    if (flags.EQ(flagsValue)) {
                        if (!visitor.visit(object)) {
                            // Stop
                            return;
                        }
                    }
                }
                offset = offset.add(objSize).add(headerSize);
            }
        } else {
            while (offset.LT(size)) {
                final Address ptr = start.add(offset);
                final Object object = ptr.toObjectReference().toObject();
                final Object tib = ptr.loadObjectReference(tibOffset);
                final Word objSize = ptr.loadWord(sizeOffset);
                final Word flags = flagsMask.isZero() ? Word.zero() : VmMagic.getObjectFlags(object).and(flagsMask);
                if (tib != FREE) {
                    if (flags.EQ(flagsValue)) {
                        if (!visitor.visit(object)) {
                            // Stop
                            return;
                        }
                    }
                }
                offset = offset.add(objSize).add(headerSize);
            }
        }
    }
}
TOP

Related Classes of org.jnode.vm.memmgr.def.VmDefaultHeap

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.