/*
* $Id$
*
* Copyright (C) 2003-2015 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.annotation.Inline;
import org.jnode.annotation.MagicPermission;
import org.jnode.vm.classmgr.ObjectLayout;
import org.jnode.vm.facade.ObjectVisitor;
import org.jnode.vm.memmgr.HeapHelper;
import org.jnode.vm.scheduler.SpinLock;
import org.vmmagic.pragma.Uninterruptible;
import org.vmmagic.pragma.UninterruptiblePragma;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.ObjectReference;
import org.vmmagic.unboxed.Offset;
import org.vmmagic.unboxed.Word;
/**
* An abstract heap class.
* <p/>
* All changes to the structure of the heap must be made exclusive by {@link #lock()}
* and {@link #unlock()}.
*
* @author epr
*/
@MagicPermission
abstract class VmAbstractHeap extends SpinLock implements Uninterruptible {
/**
* Start address of this heap (inclusive)
*/
protected Address start;
/**
* End address of this heap (exclusive)
*/
protected Address end;
/**
* Size of this heap in bytes
*/
private int size;
/**
* Size of an object header in bytes
*/
protected int headerSize;
/**
* Offset of the flags field in an object header
*/
protected Offset flagsOffset;
/**
* Offset of the type information block field in an object header
*/
protected Offset tibOffset;
/**
* Start address of allocation bitmap
*/
protected Address allocationBitmapPtr;
/**
* Default marker for free object space (marker in VMT field)
*/
protected Object FREE = null;
protected HeapHelper helper;
public VmAbstractHeap(HeapHelper helper) {
this.helper = helper;
}
/**
* Initialization method for the private fields in this class.
* This method must be called, after start and end have been set.
*
* @param slotSize
*/
protected final void initializeAbstract(int slotSize) {
this.headerSize = ObjectLayout.HEADER_SLOTS * slotSize;
this.flagsOffset = Offset.fromIntSignExtend(ObjectLayout.FLAGS_SLOT * slotSize);
this.tibOffset = Offset.fromIntSignExtend(ObjectLayout.TIB_SLOT * slotSize);
this.size = end.toWord().sub(start.toWord()).toInt();
}
/**
* Gets the size in bytes of this heap.
*
* @return int
*/
@Inline
public final int getSize() {
return size;
}
/**
* Is the given address the address of an allocated object on this heap?
*
* @param addr
* @return boolean
*/
@Inline
protected final boolean isObject(Address addr) {
if (addr.LT(start) || addr.GE(end)) {
// The object if not within this heap
return false;
}
final int offset = addr.toWord().sub(start.toWord()).toInt();
int bit = offset / ObjectLayout.OBJECT_ALIGN;
final Offset idx = Offset.fromIntZeroExtend(bit / 8);
final int mask = 1 << (bit & 7);
final Address bitmapPtr = this.allocationBitmapPtr;
final int value = bitmapPtr.loadByte(idx);
return ((value & mask) == mask);
}
/**
* Is the given address an address within this heap.
* If so, this does not always mean that the address is a valid object!
*
* @param addr
* @return boolean
*/
@Inline
protected final boolean inHeap(Address addr) {
return (addr.GE(start) && addr.LT(end));
}
/**
* Change a bit in the allocation bitmap.
*
* @param object
* @param on
*/
@Inline
protected final void setAllocationBit(Object object, boolean on) {
final Address addr = ObjectReference.fromObject(object).toAddress();
if (addr.LT(start) || addr.GE(end)) {
return;
}
final int offset = addr.toWord().sub(start.toWord()).toInt();
final int bit = offset / ObjectLayout.OBJECT_ALIGN;
final Offset idx = Offset.fromIntZeroExtend(bit / 8);
final int mask = 1 << (bit & 7);
final Address bitmapPtr = this.allocationBitmapPtr;
int value = bitmapPtr.loadByte(idx);
if (on) {
value |= mask;
} else {
value &= ~mask;
}
bitmapPtr.store((byte) value, idx);
}
/**
* 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 abstract void initialize(Address start, Address end, int slotSize);
/**
* Let a selected set of objects in this heap accept the given <code>visitor</code>.
* The selection is made based on the objectflags. The objectflags are masked
* by flagsMask and the result is compared with flagsValue, if they are equal
* the object is visited.
*
* @param visitor
* @param locking If true, use lock/unlock while proceeding to the next object.
* @param flagsMask
* @param flagsValue
* @throws UninterruptiblePragma
*/
protected abstract void walk(ObjectVisitor visitor, boolean locking, Word flagsMask, Word flagsValue)
throws UninterruptiblePragma;
}