Commit caabc2b9 authored by Kunshan Wang's avatar Kunshan Wang

GC now collects stack memory.

parent d59f3215
......@@ -18,5 +18,5 @@ class UnimplementedOprationException(message: String = null, cause: Throwable =
*/
class UvmRuntimeException(message: String = null, cause: Throwable = null) extends UvmRefImplException(message, cause)
/** Thrown when a division by zero is executed and the exception claues is not present. */
/** Thrown when a division by zero is executed and the exception clause is not present. */
class UvmDivisionByZeroException(message: String = null, cause: Throwable = null) extends UvmRuntimeException(message, cause)
\ No newline at end of file
......@@ -22,9 +22,11 @@ class ThreadStackManager(microVM: MicroVM) {
def getStackByID(id: Int): Option[InterpreterStack] = stackRegistry.get(id)
def getThreadByID(id: Int): Option[InterpreterThread] = threadRegistry.get(id)
def iterateAllLiveStacks: Iterable[InterpreterStack] = stackRegistry.values.filter(_.state != StackState.Dead)
def iterateAllLiveThreads: Iterable[InterpreterThread] = threadRegistry.values.filter(_.isRunning)
private var nextStackID: Int = 1
private def makeStackID(): Int = { val id = nextStackID; nextStackID += 1; id }
......
......@@ -18,6 +18,8 @@ object StackState {
}
class InterpreterStack(val id: Int, val stackMemory: StackMemory, stackBottomFunc: FuncVer, args: Seq[ValueBox]) {
var gcMark: Boolean = false // Mark for GC.
var state: StackState = StackState.Ready(InternalTypes.VOID) // Initial state is READY<void>
var top: InterpreterFrame = InterpreterFrame.frameForCall(stackBottomFunc, args, None)
......
package uvm.refimpl.mem
import org.slf4j.LoggerFactory
import com.typesafe.scalalogging.Logger
object Collector {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
}
abstract class Collector extends Runnable() {
import Collector._
override def run() {
try {
......@@ -10,9 +18,8 @@ abstract class Collector extends Runnable() {
}
} catch {
case e: Exception => {
System.err.println("Error thrown from collection thread.")
e.printStackTrace()
System.exit(1)
logger.error("Collector throws an exception.", e)
heap.gcError(e)
}
}
}
......
......@@ -7,6 +7,7 @@ import uvm.refimpl.UvmRefImplException
object Heap {
protected val MUTATOR_RUNNING = 0
protected val DOING_GC = 1
protected val GC_ERROR = 2 // Set if an exception is thrown in GC. In this case, an exception is thrown to the (only) mutator thread.
}
abstract class Heap {
......@@ -19,6 +20,8 @@ abstract class Heap {
protected var gcState: Int = _
protected var mustFreeSpace: Boolean = _
protected var gcException: Exception = null
def mutatorTriggerAndWaitForGCEnd(mustFreeSpace: Boolean) {
lock.lock()
......@@ -45,7 +48,7 @@ abstract class Heap {
private def mutatorWaitForGCEnd() {
lock.lock()
try {
while (gcState != MUTATOR_RUNNING) {
while (gcState == DOING_GC) {
try {
gcFinished.await()
} catch {
......@@ -55,6 +58,10 @@ abstract class Heap {
} finally {
lock.unlock()
}
if (gcState == GC_ERROR) {
throw new UvmRefImplException("Exception thrown in the GC thread.", gcException)
}
}
def untriggerGC() {
......@@ -67,7 +74,18 @@ abstract class Heap {
lock.unlock()
}
}
def gcError(e: Exception) {
lock.lock()
try {
assert((gcState == DOING_GC))
gcState = GC_ERROR
gcException = e
gcFinished.signalAll()
} finally {
lock.unlock()
}
}
def collectorWaitForGCStart() {
lock.lock()
while (gcState != DOING_GC) {
......
......@@ -4,5 +4,10 @@ import uvm.refimpl.MicroVM
import uvm.refimpl.mem.bumppointer.RewindableBumpPointerAllocator
import TypeSizes.Word
/**
* Stack memory.
* <p>
* If the stack is Dead, the stackObjRef will be a dangling pointer.
*/
class StackMemory(val stackObjRef: Word, extend: Word, microVM: MicroVM)
extends RewindableBumpPointerAllocator(stackObjRef, extend, microVM)
......@@ -53,7 +53,7 @@ class RewindableBumpPointerAllocator(val begin: Word, val extend: Word, val micr
logger.debug("hdr=0x%x, typeID=0x%x".format(hdr, typeID))
val ty = microVM.globalBundle.typeNs(typeID)
logger.debug("type=%s: %s".format(ty.repr, ty.toString))
MemoryDataScanner.scanField(ty, 0, iRef, handler)
MemoryDataScanner.scanField(ty, 0, iRef, microVM, handler)
var prevTopLoc: Word = 0L
prevTopLoc = if (ty.isInstanceOf[TypeHybrid]) {
iRef - TypeSizes.GC_HEADER_SIZE_HYBRID - WORD_SIZE_BYTES
......
......@@ -18,7 +18,8 @@ object AllScanner {
class AllScanner(val microVM: MicroVM, val handler: RefFieldHandler) extends RefFieldHandler {
import AllScanner._
private val queue = new ArrayDeque[Word]()
private val addrQueue = new ArrayDeque[Word]()
private val stackQueue = new ArrayDeque[InterpreterStack]()
def scanAll() {
traceRoots()
......@@ -30,15 +31,16 @@ class AllScanner(val microVM: MicroVM, val handler: RefFieldHandler) extends Ref
traceClientAgents()
logger.debug("Tracing globals...")
traceGlobal()
logger.debug("Tracing stacks...")
traceStacks()
logger.debug("Tracing threads...")
traceThreads()
}
private def traceClientAgents() {
for (ca <- microVM.clientAgents; h <- ca.handles) {
h.vb match {
case hor: HasObjRef => this.fromBox(hor)
case _ =>
case hor: HasObjRef => this.boxToHeap(hor)
case bst: BoxStack => this.boxToStack(bst)
case _ =>
}
}
}
......@@ -47,48 +49,84 @@ class AllScanner(val microVM: MicroVM, val handler: RefFieldHandler) extends Ref
microVM.memoryManager.globalMemory.allocator.traverseFields(this)
}
private def traceStacks() {
for (sta <- microVM.threadStackManager.iterateAllLiveStacks) {
logger.debug(s"Tracing stack ${sta.id} for registers...")
for (fra <- sta.frames; vb <- fra.boxes.values if vb.isInstanceOf[HasObjRef]) {
val rvb = vb.asInstanceOf[HasObjRef]
fromBox(rvb)
}
private def traceThreads() {
for (thr <- microVM.threadStackManager.iterateAllLiveThreads) {
logger.debug(s"Tracing live thread ${thr.id} for its stack")
this.threadToStack(thr, thr.stack)
}
}
logger.debug(s"Tracing stack ${sta.id} memory chunk in LOS...")
val stackMemory = sta.stackMemory
val stackMemObjAddr = stackMemory.stackObjRef
fromInternal(stackMemObjAddr) // This is a hack: A reference from nowhere.
private def traceStack(sta: InterpreterStack) {
logger.debug(s"Tracing stack ${sta.id} for registers...")
logger.debug(s"Tracing stack ${sta.id} for allocas...")
stackMemory.traverseFields(this)
for (fra <- sta.frames; vb <- fra.boxes.values) vb match {
case hor: HasObjRef => this.boxToHeap(hor)
case bst: BoxStack => this.boxToStack(bst)
case _ =>
}
logger.debug(s"Tracing stack ${sta.id} memory chunk in LOS...")
val stackMemory = sta.stackMemory
val stackMemObjAddr = stackMemory.stackObjRef
this.stackToStackMem(sta, stackMemObjAddr)
logger.debug(s"Tracing stack ${sta.id} for allocas...")
stackMemory.traverseFields(this)
}
private def doTransitiveClosure() {
while (!queue.isEmpty) {
val objRef = queue.pollFirst()
logger.debug("Scanning heap object 0x%x...".format(objRef))
MemoryDataScanner.scanAllocUnit(objRef, objRef, microVM, this)
var allEmpty = false
while (!allEmpty) {
allEmpty = true
while (!stackQueue.isEmpty) {
allEmpty = false
val stack = stackQueue.pollFirst()
logger.debug("Scanning stack %d...".format(stack.id))
traceStack(stack)
}
while (!addrQueue.isEmpty) {
allEmpty = false
val objRef = addrQueue.pollFirst()
logger.debug("Scanning heap object 0x%x...".format(objRef))
MemoryDataScanner.scanAllocUnit(objRef, objRef, microVM, this)
}
}
}
override def fromBox(box: HasObjRef): Option[Word] = {
val rv = handler.fromBox(box)
rv.foreach(queue.add)
override def boxToHeap(box: HasObjRef): Option[Word] = {
val rv = handler.boxToHeap(box)
rv.foreach(addrQueue.add)
rv
}
override def boxToStack(box: BoxStack): Option[InterpreterStack] = {
val rv = handler.boxToStack(box)
rv.foreach(stackQueue.add)
rv
}
override def memToHeap(objRef: Word, iRef: Word, toObj: Word, isWeak: Boolean, isTR64: Boolean): Option[Word] = {
val rv = handler.memToHeap(objRef, iRef, toObj, isWeak, isTR64)
rv.foreach(addrQueue.add)
rv
}
override def fromMem(objRef: Word, iRef: Word, toObj: Word, isWeak: Boolean, isTR64: Boolean): Option[Word] = {
val rv = handler.fromMem(objRef, iRef, toObj, isWeak, isTR64)
rv.foreach(queue.add)
override def memToStack(objRef: Word, iRef: Word, toStack: Option[InterpreterStack]): Option[InterpreterStack] = {
val rv = handler.memToStack(objRef, iRef, toStack)
rv.foreach(stackQueue.add)
rv
}
override def fromInternal(toObj: Word): Option[Word] = {
val rv = handler.fromInternal(toObj)
rv.foreach(queue.add)
override def stackToStackMem(stack: InterpreterStack, toObj: Word): Option[Word] = {
val rv = handler.stackToStackMem(stack, toObj)
rv.foreach(addrQueue.add)
rv
}
override def threadToStack(thread: InterpreterThread, toStack: Option[InterpreterStack]): Option[InterpreterStack] = {
val rv = handler.threadToStack(thread, toStack)
rv.foreach(stackQueue.add)
rv
}
......
......@@ -22,25 +22,25 @@ object MemoryDataScanner extends StrictLogging {
logger.debug("Obj 0x%x, tag 0x%x".format(objRef, tag))
val ty = HeaderUtils.getType(microVM, tag)
logger.debug("Type: %s".format(ty.repr))
scanField(ty, objRef, objRef, handler)
scanField(ty, objRef, objRef, microVM, handler)
}
def scanField(ty: Type, objRef: Word, iRef: Word, handler: RefFieldHandler) {
def scanField(ty: Type, objRef: Word, iRef: Word, microVM: MicroVM, handler: RefFieldHandler) {
ty match {
case t: TypeRef => {
val toObj = MemorySupport.loadLong(iRef)
logger.debug(s"Ref field ${iRef} -> ${toObj}")
handler.fromMem(objRef, iRef, toObj, false, false)
handler.memToHeap(objRef, iRef, toObj, false, false)
}
case t: TypeIRef => {
val toObj = MemorySupport.loadLong(iRef)
logger.debug(s"IRef field ${iRef} -> ${toObj}")
handler.fromMem(objRef, iRef, toObj, false, false)
handler.memToHeap(objRef, iRef, toObj, false, false)
}
case t: TypeWeakRef => {
val toObj = MemorySupport.loadLong(iRef)
logger.debug(s"WeakRef field ${iRef} -> ${toObj}")
handler.fromMem(objRef, iRef, toObj, true, false)
handler.memToHeap(objRef, iRef, toObj, true, false)
}
case t: TypeTagRef64 => {
val bits = MemorySupport.loadLong(iRef)
......@@ -57,7 +57,7 @@ object MemoryDataScanner extends StrictLogging {
if (OpHelper.tr64IsRef(bits)) {
val toObj = OpHelper.tr64ToRef(bits)
logger.debug(s"TagRef64 field ${iRef} -> ${toObj} tag: ${OpHelper.tr64ToTag(bits)}")
handler.fromMem(objRef, iRef, toObj, false, true)
handler.memToHeap(objRef, iRef, toObj, false, true)
}
}
case t: TypeStruct => {
......@@ -65,7 +65,7 @@ object MemoryDataScanner extends StrictLogging {
for (fieldTy <- t.fieldTy) {
val fieldAlign = TypeSizes.alignOf(fieldTy)
fieldAddr = TypeSizes.alignUp(fieldAddr, fieldAlign)
scanField(fieldTy, objRef, fieldAddr, handler)
scanField(fieldTy, objRef, fieldAddr, microVM, handler)
fieldAddr += TypeSizes.sizeOf(fieldTy)
}
}
......@@ -75,7 +75,7 @@ object MemoryDataScanner extends StrictLogging {
val elemAlign = TypeSizes.alignOf(elemTy)
var elemAddr = iRef
for (i <- 0L until t.len) {
scanField(elemTy, objRef, elemAddr, handler)
scanField(elemTy, objRef, elemAddr, microVM, handler)
elemAddr = TypeSizes.alignUp(elemAddr + elemSize, elemAlign)
}
......@@ -89,13 +89,25 @@ object MemoryDataScanner extends StrictLogging {
val varAlign = TypeSizes.alignOf(varTy)
var curAddr = iRef
val varLength = HeaderUtils.getVarLength(iRef)
scanField(fixedTy, objRef, curAddr, handler)
scanField(fixedTy, objRef, curAddr, microVM, handler)
curAddr = TypeSizes.alignUp(curAddr + fixedSize, fixedAlign)
for (i <- 0L until varLength) {
scanField(varTy, objRef, curAddr, handler)
scanField(varTy, objRef, curAddr, microVM, handler)
curAddr = TypeSizes.alignUp(curAddr + varSize, varAlign)
}
}
case t: TypeStack => {
val toStackID = MemorySupport.loadLong(iRef)
val maybeToStack = if (toStackID == 0) {
None
} else {
val toStack = microVM.threadStackManager.getStackByID(toStackID.toInt).getOrElse {
throw new UvmRefImplException("Memory location 0x%x referring to non-existing stack %d".format(iRef, toStackID))
}
Some(toStack)
}
handler.memToStack(objRef, iRef, maybeToStack)
}
case _ => // Ignore non-reference fields.
}
}
......
package uvm.refimpl.mem.scanning
import uvm.refimpl.itpr.HasObjRef
import uvm.refimpl.itpr.BoxStack
import uvm.refimpl.mem.TypeSizes._
import uvm.refimpl.mem.MemorySupport
import uvm.refimpl.itpr.OpHelper
import uvm.refimpl.itpr.InterpreterThread
import uvm.refimpl.itpr.InterpreterStack
import uvm.refimpl.UvmRefImplException
/**
* Handle reference fields or references in boxes.
* Handle references in the memory, value boxes or other Micro VM structures such as threads and stacks.
* <ul>
* <li>The caller invokes the methods on all boxes/locations it finds, no matter whether it is NULL or not.</li>
* <li>The callee checks if the box/location actually contain non-null references.</li>
* </ul>
* <p>
* Both fromBox and fromMem method return Some(addr) if addr is to be enqueued by the scanner, or None otherwise. If an
* object is moved when scanning an object, the returned addr must be the new address.
* <p>
* The caller invokes the methods on all boxes/locations it finds. The Callee checks if the box/location
* actually contain references or non-null references.
* The return value of the methods will be queued for recursive traversing. They should be the old value,
* the updated value by the copying GC, or None if the reference should not be followed.
*/
trait RefFieldHandler {
/** Scan a box. */
def fromBox(box: HasObjRef): Option[Word]
/** Scan a memory location. */
def fromMem(objRef: Word, iRef: Word, toObj: Word, isWeak: Boolean, isTR64: Boolean): Option[Word]
/**
* A reference from somewhere internal to the micro VM.
* For example, from the StackMemory to the memory byte array;
* from a finaliser table to a finalisable object (to be added).
*/
def fromInternal(toObj: Word): Option[Word]
/** A stack value box referring to a heap object. */
def boxToHeap(box: HasObjRef): Option[Word]
/** A stack value box referring to a "stack"-typed value. */
def boxToStack(box: BoxStack): Option[InterpreterStack]
/** A memory location referring to a heap object. */
def memToHeap(objRef: Word, iRef: Word, toObj: Word, isWeak: Boolean, isTR64: Boolean): Option[Word]
/** A memory location referring to a heap object. Return the new stack ID or 0. */
def memToStack(objRef: Word, iRef: Word, toStack: Option[InterpreterStack]): Option[InterpreterStack]
/** An InterpreterStack object referring to its stackMemory field. Stack memory cannot move. */
def stackToStackMem(stack: InterpreterStack, toObj: Word): Option[Word]
/** An InterpreterThread referring to its stack. GC cannot rebind stacks. */
def threadToStack(thread: InterpreterThread, toStack: Option[InterpreterStack]): Option[InterpreterStack]
}
object RefFieldUpdater {
def updateBox(box: HasObjRef, newObjRef: Word): Unit = box.setObjRef(newObjRef)
def updateMemory(iRef: Word, isTR64: Boolean, newObjRef: Word): Unit = {
def updateBoxToHeap(box: HasObjRef, newObjRef: Word): Unit = box.setObjRef(newObjRef)
def updateBoxToStack(box: BoxStack, newStack: Option[InterpreterStack]) = box.stack = newStack
def updateMemToHeap(iRef: Word, isTR64: Boolean, newObjRef: Word): Unit = {
if (isTR64) {
val oldRaw = MemorySupport.loadLong(iRef)
val oldTag = OpHelper.tr64ToTag(oldRaw)
......@@ -39,4 +47,7 @@ object RefFieldUpdater {
MemorySupport.storeLong(iRef, newObjRef)
}
}
def updateMemToStack(iRef: Word, newStack: Option[InterpreterStack]) = {
MemorySupport.storeLong(iRef, newStack.map(_.id).getOrElse(0).toLong)
}
}
\ No newline at end of file
......@@ -18,9 +18,9 @@ object SimpleImmixCollector {
}
class SimpleImmixCollector(val heap: SimpleImmixHeap,
val space: SimpleImmixSpace,
val los: LargeObjectSpace,
microVM: MicroVM) extends Collector with Runnable {
val space: SimpleImmixSpace,
val los: LargeObjectSpace,
microVM: MicroVM) extends Collector with Runnable {
import SimpleImmixCollector._
......@@ -48,12 +48,17 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap,
logger.debug("Marking and getting statistics....")
val s1 = new AllScanner(microVM, new RefFieldHandler() {
override def fromBox(box: HasObjRef): Option[Word] = box match {
case HasNonZeroRef(toObj) => maybeMarkAndStat(toObj)
case _ => None
override def boxToHeap(box: HasObjRef): Option[Word] = if (box.hasObjRef()) {
maybeMarkAndStatIfNotNull(box.getObjRef())
} else {
None
}
override def boxToStack(box: BoxStack): Option[InterpreterStack] = {
maybeMarkStackIfSome(box.stack)
}
override def fromMem(objRef: Word, iRef: Word, toObj: Word, isWeak: Boolean, isTR64: Boolean): Option[Word] = {
override def memToHeap(objRef: Word, iRef: Word, toObj: Word, isWeak: Boolean, isTR64: Boolean): Option[Word] = {
if (toObj != 0L) {
if (isWeak) {
logger.debug(s"Enqueued weak reference ${iRef} to ${toObj}")
......@@ -67,7 +72,15 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap,
}
}
override def fromInternal(toObj: Word): Option[Word] = if (toObj != 0L) maybeMarkAndStat(toObj) else None
override def memToStack(objRef: Word, iRef: Word, toStack: Option[InterpreterStack]): Option[InterpreterStack] = {
maybeMarkStackIfSome(toStack)
}
override def stackToStackMem(stack: InterpreterStack, toObj: Word): Option[Word] = maybeMarkAndStatIfNotNull(toObj)
override def threadToStack(thread: InterpreterThread, toStack: Option[InterpreterStack]): Option[InterpreterStack] = {
maybeMarkStackIfSome(toStack)
}
})
s1.scanAll()
......@@ -103,6 +116,15 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap,
logger.debug("Marked. Collecting blocks....")
val anyMemoryRecycled = collectBlocks()
logger.debug("Killing unreachable stacks...")
for (st <- microVM.threadStackManager.iterateAllLiveStacks) {
if(!st.gcMark) {
logger.debug("Killing stack %d...".format(st.id))
st.state = StackState.Dead
}
}
if (!anyMemoryRecycled && heap.getMustFreeSpace) {
throw new UvmRefImplException("Out of memory because the GC failed to recycle any memory.")
}
......@@ -117,6 +139,10 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap,
heap.untriggerGC()
}
private def maybeMarkAndStatIfNotNull(addr: Word): Option[Word] = {
if (addr != 0L) maybeMarkAndStat(addr) else None
}
private def maybeMarkAndStat(addr: Word): Option[Word] = {
assert(addr != 0L, "addr should be non-zero before calling this function")
val oldHeader = HeaderUtils.getTag(addr)
......@@ -152,24 +178,52 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap,
}
}
private val markMover = new RefFieldHandler {
override def fromBox(box: HasObjRef): Option[Word] = box match {
case HasNonZeroRef(toObj) => maybeMove(toObj, newObjRef => RefFieldUpdater.updateBox(box, newObjRef))
case _ => None
}
private def maybeMarkStackIfSome(maybeStack: Option[InterpreterStack]): Option[InterpreterStack] = {
maybeStack.flatMap(maybeMarkStack)
}
override def fromMem(objRef: Word, iRef: Word, toObj: Word, isWeak: Boolean, isTR64: Boolean): Option[Word] = {
if (toObj != 0L) {
maybeMove(toObj, newObjRef => RefFieldUpdater.updateMemory(iRef, isTR64, newObjRef))
private def maybeMarkStack(stack: InterpreterStack): Option[InterpreterStack] = {
if (stack.state != StackState.Dead) {
if (!stack.gcMark) {
stack.gcMark = true
Some(stack)
} else {
None
}
} else {
None
}
}
private val markMover = new RefFieldHandler {
override def boxToHeap(box: HasObjRef): Option[Word] = if (box.hasObjRef()) {
maybeMoveIfNotNull(box.getObjRef, newObjRef => RefFieldUpdater.updateBoxToHeap(box, newObjRef))
} else {
None
}
override def boxToStack(box: BoxStack): Option[InterpreterStack] = {
maybeMarkStackIfSome(box.stack)
}
override def memToHeap(objRef: Word, iRef: Word, toObj: Word, isWeak: Boolean, isTR64: Boolean): Option[Word] = {
maybeMoveIfNotNull(toObj, newObjRef => RefFieldUpdater.updateMemToHeap(iRef, isTR64, newObjRef))
}
override def memToStack(objRef: Word, iRef: Word, toStack: Option[InterpreterStack]): Option[InterpreterStack] = {
maybeMarkStackIfSome(toStack)
}
// Currently internally referenced objects (only the byte array for stacks) cannot move and does not transitively
// refer to other objects.
override def fromInternal(toObj: Word): Option[Word] = None
override def stackToStackMem(stack: InterpreterStack, toObj: Word): Option[Word] = {
maybeMoveIfNotNull(toObj, _ => throw new UvmRefImplException("Stack memory cannot move."))
}
override def threadToStack(thread: InterpreterThread, toStack: Option[InterpreterStack]): Option[InterpreterStack] = {
maybeMarkStackIfSome(toStack)
}
private def maybeMoveIfNotNull(toObj: Word, updateFunc: Word => Unit): Option[Word] = {
if (toObj != 0L) maybeMove(toObj, updateFunc) else None
}
private def maybeMove(toObj: Word, updateFunc: Word => Unit): Option[Word] = {
val oldHeader = HeaderUtils.getTag(toObj)
......@@ -275,16 +329,33 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap,
}
private val clearMarkHandler = new RefFieldHandler() {
override def fromBox(box: HasObjRef): Option[Word] = box match {
case HasNonZeroRef(toObj) => clearMark(toObj)
case _ => None
override def boxToHeap(box: HasObjRef): Option[Word] = if (box.hasObjRef) {
clearMarkIfNotNull(box.getObjRef())
} else {
None
}
override def boxToStack(box: BoxStack): Option[InterpreterStack] = {
clearStackMarkIfSome(box.stack)
}
override def memToHeap(objRef: Word, iRef: Word, toObj: Word, isWeak: Boolean, isTR64: Boolean): Option[Word] = {
clearMarkIfNotNull(toObj)
}
override def memToStack(objRef: Word, iRef: Word, toStack: Option[InterpreterStack]): Option[InterpreterStack] = {
clearStackMarkIfSome(toStack)
}
override def fromMem(objRef: Word, iRef: Word, toObj: Word, isWeak: Boolean, isTR64: Boolean): Option[Word] = {
if (toObj != 0L) clearMark(toObj) else None
override def stackToStackMem(stack: InterpreterStack, toObj: Word): Option[Word] = clearMarkIfNotNull(toObj)
override def threadToStack(thread: InterpreterThread, toStack: Option[InterpreterStack]): Option[InterpreterStack] = {
clearStackMarkIfSome(toStack)
}
}
override def fromInternal(toObj: Word): Option[Word] = if (toObj != 0L) clearMark(toObj) else None
private def clearMarkIfNotNull(objRef: Long): Option[Word] = {
if (objRef != 0L) clearMark(objRef) else None
}
private def clearMark(objRef: Long): Option[Word] = {
......@@ -300,6 +371,19 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap,
}
}
private def clearStackMarkIfSome(maybeStack: Option[InterpreterStack]): Option[InterpreterStack] = {
maybeStack.flatMap(clearStackMark)
}
private def clearStackMark(stack: InterpreterStack): Option[InterpreterStack] = {
if (stack.gcMark) {
stack.gcMark = false
Some(stack)
} else {
None
}
}
private def getMovement(objRef: Word): Option[Word] = {
val tag = HeaderUtils.getTag(objRef)
logger.debug("Inspecting header for Futex. Obj 0x%x, tag 0x%x".format(objRef, tag))
......@@ -318,16 +402,4 @@ class SimpleImmixCollector(val heap: SimpleImmixHeap,
microVM.threadStackManager.futexManager.afterGCAdjust(getMovement)
}
private object HasNonZeroRef {
def unapply(obj: Any): Option[Word] = obj match {
case hor: HasObjRef => if (hor.hasObjRef) {
val toObj = hor.getObjRef
if (toObj != 0L) Some(toObj)
else None
} else None
case _ => None
}
}
}
......@@ -18,10 +18,10 @@ class UvmInterpreterSpec extends UvmBundleTesterBase {
setLogLevels(
ROOT_LOGGER_NAME -> INFO,
//"uvm.refimpl.mem" -> DEBUG,
//"uvm.refimpl.mem.simpleimmix.SimpleImmixCollector$" -> DEBUG,
"uvm.refimpl.itpr" -> DEBUG)
override def makeMicroVM = new MicroVM(heapSize = 64L * 1024L * 1024L)
override def makeMicroVM = new MicroVM(heapSize = 8L * 1024L * 1024L)
preloadBundles("tests/uvm-refimpl-test/basic-tests.uir")
......