Commit 63af3f1e authored by Kunshan Wang's avatar Kunshan Wang

Reworked memory scanner to support bootimg

parent 1958f150
......@@ -6,23 +6,29 @@ import java.nio.charset.StandardCharsets
import java.nio.file._
import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.HashMap
import org.slf4j.LoggerFactory
import com.typesafe.scalalogging.Logger
import uvm._
import uvm.ir.irbuilder.IRNode
import uvm.ir.textoutput.BundleSerializer
import uvm.ir.textoutput.EntityUtils
import uvm.refimpl._
import uvm.refimpl.itpr.FrameCursor
import uvm.refimpl.itpr.InterpreterStack
import uvm.refimpl.itpr.InterpreterThread
import uvm.refimpl.mem.HeaderUtils
import uvm.refimpl.mem.Space
import uvm.refimpl.mem.TypeSizes
import uvm.refimpl.mem.scanning.MemoryDataScanner
import uvm.refimpl.mem.scanning.MemoryFieldHandler
import uvm.refimpl.nat.NativeSupport
import uvm.refimpl.nat.PlatformConstants.Word
import uvm.types._
import uvm.utils.WithUtils.tryWithResource
import uvm.ir.textoutput.EntityUtils
import uvm.ir.textoutput.BundleSerializer
import scala.collection.mutable.HashMap
class BootImageBuilder(implicit microVM: MicroVM) {
def makeBootImage(whiteList: Seq[TopLevel], outputFile: String): Unit = {
......@@ -41,7 +47,7 @@ object BootImageWriter {
val FILEEXT_DATA = ".data"
val FILEEXT_ALLOC = ".alloc"
val FILEEXT_RELOC = ".reloc"
val UIRBUNDLE_FILE = "bundle.uir"
val IDNAMEMAP_FILE = "idnamemap"
......@@ -61,7 +67,7 @@ object BootImageWriter {
* @param fileOffset The offset from the beginning of the .data file.
* @param ty The type of the allocation unit.
* @param varLen The length of the variable part if it is a hybrid; otherwise 0.
*
*
* @param addr The address in the current micro VM instance. Not persisted.
*/
case class UnitAllocRecord(num: Long, fileOffset: Long, ty: Type, varLen: Long, addr: Word)
......@@ -97,12 +103,12 @@ class BootImageWriter(tcb: TransitiveClosureBuilder, outputFile: String)(implici
val bundleSerializer = new BundleSerializer(microVM.globalBundle, tcb.tls.set)
val tempDir = Files.createTempDirectory("mu-bootimg")
logger.info("Writing bootimg files to temp dir: %s".format(tempDir.toAbsolutePath().toString()))
val globalGroup = new FileGroup("global", tempDir)
val heapGroup = new FileGroup("heap", tempDir)
val idNameMapPath = tempDir.resolve(IDNAMEMAP_FILE)
val uirBundlePath = tempDir.resolve(UIRBUNDLE_FILE)
......@@ -110,7 +116,7 @@ class BootImageWriter(tcb: TransitiveClosureBuilder, outputFile: String)(implici
private val smallObjectSpace: Space = microVM.memoryManager.heap.space
private val largeObjectSpace: Space = microVM.memoryManager.heap.los
private implicit val memorySupport = microVM.memoryManager.memorySupport
val addrToGlobalCell = tcb.globalCellMap
val addrToHeapObjNum = new HashMap[Word, Long]()
......@@ -127,13 +133,13 @@ class BootImageWriter(tcb: TransitiveClosureBuilder, outputFile: String)(implici
writeAllocRecs(globalGroup)
writeAllocRecs(heapGroup)
scanForRelocs(globalGroup)
scanForRelocs(heapGroup)
writeRelocRecs(globalGroup)
writeRelocRecs(heapGroup)
writeIDNameMap()
writeUIRBundle()
}
......@@ -172,17 +178,32 @@ class BootImageWriter(tcb: TransitiveClosureBuilder, outputFile: String)(implici
}
}
}
private def scanForRelocs(group: FileGroup): Unit = {
for (alloc <- group.allocRecs) {
???
val num = alloc.num
val begin = alloc.addr
MemoryDataScanner.scanAllocUnit(begin, new MemoryFieldHandler {
def visitRefField(objRef: Word, iRef: Word, toObj: Word, isWeak: Boolean): Unit = {}
def visitIRefField(objRef: Word, iRef: Word, toObj: Word, toOffset: Word): Unit = {}
/** This function is called only when the tagref is holding a reference. */
def visitTagRefField(objRef: Word, iRef: Word, toObj: Word): Unit = {}
def visitFuncRefField(objRef: Word, iRef: Word, toFunc: Option[Function]): Unit = {}
def visitStackRefField(objRef: Word, iRef: Word, toStack: Option[InterpreterStack]): Unit = {}
def visitThreadRefField(objRef: Word, iRef: Word, toThread: Option[InterpreterThread]): Unit = {}
def visitFCRefField(objRef: Word, iRef: Word, toFCRef: Option[FrameCursor]): Unit = {}
def visitIRNodeRefField(objRef: Word, iRef: Word, toIRNode: Option[IRNode]): Unit = {}
})
}
}
private def writeRelocRecs(group: FileGroup): Unit = {
???
//???
}
private def writeIDNameMap(): Unit = {
tryWithResource(Files.newBufferedWriter(idNameMapPath, StandardCharsets.UTF_8)) { writer =>
bundleSerializer.writeIDNameMap(writer)
......@@ -223,7 +244,7 @@ class AlignedOutputStream(os: OutputStream) extends Closeable {
if (remain > 0) {
transfer(nextAddr, remain.toInt)
}
position += size
}
......
......@@ -15,9 +15,10 @@ import uvm.refimpl.mem.Space
import uvm.refimpl.mem.TypeSizes
import uvm.refimpl.mem.TypeSizes.Word
import uvm.refimpl.mem.scanning.MemoryDataScanner
import uvm.refimpl.mem.scanning.RefFieldHandler
import uvm.ssavariables._
import uvm.types._
import uvm.refimpl.mem.scanning.MemoryFieldHandler
import uvm.ir.irbuilder.IRNode
object TransitiveClosure {
def apply[T](initialElems: T*) = new TransitiveClosure(initialElems)
......@@ -63,7 +64,7 @@ object TransitiveClosureBuilder {
case class GlobalCellRec(begin: Word, end: Word, g: GlobalCell)
}
class TransitiveClosureBuilder(initialSet: Seq[TopLevel])(implicit microVM: MicroVM) extends RefFieldHandler {
class TransitiveClosureBuilder(initialSet: Seq[TopLevel])(implicit microVM: MicroVM) extends MemoryFieldHandler {
import TransitiveClosureBuilder._
private val globalMemory: Space = microVM.memoryManager.globalMemory
......@@ -291,48 +292,55 @@ class TransitiveClosureBuilder(initialSet: Seq[TopLevel])(implicit microVM: Micr
MemoryDataScanner.scanAllocUnit(begin, this)
}
def boxToHeap(box: HasObjRef): Option[Word] =
throw new BootImageBuilderException("BUG: Box should not have been scanned during boot image building.")
def boxToStack(box: BoxStack): Option[InterpreterStack] =
throw new BootImageBuilderException("BUG: Box should not have been scanned during boot image building.")
def memToHeap(objRef: Word, iRef: Word, toObj: Word, isWeak: Boolean, isTR64: Boolean): Option[Word] = {
override def visitRefField(objRef: Word, iRef: Word, toObj: Word, isWeak: Boolean): Unit = {
if (toObj != 0L) {
allocs += toObj
Some(toObj)
} else {
None
}
}
override def memToNonHeap(objRef: Word, iRef: Word, addr: Word): Unit = {
require(globalMemory.isInSpace(addr), {
val inLOS = largeObjectSpace.isInSpace(addr)
("Error: Non-heap internal reference not referring to global space. objRef: 0x%x, iref: 0x%x, target: 0x%x, inLOS: %s. " +
"If the address is in the large object space, it may refer to a stack cell (ALLOCA)").format(
objRef, iRef, addr, inLOS)
})
val gr = getGlobalCellRec(addr)
tls += gr.g
override def visitIRefField(objRef: Word, iRef: Word, toObj: Word, toOffset: Word): Unit = {
if (toObj == 0L) {
if (globalMemory.isInSpace(toOffset)) {
val gr = getGlobalCellRec(toOffset)
tls += gr.g
} else {
if (largeObjectSpace.isInSpace(toOffset)) {
throw new BootImageBuilderException(("Error: non-object iref to LOS found. This is probably a reference to " +
"a stack cell (ALLOCA). It should not exist during boot image building. source: [0x%x + 0x%x] -> dest 0x%x").format(
objRef, iRef, toOffset))
} else {
throw new BootImageBuilderException(("Error: non-object iref not referring to global. source: [0x%x + 0x%x] -> dest 0x%x").format(
objRef, iRef, toOffset))
}
}
} else {
if (toObj != 0L) {
allocs += toObj
}
}
}
def memToStack(objRef: Word, iRef: Word, toStack: Option[InterpreterStack]): Option[InterpreterStack] = {
if (toStack.isDefined) {
throw new BootImageBuilderException(
"Error: Stack reachable during boot image building. From: obj 0x%x, iref 0x%x. To stack id: %d".format(
objRef, iRef, toStack.get.id))
override def visitTagRefField(objRef: Word, iRef: Word, toObj: Word): Unit = {
if (toObj != 0L) {
allocs += toObj
}
None
}
def stackToStackMem(stack: InterpreterStack, toObj: Word): Option[Word] =
throw new BootImageBuilderException("BUG: Stack should not have been scanned during boot image building.")
def threadToStack(thread: InterpreterThread, toStack: Option[InterpreterStack]): Option[InterpreterStack] =
throw new BootImageBuilderException("BUG: Thread should not have been scanned during boot image building.")
def pinSetToMem(toObj: Word): Option[Word] =
throw new BootImageBuilderException("BUG: Pin set should not have been scanned during boot image building.")
override def visitFuncRefField(objRef: Word, iRef: Word, toFunc: Option[Function]): Unit = {
toFunc.foreach(tls+=)
}
override def visitStackRefField(objRef: Word, iRef: Word, toStack: Option[InterpreterStack]): Unit =
toStack.foreach(o => throw noReach("stack", objRef, iRef, o))
override def visitThreadRefField(objRef: Word, iRef: Word, toThread: Option[InterpreterThread]): Unit =
toThread.foreach(o => throw noReach("thread", objRef, iRef, o))
override def visitFCRefField(objRef: Word, iRef: Word, toFCRef: Option[FrameCursor]): Unit =
toFCRef.foreach(o => throw noReach("frame cursor", objRef, iRef, o))
override def visitIRNodeRefField(objRef: Word, iRef: Word, toIRNode: Option[IRNode]): Unit =
toIRNode.foreach(o => throw noReach("IR node", objRef, iRef, o))
private def noReach(kind: String, objRef: Word, iRef: Word, obj: AnyRef) =
new BootImageBuilderException(
"Error: Non-null %s field is not allowed in boot image. From: obj 0x%x, iref 0x%x. To stack id: %s".format(
objRef, iRef, obj))
}
\ No newline at end of file
......@@ -35,3 +35,6 @@ class UvmIllegalMemoryAccessException(message: String = null, cause: Throwable =
/** Thrown on syntax errors in HAIL scripts. */
class UvmHailParsingException(message: String = null, cause: Throwable = null) extends UvmRefImplException(message, cause)
/** Thrown if a number does not match any entity when using ObjectKeepers. */
class UvmUnknownIDException(message: String = null, cause: Throwable = null) extends UvmRuntimeException(message, cause)
......@@ -10,6 +10,7 @@ import com.typesafe.scalalogging.Logger
import uvm.refimpl.nat.NativeCallHelper
import uvm.utils.IDFactory
import uvm.refimpl.UvmRuntimeException
import uvm.refimpl.UvmUnknownIDException
/**
* An object with this trait can be uniquely identified within a MicroVM using an Int ID.
......@@ -32,7 +33,12 @@ class IDObjectKeeper[T <: HasID](val kind: String) {
val idFactory = new IDFactory(1)
/** Get an object by its ID. */
def apply(id: Int) = registry.apply(id)
def apply(id: Int) = try {
registry.apply(id)
} catch {
case e: NoSuchElementException => throw new UvmUnknownIDException(
"Attempted to lookup %s object by ID %d, but it is not found".format(kind, id))
}
/** Get an object by its ID, handle non-existing cases. */
def get(id: Int) = registry.get(id)
......
......@@ -665,17 +665,14 @@ object MemoryOperations {
* Load irnoderef value from the memory. Use fake value from microVM.irNodeRegistry
*/
def loadIRNode(loc: Word)(implicit microVM: MicroVM, memorySupport: MemorySupport): Option[IRNode] = {
val irNodeLong = memorySupport.loadLong(loc).toInt
val maybeIRNode = microVM.irNodeRegistry.longToObj(irNodeLong)
maybeIRNode
memorySupport.loadEntity[IRNode](loc)
}
/**
* Store irnoderef value into the memory. Use fake value from microVM.irNodeRegistry
*/
def storeIRNode(loc: Word, maybeIRNode: Option[IRNode])(implicit microVM: MicroVM, memorySupport: MemorySupport): Unit = {
val irNodeLong = microVM.irNodeRegistry.objGetLong(maybeIRNode)
memorySupport.storeLong(loc, irNodeLong)
memorySupport.storeEntity(loc, maybeIRNode)
}
def loadInt32Array(base: Word, len: Word)(implicit memorySupport: MemorySupport): IndexedSeq[Int] = {
......
......@@ -7,11 +7,22 @@ import jnr.ffi.{ Runtime, Memory, Pointer }
import uvm.refimpl.UvmRuntimeException
import uvm.refimpl.UvmIllegalMemoryAccessException
import uvm.refimpl.nat.NativeSupport
import scala.annotation.implicitNotFound
import uvm.refimpl.MicroVM
import uvm.Function
import uvm.refimpl.itpr.InterpreterThread
import uvm.refimpl.itpr.InterpreterStack
import uvm.ir.irbuilder.IRNode
import uvm.refimpl.UvmUnknownIDException
import uvm.refimpl.UvmRefImplException
import uvm.refimpl.itpr.FrameCursor
/**
* Support for native memory access. Backed by JNR-FFI.
*/
class MemorySupport(val muMemorySize: Word) {
import EntityAccessors._
val jnrRuntime = NativeSupport.jnrRuntime
val theMemory = NativeSupport.theMemory
......@@ -130,6 +141,42 @@ class MemorySupport(val muMemorySize: Word) {
return oldVal
}
def loadEntity[T: CanBeIntegerized](addr: Word)(implicit microVM: MicroVM): Option[T] = {
val num = loadLong(addr, inMu = true)
val obj = try {
implicitly[CanBeIntegerized[T]].deIntegerize(num)
} catch {
case e: UvmUnknownIDException =>
throw new UvmRefImplException("Memory location 0x%x referring to non-existing entity %d".format(addr, num), e)
}
obj
}
def storeEntity[T: CanBeIntegerized](addr: Word, obj: Option[T])(implicit microVM: MicroVM): Unit = {
val num = implicitly[CanBeIntegerized[T]].integerize(obj)
storeLong(addr, num, inMu = true)
}
def cmpXchgEntity[T: CanBeIntegerized](addr: Word, expected: Option[T], desired: Option[T])(
implicit microVM: MicroVM): (Boolean, Option[T]) = {
val numExpected = implicitly[CanBeIntegerized[T]].integerize(expected)
val numDesired = implicitly[CanBeIntegerized[T]].integerize(expected)
val (succ, oldNum) = cmpXchgLong(addr, numExpected, numDesired, inMu = true)
val oldObj = try {
implicitly[CanBeIntegerized[T]].deIntegerize(oldNum)
} catch {
case e: UvmUnknownIDException =>
throw new UvmRefImplException("Memory location 0x%x referring to non-existing entity %d".format(addr, oldNum), e)
}
(succ, oldObj)
}
def xchgEntity[T: CanBeIntegerized](addr: Word, desired: Option[T])(implicit microVM: MicroVM): Option[T] = {
val oldVal = loadEntity[T](addr)
storeEntity[T](addr, desired)
return oldVal
}
def memset(addr: Word, size: Word, value: Byte): Unit = {
theMemory.setMemory(addr, size, value)
}
......@@ -150,3 +197,46 @@ class MemorySupport(val muMemorySize: Word) {
theMemory.put(addr, dest, 0, len.toInt)
}
}
object EntityAccessors {
@implicitNotFound("Mu entity type ${T} cannot be represented as an integer, thus cannot be loaded/stored from the memory.")
trait CanBeIntegerized[T] {
protected def _integerize(obj: T)(implicit microVM: MicroVM): Word
protected def _deIntegerize(num: Word)(implicit microVM: MicroVM): T
def integerize(obj: Option[T])(implicit microVM: MicroVM): Word =
obj.map(_integerize).getOrElse(0L)
def deIntegerize(num: Word)(implicit microVM: MicroVM): Option[T] = {
if (num == 0L) {
None
} else {
Some(_deIntegerize(num))
}
}
}
implicit object FunctionIntegerizer extends CanBeIntegerized[Function] {
def _integerize(obj: Function)(implicit microVM: MicroVM): Word = obj.id.toLong
def _deIntegerize(num: Word)(implicit microVM: MicroVM): Function = microVM.globalBundle.funcNs(num.toInt)
}
implicit object ThreadIntegerizer extends CanBeIntegerized[InterpreterThread] {
def _integerize(obj: InterpreterThread)(implicit microVM: MicroVM): Word = obj.id.toLong
def _deIntegerize(num: Word)(implicit microVM: MicroVM): InterpreterThread = microVM.threadStackManager.threadRegistry(num.toInt)
}
implicit object StackIntegerizer extends CanBeIntegerized[InterpreterStack] {
def _integerize(obj: InterpreterStack)(implicit microVM: MicroVM): Word = obj.id.toLong
def _deIntegerize(num: Word)(implicit microVM: MicroVM): InterpreterStack = microVM.threadStackManager.stackRegistry(num.toInt)
}
implicit object FrameCursorIntegerizer extends CanBeIntegerized[FrameCursor] {
def _integerize(obj: FrameCursor)(implicit microVM: MicroVM): Word = obj.id.toLong
def _deIntegerize(num: Word)(implicit microVM: MicroVM): FrameCursor = microVM.threadStackManager.frameCursorRegistry(num.toInt)
}
implicit object IRNodeIntegerizer extends CanBeIntegerized[IRNode] {
def _integerize(obj: IRNode)(implicit microVM: MicroVM): Word = microVM.irNodeRegistry.objGetLong(obj)
def _deIntegerize(num: Word)(implicit microVM: MicroVM): IRNode = microVM.irNodeRegistry.longToObj(num)
}
}
......@@ -9,29 +9,25 @@ import scala.collection.mutable.HashMap
* Similar to JFFI's object exposer.
*/
class SequentialObjectKeeper[T] {
private val longToObj = new HashMap[Long, T]()
private val objToLong = new HashMap[T, Long]()
private val longToObjMap = new HashMap[Long, T]()
private val objToLongMap = new HashMap[T, Long]()
var nextLong = 1L
def objGetLong(maybeObj: Option[T]): Long = {
maybeObj match {
case None => 0L
case Some(obj) =>
objToLong.getOrElseUpdate(obj, {
val myLong = nextLong
nextLong += 1
longToObj(myLong) = obj
myLong
})
}
def objGetLong(obj: T): Long = {
objToLongMap.getOrElseUpdate(obj, {
val myLong = nextLong
nextLong += 1
longToObjMap(myLong) = obj
myLong
})
}
def longToObj(l: Long): Option[T] = longToObj.get(l)
def longToObj(l: Long): T = longToObjMap.apply(l)
def maybeRemoveObj(obj: T): Unit = {
objToLong.remove(obj).foreach { l =>
longToObj.remove(l)
objToLongMap.remove(obj).foreach { l =>
longToObjMap.remove(l)
}
}
}
\ No newline at end of file
......@@ -8,6 +8,8 @@ import com.typesafe.scalalogging.StrictLogging
import TypeSizes._
import com.typesafe.scalalogging.Logger
import org.slf4j.LoggerFactory
import uvm.Function
import uvm.ir.irbuilder.IRNode
object MemoryDataScanner extends StrictLogging {
......@@ -17,7 +19,7 @@ object MemoryDataScanner extends StrictLogging {
* Scan an allocation unit. In this implementation, heap objects, alloca cells and global
* cells all have the same layout.
*/
def scanAllocUnit(objRef: Word, handler: RefFieldHandler)(implicit microVM: MicroVM, memorySupport: MemorySupport) {
def scanAllocUnit(objRef: Word, handler: MemoryFieldHandler)(implicit microVM: MicroVM, memorySupport: MemorySupport) {
val tag = HeaderUtils.getTag(objRef)
logger.debug("Obj 0x%x, tag 0x%x".format(objRef, tag))
val ty = HeaderUtils.getType(microVM, tag)
......@@ -33,7 +35,7 @@ object MemoryDataScanner extends StrictLogging {
scanField(ty, objRef, objRef, handler)
}
def scanField(ty: Type, objRef: Word, iRef: Word, handler: RefFieldHandler)(implicit microVM: MicroVM, memorySupport: MemorySupport) {
def scanField(ty: Type, objRef: Word, iRef: Word, handler: MemoryFieldHandler)(implicit microVM: MicroVM, memorySupport: MemorySupport) {
def logField(kind: String, toObj: Word): String = "%s field [0x%x + 0x%x] = 0x%x -> 0x%x".format(kind, objRef, iRef - objRef, iRef, toObj)
def logIRefField(kind: String, toObj: Word, offset: Word): String = "%s field [0x%x + 0x%x] = 0x%x -> 0x%x + 0x%x = 0x%x".format(
kind, objRef, iRef - objRef, iRef, toObj, offset, toObj + offset)
......@@ -41,22 +43,18 @@ object MemoryDataScanner extends StrictLogging {
case t: TypeRef => {
val toObj = memorySupport.loadLong(iRef)
logger.debug(logField("Ref", toObj))
handler.memToHeap(objRef, iRef, toObj, false, false)
handler.visitRefField(objRef, iRef, toObj, false)
}
case t: TypeIRef => {
val toObj = memorySupport.loadLong(iRef)
val offset = memorySupport.loadLong(iRef + WORD_SIZE_BYTES)
logger.debug(logIRefField("IRef", toObj, offset))
if (toObj == 0L && offset != 0L) {
handler.memToNonHeap(objRef, iRef, offset)
} else {
handler.memToHeap(objRef, iRef, toObj, false, false)
}
handler.visitIRefField(objRef, iRef, toObj, offset)
}
case t: TypeWeakRef => {
val toObj = memorySupport.loadLong(iRef)
logger.debug(logField("WeakRef", toObj))
handler.memToHeap(objRef, iRef, toObj, true, false)
handler.visitRefField(objRef, iRef, toObj, true)
}
case t: TypeTagRef64 => {
val bits = memorySupport.loadLong(iRef)
......@@ -73,7 +71,7 @@ object MemoryDataScanner extends StrictLogging {
if (OpHelper.tr64IsRef(bits)) {
val toObj = OpHelper.tr64ToRef(bits)
logger.debug(logField("TagRef64", toObj))
handler.memToHeap(objRef, iRef, toObj, false, true)
handler.visitTagRefField(objRef, iRef, toObj)
}
}
case t: TypeStruct => {
......@@ -115,28 +113,24 @@ object MemoryDataScanner extends StrictLogging {
}
}
case t: TypeStackRef => {
val toStackID = memorySupport.loadLong(iRef)
val maybeToStack = if (toStackID == 0) {
None
} else {
val toStack = microVM.threadStackManager.stackRegistry.get(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)
val obj = memorySupport.loadEntity[InterpreterStack](iRef)
handler.visitStackRefField(objRef, iRef, obj)
}
case t: TypeFuncRef => {
val toFuncID = memorySupport.loadLong(iRef)
val maybeToFunc = if (toFuncID == 0) {
None
} else {
val toFunc = microVM.globalBundle.funcNs.get(toFuncID.toInt).getOrElse {
throw new UvmRefImplException("Memory location 0x%x referring to non-existing function %d".format(iRef, toFuncID))
}
Some(toFunc)
}
handler.memToFunc(objRef, iRef, maybeToFunc)
val obj = memorySupport.loadEntity[Function](iRef)
handler.visitFuncRefField(objRef, iRef, obj)
}
case t: TypeThreadRef => {
val obj = memorySupport.loadEntity[InterpreterThread](iRef)
handler.visitThreadRefField(objRef, iRef, obj)
}
case t: TypeFrameCursorRef => {
val obj = memorySupport.loadEntity[FrameCursor](iRef)
handler.visitFCRefField(objRef, iRef, obj)
}
case t: TypeIRNodeRef => {
val obj = memorySupport.loadEntity[IRNode](iRef)
handler.visitIRNodeRefField(objRef, iRef, obj)
}
case _ => // Ignore non-reference fields.
}
......
......@@ -11,6 +11,28 @@ import uvm.refimpl.UvmRefImplException
import org.slf4j.LoggerFactory
import com.typesafe.scalalogging.Logger
import uvm.Function
import uvm.refimpl.itpr.FrameCursor
import uvm.ir.irbuilder.IRNode
/**
* Handle general reference fields in the memory. This trait is mostly useful for the boot image builder.
* <p>
* As a convention, the parameter name "objRef" means the "beginning of an allocation unit", not limited to heap
* object; "iRef" is the address of the field itself.
*/
trait MemoryFieldHandler {
def visitRefField(objRef: Word, iRef: Word, toObj: Word, isWeak: Boolean): Unit
def visitIRefField(objRef: Word, iRef: Word, toObj: Word, toOffset: Word): Unit
/** This function is called only when the tagref is holding a reference. */
def visitTagRefField(objRef: Word, iRef: Word, toObj: Word): Unit
def visitFuncRefField(objRef: Word, iRef: Word, toFunc: Option[Function]): Unit
def visitStackRefField(objRef: Word, iRef: Word, toStack: Option[InterpreterStack]): Unit
def visitThreadRefField(objRef: Word, iRef: Word, toThread: Option[InterpreterThread]): Unit
def visitFCRefField(objRef: Word, iRef: Word, toFCRef: Option[FrameCursor]): Unit
def visitIRNodeRefField(objRef: Word, iRef: Word, toIRNode: Option[IRNode]): Unit
}
/**
* Handle references in the memory, value boxes or other Micro VM structures such as threads and stacks.
......@@ -22,7 +44,7 @@ import uvm.Function
* 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 {
trait RefFieldHandler extends MemoryFieldHandler {
/** 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. */
......@@ -37,18 +59,28 @@ trait RefFieldHandler {
def threadToStack(thread: InterpreterThread, toStack: Option[InterpreterStack]): Option[InterpreterStack]
/** Pin set referring to the memory. Pinned objects cannot be moved. */
def pinSetToMem(toObj: Word): Option[Word]
/**
* A memory location referring to non-heap Mu memory. For GC, such fields do not need to be traced. But
* boot image writers need them to track other global cells.
*/
def memToNonHeap(objRef: Word, iRef: Word, addr: Word): Unit = ()
/**
* A memory location referring to a Mu function. GC does not need to care about function references, but
* boot image builders need to find them so that functions can be relocated.
*/
def memToFunc(objRef: Word, iRef: Word, toFunc: Option[Function]): Unit = ()
def visitRefField(objRef: Word, iRef: Word, toObj: Word, isWeak: Boolean): Unit = {
memToHeap(objRef, iRef, toObj, isWeak, false)
}
def visitIRefField(objRef: Word, iRef: Word, toObj: Word, toOffset: Word): Unit = {
memToHeap(objRef, iRef, toObj, false, false)
}
/** This function is called only when the tagref is holding a reference. */
def visitTagRefField(objRef: Word, iRef: Word, toObj: Word): Unit = {
memToHeap(objRef, iRef, toObj, false, true)
}
def visitStackRefField(objRef: Word, iRef: Word, toStack: Option[InterpreterStack]): Unit = {
memToStack(objRef, iRef, toStack)
}
def visitFuncRefField(objRef: Word, iRef: Word, toFunc: Option[Function]): Unit = {}
def visitThreadRefField(objRef: Word, iRef: Word, toThread: Option[InterpreterThread]): Unit = {}
def visitFCRefField(objRef: Word, iRef: Word, toFCRef: Option[FrameCursor]): Unit = {}
def visitIRNodeRefField(objRef: Word, iRef: Word, toIRNode: Option[IRNode]): Unit = {}
}
object RefFieldUpdater {
......
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