GitLab will continue to be upgraded from 11.4.5-ce.0 on November 25th 2019 at 4.00pm (AEDT) to 5.00pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available.

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")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment