Commit c3414084 authored by Kunshan Wang's avatar Kunshan Wang

Porting garbage collector...

parent 2376c1d9
......@@ -21,7 +21,7 @@ class MicroVM(heapSize: Word = MicroVM.DEFAULT_HEAP_SIZE,
val globalBundle = new Bundle()
val constantPool = new ConstantPool(this)
val memoryManager = new MemoryManager(heapSize, globalSize, stackSize, this)
//val threadStackManager = new ThreadStackManager(this)
val threadStackManager = new ThreadStackManager(this)
//val trapManager = new TrapManager(this)
val clientAgents = new HashSet[ClientAgent]()
......
package uvm.refimpl
import uvm._
import uvm.types._
import uvm.ssavariables._
import uvm.ir.textinput.IDFactory
import scala.collection.mutable.HashMap
import uvm.FuncSig
......@@ -19,15 +21,20 @@ object InternalTypes {
def internal(name: String) = "@uvm.internal.types." + name
val I1 = TypeInt(1) := internal("i1")
val I6 = TypeInt(6) := internal("i6")
val I52 = TypeInt(52) := internal("i52")
val I64 = TypeInt(52) := internal("i64")
val DOUBLE = TypeDouble() := internal("double")
val VOID = TypeVoid() := internal("void")
val BYTE = TypeInt(8) := internal("byte")
val BYTE_ARRAY = TypeHybrid(VOID, BYTE) := internal("byte_array")
val DOUBLE = TypeDouble() := internal("double")
val I52 = TypeInt(52) := internal("i52")
val REF_VOID = TypeRef(VOID) := internal("ref_void")
val I6 = TypeInt(6) := internal("i6")
val STACK = TypeStack() := internal("stack")
val THREAD = TypeStack() := internal("thread")
val TAGREF64 = TypeTagRef64() := internal("tagref64")
}
......@@ -40,6 +47,83 @@ object InternalTypePool {
def apply[FromT, ToT](factory: FromT => ToT): LazyPool[FromT, ToT] = new LazyPool[FromT, ToT](factory)
}
val refOf = LazyPool(TypeRef)
val irefOf = LazyPool(TypeIRef)
val funcOf = LazyPool(TypeFunc)
val vecOf = new LazyPool[(Type, Long), TypeVector]({ case (t, l) => TypeVector(t, l) })
def unmarkedOf(t: Type): Type = t match {
case TypeWeakRef(r) => refOf(r)
case _ => t
}
}
object TypeInferer {
import InternalTypes._
import InternalTypePool._
def inferType(v: SSAVariable): Type = v match {
case c: Constant => c.constTy
case g: GlobalCell => irefOf(g.cellTy)
case f: Function => funcOf(f.sig)
case p: Parameter => p.funcVer.sig.paramTy(p.index)
case i: InstBinOp => i.opndTy
case i: InstCmp => I1
case i: InstConv => i.toTy
case i: InstSelect => i.opndTy
case i: InstBranch => VOID
case i: InstBranch2 => VOID
case i: InstSelect => i.opndTy
case i: InstPhi => i.opndTy
case i: InstCall => i.sig.retTy
case i: InstTailCall => VOID
case i: InstRet => VOID
case i: InstRetVoid => VOID
case i: InstThrow => VOID
case i: InstLandingPad => REF_VOID
case i: InstExtractValue => i.strTy.fieldTy(i.index)
case i: InstInsertValue => i.strTy
case i: InstExtractElement => i.vecTy.elemTy
case i: InstInsertElement => i.vecTy
case i: InstShuffleVector => vecOf((i.vecTy.elemTy, i.maskTy.len))
case i: InstNew => refOf(i.allocTy)
case i: InstNewHybrid => refOf(i.allocTy)
case i: InstAlloca => irefOf(i.allocTy)
case i: InstAllocaHybrid => irefOf(i.allocTy)
case i: InstGetIRef => irefOf(i.referentTy)
case i: InstGetFieldIRef => irefOf(i.referentTy.fieldTy(i.index))
case i: InstGetElemIRef => irefOf(i.referentTy.elemTy)
case i: InstShiftIRef => irefOf(i.referentTy)
case i: InstGetFixedPartIRef => irefOf(i.referentTy.fixedTy)
case i: InstGetVarPartIRef => irefOf(i.referentTy.varTy)
case i: InstLoad => unmarkedOf(i.referentTy)
case i: InstStore => VOID
case i: InstCmpXchg => unmarkedOf(i.referentTy)
case i: InstAtomicRMW => unmarkedOf(i.referentTy)
case i: InstFence => VOID
case i: InstTrap => i.retTy
case i: InstWatchPoint => i.retTy
case i: InstCCall => i.sig.retTy
case i: InstNewStack => STACK
case i: InstSwapStack => i.curStackAction match {
case RetWith(t) => t
case _: KillOld => VOID
}
case i: InstCommInst => i.inst.name.get match {
case "@uvm.new_thread" => THREAD
case "@uvm.kill_stack" => VOID
case "@uvm.thread_exit" => VOID
case "@uvm.current_stack" => STACK
case "@uvm.tr64.is_fp" => I1
case "@uvm.tr64.is_int" => I1
case "@uvm.tr64.is_ref" => I1
case "@uvm.tr64.from_fp" => TAGREF64
case "@uvm.tr64.from_int" => TAGREF64
case "@uvm.tr64.from_ref" => TAGREF64
case "@uvm.tr64.to_fp" => DOUBLE
case "@uvm.tr64.to_int" => I52
case "@uvm.tr64.to_ref" => REF_VOID
case "@uvm.tr64.to_tag" => I6
case "@uvm.futex.wait" => I64
case "@uvm.futex.wake" => I64
}
}
}
\ No newline at end of file
package uvm.refimpl.itpr
import uvm.Function
import uvm.refimpl.MicroVM
import uvm.refimpl.mem._
import scala.collection.mutable.HashMap
import scala.collection.mutable.ArrayBuffer
class ThreadStackManager(microVM: MicroVM) {
val stackRegistry = new HashMap[Int, InterpreterStack]()
val threadRegistry = new HashMap[Int, InterpreterThread]()
def getStackByID(id: Int): Option[InterpreterStack] = stackRegistry.get(id)
def getThreadByID(id: Int): Option[InterpreterThread] = threadRegistry.get(id)
private var nextStackID: Int = 1
private def makeStackID(): Int = {val id = nextStackID; nextStackID += 1; id}
private var nextThreadID: Int = 1
private def makeThreadID(): Int = {val id = nextThreadID; nextThreadID += 1; id}
def newStack(function: Function, args: Seq[ValueBox]): InterpreterStack = {
val stackMemory = microVM.memoryManager.makeStackMemory()
val id = makeStackID()
val sta = new InterpreterStack(id, stackMemory, function.versions.head, args)
stackRegistry.put(id, sta)
sta
}
def newThread(stack: InterpreterStack): InterpreterThread = {
val mutator = microVM.memoryManager.makeMutator()
val id = makeThreadID()
val thr = new InterpreterThread(id, microVM, stack, mutator)
threadRegistry.put(id, thr)
thr.start()
thr
}
def joinAll() {
var someRunning: Boolean = false
do {
someRunning = false
val curThreads = threadRegistry.values.toList
for (thr2 <- curThreads) {
thr2.step()
someRunning = thr2.isRunning || someRunning
}
} while (someRunning)
}
def joinThread(thr: InterpreterThread) {
while (thr.isRunning) {
val curThreads = threadRegistry.values.toList
for (thr2 <- curThreads) {
thr2.step()
}
}
}
}
package uvm.refimpl.itpr
import uvm._
import uvm.types._
import uvm.refimpl._
import uvm.refimpl.mem.TypeSizes.Word
abstract class ValueBox
......@@ -41,3 +43,24 @@ case class BoxTagRef64(var raw: Long) extends HasObjRef {
}
}
object ValueBox {
def makeBoxForType(ty: Type): ValueBox = ty match {
case _: TypeInt => BoxInt(0)
case _: TypeFloat => BoxFloat(0.0f)
case _: TypeDouble => BoxDouble(0.0d)
case TypeVector(elemTy, len) => BoxVector(Seq.fill(4)(makeBoxForType(elemTy)))
case _: TypeRef => BoxRef(0L)
case _: TypeIRef => BoxIRef(0L, 0L)
case _: TypeWeakRef => throw new UvmRefImplException("weakref cannot be an SSA variable type")
case TypeStruct(fieldTys) => BoxStruct(fieldTys.map(makeBoxForType))
case _: TypeArray => throw new UvmRefImplException("array cannot be an SSA variable type")
case _: TypeHybrid => throw new UvmRefImplException("hybrid cannot be an SSA variable type")
case _: TypeVoid => BoxVoid()
case _: TypeFunc => BoxFunc(None)
case _: TypeStack => BoxStack(None)
case _: TypeThread => BoxThread(None)
case _: TypeTagRef64 => BoxTagRef64(0L)
}
}
\ No newline at end of file
package uvm.refimpl.itpr
class InterpreterThread {
}
class InterpreterStack {
}
class InterpreterFrame {
}
\ No newline at end of file
package uvm.refimpl.itpr
import uvm._
import uvm.types._
import uvm.ssavariables._
import uvm.refimpl._
import uvm.refimpl.mem._
import scala.collection.mutable.HashMap
import scala.collection.AbstractIterator
abstract class StackState
object StackState {
case class Ready(t: Type) extends uvm.refimpl.itpr.StackState
case object Running extends StackState
case object Dead extends StackState
}
class InterpreterStack(val id: Int, val stackMemory: StackMemory, stackBottomFunc: FuncVer, args: Seq[ValueBox]) {
throw new UvmRefImplException("Not implemented")
var state: StackState = StackState.Ready(InternalTypes.VOID) // Initial state is READY<void>
var top: InterpreterFrame = new InterpreterFrame(stackBottomFunc, None) // Bottom frame
def frames: Iterator[InterpreterFrame] = new AbstractIterator[InterpreterFrame] {
var curFrame: Option[InterpreterFrame] = Some(top)
def hasNext = curFrame.isDefined
def next = {
val res = curFrame.get
curFrame = res.prev
res
}
}
}
class InterpreterFrame(val funcVer: FuncVer, val prev: Option[InterpreterFrame]) {
val boxes = new HashMap[LocalVariable, ValueBox]()
var curBB: BasicBlock = funcVer.entry
var curInstIndex: Int = 0
var savedStackPointer: Long = 0
makeBoxes()
private def makeBoxes() {
for (param <- funcVer.params) {
putBox(param)
}
for (bb <- funcVer.bbs; inst <- bb.insts) {
putBox(inst)
}
}
private def putBox(lv: LocalVariable) {
val ty = TypeInferer.inferType(lv)
boxes.put(lv, ValueBox.makeBoxForType(ty))
}
def curInst: Instruction = curBB.insts(curInstIndex)
def incPC() {
curInstIndex += 1
}
def jump(bb: BasicBlock, ix: Int) {
curBB = bb
curInstIndex = ix
}
def keepaliveBoxes(): Seq[ValueBox] = {
curInst match {
case hka: HasKeepAliveClause =>
val kas = hka.keepAlives
val kaBoxes = kas.map(boxes.apply)
kaBoxes
case i => throw new UvmRefImplException("Instruction does not have keepalives: " + i.repr)
}
}
}
\ No newline at end of file
package uvm.refimpl.itpr
import uvm._
import uvm.refimpl._
import uvm.refimpl.mem._
class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: InterpreterStack, val mutator: Mutator) {
var stack: Option[InterpreterStack] = Some(initialStack)
throw new UvmRefImplException("Not implemented")
def start(): Unit = {
throw new UvmRefImplException("Not implemented")
}
def isRunning: Boolean = {
throw new UvmRefImplException("Not implemented")
}
def step(): Unit = {
throw new UvmRefImplException("Not implemented")
}
}
package uvm.refimpl.mem
abstract class Collector extends Runnable() {
override def run() {
try {
while (true) {
park()
collect()
}
} catch {
case e: Exception => {
System.err.println("Error thrown from collection thread.")
e.printStackTrace()
System.exit(1)
}
}
}
private def park() {
getHeap.collectorWaitForGCStart()
}
protected def getHeap(): Heap
protected def collect(): Unit
}
......@@ -7,9 +7,9 @@ import uvm.refimpl.mem.TypeSizes._
import uvm.refimpl.mem.bumppointer.RewindableBumpPointerAllocator
import java.util.HashMap
class GlobalMemory(begin: Word, size: Word, microVM: MicroVM) extends Space("GlobalSpace", begin, size) {
class GlobalMemory(val begin: Word, val size: Word, microVM: MicroVM) extends Space("GlobalSpace", begin, size) {
private val allocator = new RewindableBumpPointerAllocator(begin, size, microVM)
val allocator = new RewindableBumpPointerAllocator(begin, size, microVM)
private val locationMap = new HashMap[GlobalCell, Word]()
......
......@@ -8,38 +8,38 @@ import org.slf4j.LoggerFactory
object HeaderUtils extends StrictLogging {
def postAllocScalar(addr: Word, tag: Long) {
def postAllocScalar(addr: Word, tag: Word) {
setTag(addr, tag)
}
def postAllocHybrid(addr: Word, tag: Long, len: Long) {
def postAllocHybrid(addr: Word, tag: Word, len: Word) {
postAllocScalar(addr, tag)
setVarLength(addr, len)
}
def getTag(objRef: Word): Long = {
def getTag(objRef: Word): Word = {
MemorySupport.loadLong(objRef + TypeSizes.GC_HEADER_OFFSET_TAG)
}
def getVarLength(objRef: Word): Long = {
def getVarLength(objRef: Word): Word = {
MemorySupport.loadLong(objRef + TypeSizes.GC_HEADER_OFFSET_HYBRID_LENGTH)
}
def setTag(objRef: Word, tag: Long) {
def setTag(objRef: Word, tag: Word) {
logger.debug(s"Storing tag ${tag} at addr ${TypeSizes.GC_HEADER_OFFSET_TAG}")
MemorySupport.storeLong(objRef + TypeSizes.GC_HEADER_OFFSET_TAG, tag)
}
def setVarLength(objRef: Word, len: Long) {
def setVarLength(objRef: Word, len: Word) {
MemorySupport.storeLong(objRef + TypeSizes.GC_HEADER_OFFSET_HYBRID_LENGTH, len)
}
def getTypeID(tag: Long): Int = (tag & 0x00000000ffffffffL).toInt
def getTypeID(tag: Word): Int = (tag & 0x00000000ffffffffL).toInt
def getType(microVM: MicroVM, tag: Long): Type = {
def getType(microVM: MicroVM, tag: Word): Type = {
val typeID = getTypeID(tag)
microVM.globalBundle.typeNs(typeID)
}
def getForwardedDest(oldHeader: Long): Long = oldHeader & 0x0000ffffffffffffL
def getForwardedDest(oldHeader: Word): Word = oldHeader & 0x0000ffffffffffffL
}
package uvm.refimpl.mem
import java.util.concurrent.locks._
import Heap._
import uvm.refimpl.UvmRefImplException
object Heap {
protected val MUTATOR_RUNNING = 0
protected val DOING_GC = 1
}
abstract class Heap {
protected val lock: Lock = new ReentrantLock()
protected val gcCanStart: Condition = lock.newCondition()
protected val gcFinished: Condition = lock.newCondition()
protected var gcState: Int = _
protected var mustFreeSpace: Boolean = _
def mutatorTriggerAndWaitForGCEnd(mustFreeSpace: Boolean) {
lock.lock()
try {
triggerGC(mustFreeSpace)
mutatorWaitForGCEnd()
} finally {
lock.unlock()
}
}
private def triggerGC(mustFreeSpace: Boolean) {
lock.lock()
try {
assert((gcState == MUTATOR_RUNNING))
gcState = DOING_GC
this.mustFreeSpace = mustFreeSpace
gcCanStart.signalAll()
} finally {
lock.unlock()
}
}
private def mutatorWaitForGCEnd() {
lock.lock()
try {
while (gcState != MUTATOR_RUNNING) {
try {
gcFinished.await()
} catch {
case e: InterruptedException => throw new UvmRefImplException("Interrupted while waiting for GC. Stop.")
}
}
} finally {
lock.unlock()
}
}
def untriggerGC() {
lock.lock()
try {
assert((gcState == DOING_GC))
gcState = MUTATOR_RUNNING
gcFinished.signalAll()
} finally {
lock.unlock()
}
}
def collectorWaitForGCStart() {
lock.lock()
while (gcState != DOING_GC) {
try {
gcCanStart.await()
} catch {
case e: InterruptedException => throw new UvmRefImplException("GC thread is interrupted.")
}
}
lock.unlock()
}
def makeMutator(): Mutator
def getMustFreeSpace(): Boolean = mustFreeSpace
}
......@@ -15,7 +15,7 @@ object MemUtils extends StrictLogging {
}
}
def memcpy(src: Long, dst: Word, length: Word) {
def memcpy(src: Word, dst: Word, length: Word) {
logger.debug("Copying [${src} -> ${dst}] ${length} bytes")
var a: Word = 0
while (a < length) {
......
package uvm.refimpl.mem
import uvm.refimpl.MicroVM
//import uvm.refimpl.mem.MicroVMInternalTypes
//import uvm.refimpl.mem.simpleimmix.SimpleImmixHeap
import uvm.refimpl._
import TypeSizes._
import uvm.refimpl.mem.simpleimmix._
import MemoryManager._
object MemoryManager {
val MEMORY_BEGIN = 0x100000L
}
class MemoryManager(val heapSize: Long,
val globalSize: Long,
val stackSize: Long,
val microVM: MicroVM) {
class MemoryManager(val heapSize: Word, val globalSize: Word, val stackSize: Word, microVM: MicroVM) {
// val heap = new SimpleImmixHeap(MEMORY_BEGIN, heapSize, microVM)
val heap = new SimpleImmixHeap(MEMORY_BEGIN, heapSize, microVM)
val globalMemory = new GlobalMemory(MEMORY_BEGIN + heapSize, globalSize, microVM)
// private val stacks = new ArrayList[StackMemory]()
private val internalMutator = heap.makeMutator()
// private val internalMutator = heap.makeMutator()
def makeMutator(): Mutator = heap.makeMutator()
// def makeMutator(): Mutator = heap.makeMutator()
// def makeStackMemory(): StackMemory = {
// val objRef = internalMutator.newHybrid(MicroVMInternalTypes.BYTE_ARRAY_TYPE, stackSize)
// val stackMemory = new StackMemory(objRef, stackSize, microVM)
// stackMemory
// }
def makeStackMemory(): StackMemory = {
val objRef = internalMutator.newHybrid(InternalTypes.BYTE_ARRAY, stackSize)
val stackMemory = new StackMemory(objRef, stackSize, microVM)
stackMemory
}
}
package uvm.refimpl.mem
import uvm.types._
import TypeSizes._
abstract class Mutator {
def alloc(size: Word, align: Word, headerSize: Word): Word
def newScalar(ty: Type): Word = {
val tag = ty.id
val size = sizeOf(ty)
val align = alignOf(ty)
val objAddr = alloc(size, align, GC_HEADER_SIZE_SCALAR)
HeaderUtils.postAllocScalar(objAddr, tag)
objAddr
}
def newHybrid(ty: TypeHybrid, len: Word): Word = {
val tag = ty.id
val size = hybridSizeOf(ty, len)
val align = hybridAlignOf(ty, len)
val objAddr = alloc(size, align, GC_HEADER_SIZE_HYBRID)
HeaderUtils.postAllocHybrid(objAddr, tag, len)
objAddr
}
def allocaScalar(sm: StackMemory, ty: Type): Word = {
val tag = ty.id
val size = sizeOf(ty)
val align = alignOf(ty)
val objAddr = sm.alloc(size, align, GC_HEADER_SIZE_SCALAR)
HeaderUtils.postAllocScalar(objAddr, tag)
objAddr
}
def allocaHybrid(sm: StackMemory, ty: TypeHybrid, len: Word): Word = {
val tag = ty.id
val size = hybridSizeOf(ty, len)
val align = hybridAlignOf(ty, len)
val objAddr = sm.alloc(size, align, GC_HEADER_SIZE_HYBRID)
HeaderUtils.postAllocHybrid(objAddr, tag, len)
objAddr
}
def close(): Unit
}
......@@ -10,12 +10,12 @@ object Space {
spaces = space :: spaces
}
def getSpaceForAddress(addr: Long): Option[Space] = {
def getSpaceForAddress(addr: Word): Option[Space] = {
spaces.find(_.isInSpace(addr))
}
}
class Space(val name: String, val begin: Long, val extend: Long) {
class Space(val name: String, val begin: Word, val extend: Word) {
addSpace(this)
def isInSpace(addr: Word): Boolean = begin <= addr && addr < begin + extend
......
package uvm.refimpl.mem
import uvm.refimpl.MicroVM
import uvm.refimpl.mem.bumppointer.RewindableBumpPointerAllocator
import TypeSizes.Word
class StackMemory(val stackObjRef: Word, val extend: Word, microVM: MicroVM)
extends RewindableBumpPointerAllocator(stackObjRef, extend, microVM)
......@@ -14,13 +14,13 @@ object RewindableBumpPointerAllocator {
val logger: Logger = Logger(LoggerFactory.getLogger(getClass.getName))
}
class RewindableBumpPointerAllocator(val begin: Long, val extend: Long, val microVM: MicroVM)
class RewindableBumpPointerAllocator(val begin: Word, val extend: Word, val microVM: MicroVM)
extends Allocator {
import RewindableBumpPointerAllocator._
var top: Long = begin
var top: Word = begin
override def alloc(size: Word, align: Word, headerSize: Word): Long = {
override def alloc(size: Word, align: Word, headerSize: Word): Word = {
val dataStart = top + WORD_SIZE_BYTES
val iRef = dataStart + headerSize
val dataEnd = iRef + size
......@@ -35,7 +35,7 @@ class RewindableBumpPointerAllocator(val begin: Long, val extend: Long, val micr
iRef
}
def rewind(newTop: Long) {
def rewind(newTop: Word) {
top = newTop
}
......@@ -54,7 +54,7 @@ class RewindableBumpPointerAllocator(val begin: Long, val extend: Long, val micr
val ty = microVM.globalBundle.typeNs(typeID)