WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

Commit c3414084 authored by Kunshan Wang's avatar Kunshan Wang
Browse files

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 {