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, ...@@ -21,7 +21,7 @@ class MicroVM(heapSize: Word = MicroVM.DEFAULT_HEAP_SIZE,
val globalBundle = new Bundle() val globalBundle = new Bundle()
val constantPool = new ConstantPool(this) val constantPool = new ConstantPool(this)
val memoryManager = new MemoryManager(heapSize, globalSize, stackSize, 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 trapManager = new TrapManager(this)
val clientAgents = new HashSet[ClientAgent]() val clientAgents = new HashSet[ClientAgent]()
......
package uvm.refimpl package uvm.refimpl
import uvm._
import uvm.types._ import uvm.types._
import uvm.ssavariables._
import uvm.ir.textinput.IDFactory import uvm.ir.textinput.IDFactory
import scala.collection.mutable.HashMap import scala.collection.mutable.HashMap
import uvm.FuncSig import uvm.FuncSig
...@@ -19,15 +21,20 @@ object InternalTypes { ...@@ -19,15 +21,20 @@ object InternalTypes {
def internal(name: String) = "@uvm.internal.types." + name 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 VOID = TypeVoid() := internal("void")
val BYTE = TypeInt(8) := internal("byte") val BYTE = TypeInt(8) := internal("byte")
val BYTE_ARRAY = TypeHybrid(VOID, BYTE) := internal("byte_array") 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 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") val TAGREF64 = TypeTagRef64() := internal("tagref64")
} }
...@@ -40,6 +47,83 @@ object InternalTypePool { ...@@ -40,6 +47,83 @@ object InternalTypePool {
def apply[FromT, ToT](factory: FromT => ToT): LazyPool[FromT, ToT] = new LazyPool[FromT, ToT](factory) def apply[FromT, ToT](factory: FromT => ToT): LazyPool[FromT, ToT] = new LazyPool[FromT, ToT](factory)
} }
val refOf = LazyPool(TypeRef)
val irefOf = LazyPool(TypeIRef) val irefOf = LazyPool(TypeIRef)
val funcOf = LazyPool(TypeFunc) 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 package uvm.refimpl.itpr
import uvm._ import uvm._
import uvm.types._
import uvm.refimpl._
import uvm.refimpl.mem.TypeSizes.Word import uvm.refimpl.mem.TypeSizes.Word
abstract class ValueBox abstract class ValueBox
...@@ -41,3 +43,24 @@ case class BoxTagRef64(var raw: Long) extends HasObjRef { ...@@ -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._ ...@@ -7,9 +7,9 @@ import uvm.refimpl.mem.TypeSizes._
import uvm.refimpl.mem.bumppointer.RewindableBumpPointerAllocator import uvm.refimpl.mem.bumppointer.RewindableBumpPointerAllocator
import java.util.HashMap 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]() private val locationMap = new HashMap[GlobalCell, Word]()
......
...@@ -8,38 +8,38 @@ import org.slf4j.LoggerFactory ...@@ -8,38 +8,38 @@ import org.slf4j.LoggerFactory
object HeaderUtils extends StrictLogging { object HeaderUtils extends StrictLogging {
def postAllocScalar(addr: Word, tag: Long) { def postAllocScalar(addr: Word, tag: Word) {
setTag(addr, tag) setTag(addr, tag)
} }
def postAllocHybrid(addr: Word, tag: Long, len: Long) { def postAllocHybrid(addr: Word, tag: Word, len: Word) {
postAllocScalar(addr, tag) postAllocScalar(addr, tag)
setVarLength(addr, len) setVarLength(addr, len)
} }
def getTag(objRef: Word): Long = { def getTag(objRef: Word): Word = {
MemorySupport.loadLong(objRef + TypeSizes.GC_HEADER_OFFSET_TAG) 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) 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}") logger.debug(s"Storing tag ${tag} at addr ${TypeSizes.GC_HEADER_OFFSET_TAG}")
MemorySupport.storeLong(objRef + TypeSizes.GC_HEADER_OFFSET_TAG, 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) 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) val typeID = getTypeID(tag)
microVM.globalBundle.typeNs(typeID) 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 { ...@@ -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") logger.debug("Copying [${src} -> ${dst}] ${length} bytes")
var a: Word = 0 var a: Word = 0
while (a < length) { while (a < length) {
......
package uvm.refimpl.mem package uvm.refimpl.mem
import uvm.refimpl.MicroVM import uvm.refimpl._
//import uvm.refimpl.mem.MicroVMInternalTypes import TypeSizes._
//import uvm.refimpl.mem.simpleimmix.SimpleImmixHeap import uvm.refimpl.mem.simpleimmix._
import MemoryManager._ import MemoryManager._
object MemoryManager { object MemoryManager {
val MEMORY_BEGIN = 0x100000L val MEMORY_BEGIN = 0x100000L
} }
class MemoryManager(val heapSize: Long, class MemoryManager(val heapSize: Word, val globalSize: Word, val stackSize: Word, microVM: MicroVM) {
val globalSize: Long,
val stackSize: Long,
val 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) 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(InternalTypes.BYTE_ARRAY, stackSize)
// def makeStackMemory(): StackMemory = { val stackMemory = new StackMemory(objRef, stackSize, microVM)
// val objRef = internalMutator.newHybrid(MicroVMInternalTypes.BYTE_ARRAY_TYPE, stackSize) stackMemory
// 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