Commit e4fdc4b2 authored by Kunshan Wang's avatar Kunshan Wang

Switched to JNR-FFI-based native memory access.

parent 1d03dfae
......@@ -17,12 +17,15 @@ object MicroVM {
class MicroVM(heapSize: Word = MicroVM.DEFAULT_HEAP_SIZE,
globalSize: Word = MicroVM.DEFAULT_GLOBAL_SIZE,
stackSize: Word = MicroVM.DEFAULT_STACK_SIZE) {
// implicitly injected resources
private implicit val microVM = this
val globalBundle = new Bundle()
val constantPool = new ConstantPool(this)
val memoryManager = new MemoryManager(heapSize, globalSize, stackSize, this)
val threadStackManager = new ThreadStackManager(this)
val trapManager = new TrapManager(this)
val constantPool = new ConstantPool()
val memoryManager = new MemoryManager(heapSize, globalSize, stackSize)
val threadStackManager = new ThreadStackManager()
val trapManager = new TrapManager()
val clientAgents = new HashSet[ClientAgent]()
val irReader = new UIRTextReader(new IDFactory())
......
......@@ -27,6 +27,11 @@ trait UndefinedFunctionHandler {
}
class ClientAgent(microVM: MicroVM) {
// Injectable resources (used by memory access operations)
private implicit val microVM_ = microVM
private implicit val memorySupport = microVM.memoryManager.memorySupport
val handles = new HashSet[Handle]()
microVM.clientAgents.add(this)
......@@ -252,7 +257,7 @@ class ClientAgent(microVM: MicroVM) {
val iRef = b.objRef + b.offset
val nb = ValueBox.makeBoxForType(uty)
MemoryOperations.load(uty, iRef, nb, microVM)
MemoryOperations.load(uty, iRef, nb)
newHandle(uty, nb)
}
......@@ -265,7 +270,7 @@ class ClientAgent(microVM: MicroVM) {
val nvb = newVal.vb
val nb = ValueBox.makeBoxForType(uty)
MemoryOperations.store(uty, iRef, nvb, nb, microVM)
MemoryOperations.store(uty, iRef, nvb, nb)
}
def cmpXchg(ordSucc: MemoryOrder, ordFail: MemoryOrder, weak: Boolean, loc: Handle, expected: Handle, desired: Handle): (Boolean, Handle) = {
......@@ -276,7 +281,7 @@ class ClientAgent(microVM: MicroVM) {
val eb = expected.vb
val db = desired.vb
val br = ValueBox.makeBoxForType(uty)
val succ = MemoryOperations.cmpXchg(uty, iRef, eb, db, br, microVM)
val succ = MemoryOperations.cmpXchg(uty, iRef, eb, db, br)
(succ, newHandle(uty, br))
}
......@@ -287,7 +292,7 @@ class ClientAgent(microVM: MicroVM) {
val iRef = lb.objRef + lb.offset
val ob = opnd.vb
val br = ValueBox.makeBoxForType(uty)
MemoryOperations.atomicRMW(uty, op, iRef, ob, br, microVM)
MemoryOperations.atomicRMW(uty, op, iRef, ob, br)
newHandle(uty, br)
}
......
......@@ -19,4 +19,7 @@ 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 clause is not present. */
class UvmDivisionByZeroException(message: String = null, cause: Throwable = null) extends UvmRuntimeException(message, cause)
\ No newline at end of file
class UvmDivisionByZeroException(message: String = null, cause: Throwable = null) extends UvmRuntimeException(message, cause)
/** Thrown when accessing Mu memory but the address is outside the allocated region. */
class UvmIllegalMemoryAccessException(message: String = null, cause: Throwable = null) extends UvmRuntimeException(message, cause)
......@@ -6,7 +6,7 @@ import uvm.ssavariables._
import uvm.refimpl.MicroVM
import scala.collection.mutable.HashMap
class ConstantPool(microVM: MicroVM) {
class ConstantPool(implicit microVM: MicroVM) {
val globalVarBoxes = HashMap[GlobalVariable, ValueBox]()
def addGlobalVar(g: GlobalVariable) {
......
......@@ -15,9 +15,12 @@ object InterpreterThread {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
}
class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: InterpreterStack, val mutator: Mutator) {
class InterpreterThread(val id: Int, implicit private val microVM: MicroVM, initialStack: InterpreterStack, val mutator: Mutator) {
import InterpreterThread._
// Injectable resources (used by memory access instructions)
implicit private val memorySupport = microVM.memoryManager.memorySupport
// Thread states
/** The underlying stack. */
......@@ -683,7 +686,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
if (la == 0L) {
nullRefError(excClause)
} else {
MemoryOperations.load(uty, la, ib, microVM)
MemoryOperations.load(uty, la, ib)
continueNormally()
}
}
......@@ -698,7 +701,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
if (la == 0L) {
nullRefError(excClause)
} else {
MemoryOperations.store(uty, la, nvb, ib, microVM)
MemoryOperations.store(uty, la, nvb, ib)
continueNormally()
}
}
......@@ -714,7 +717,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
if (la == 0L) {
nullRefError(excClause)
} else {
MemoryOperations.cmpXchg(uty, la, eb, db, ib, microVM)
MemoryOperations.cmpXchg(uty, la, eb, db, ib)
continueNormally()
}
}
......@@ -729,7 +732,7 @@ class InterpreterThread(val id: Int, microVM: MicroVM, initialStack: Interpreter
if (la == 0L) {
nullRefError(excClause)
} else {
MemoryOperations.atomicRMW(uty, op, la, ob, ib, microVM)
MemoryOperations.atomicRMW(uty, op, la, ob, ib)
continueNormally()
}
}
......
......@@ -12,7 +12,7 @@ object ThreadStackManager {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
}
class ThreadStackManager(microVM: MicroVM) {
class ThreadStackManager(implicit microVM: MicroVM) {
import ThreadStackManager._
private val stackRegistry = new HashMap[Int, InterpreterStack]()
......
......@@ -3,7 +3,7 @@ package uvm.refimpl.itpr
import uvm.refimpl._
import scala.collection.mutable.HashSet
class TrapManager(microVM: MicroVM) {
class TrapManager(implicit microVM: MicroVM) {
var trapHandler: TrapHandler = DefaultTrapHandler
var undefinedFunctionHandler: UndefinedFunctionHandler = DefaultUndefinedFunctionHandler
......
......@@ -283,44 +283,44 @@ object PrimOpHelpers {
}
object MemoryOperations {
def load(ty: Type, loc: Word, br: ValueBox, microVM: MicroVM): Unit = {
def load(ty: Type, loc: Word, br: ValueBox)(implicit microVM: MicroVM, memorySupport: MemorySupport): Unit = {
def loadScalar(ty: Type, loc: Word, br: ValueBox): Unit = ty match {
case TypeInt(l) =>
val bi: BigInt = l match {
case 8 => MemorySupport.loadByte(loc)
case 16 => MemorySupport.loadShort(loc)
case 32 => MemorySupport.loadInt(loc)
case 64 => MemorySupport.loadLong(loc)
case 8 => memorySupport.loadByte(loc)
case 16 => memorySupport.loadShort(loc)
case 32 => memorySupport.loadInt(loc)
case 64 => memorySupport.loadLong(loc)
case _ => throw new UnimplementedOprationException("Loading int of length %d is not supported".format(l))
}
br.asInstanceOf[BoxInt].value = OpHelper.unprepare(bi, l)
case _: TypeFloat =>
val fv = MemorySupport.loadFloat(loc)
val fv = memorySupport.loadFloat(loc)
br.asInstanceOf[BoxFloat].value = fv
case _: TypeDouble =>
val dv = MemorySupport.loadDouble(loc)
val dv = memorySupport.loadDouble(loc)
br.asInstanceOf[BoxDouble].value = dv
case _: TypeRef =>
val addr = MemorySupport.loadLong(loc)
val addr = memorySupport.loadLong(loc)
br.asInstanceOf[BoxRef].objRef = addr
case _: TypeIRef =>
val base = MemorySupport.loadLong(loc)
val offset = MemorySupport.loadLong(loc + WORD_SIZE_BYTES)
val base = memorySupport.loadLong(loc)
val offset = memorySupport.loadLong(loc + WORD_SIZE_BYTES)
br.asInstanceOf[BoxIRef].oo = (base, offset)
case _: TypeFunc =>
val fid = MemorySupport.loadLong(loc).toInt
val fid = memorySupport.loadLong(loc).toInt
val func = microVM.globalBundle.funcNs.get(fid)
br.asInstanceOf[BoxFunc].func = func
case _: TypeThread =>
val tid = MemorySupport.loadLong(loc).toInt
val tid = memorySupport.loadLong(loc).toInt
val thr = microVM.threadStackManager.getThreadByID(tid)
br.asInstanceOf[BoxThread].thread = thr
case _: TypeStack =>
val sid = MemorySupport.loadLong(loc).toInt
val sid = memorySupport.loadLong(loc).toInt
val sta = microVM.threadStackManager.getStackByID(sid)
br.asInstanceOf[BoxStack].stack = sta
case _: TypeTagRef64 =>
val raw = MemorySupport.loadLong(loc)
val raw = memorySupport.loadLong(loc)
br.asInstanceOf[BoxTagRef64].raw = raw
case _ => throw new UnimplementedOprationException("Loading of type %s is not supporing".format(ty.getClass.getName))
}
......@@ -336,42 +336,42 @@ object MemoryOperations {
}
}
def store(ty: Type, loc: Word, nvb: ValueBox, br: ValueBox, microVM: MicroVM): Unit = {
def store(ty: Type, loc: Word, nvb: ValueBox, br: ValueBox)(implicit memorySupport: MemorySupport): Unit = {
def storeScalar(ty: Type, loc: Word, nvb: ValueBox, br: ValueBox): Unit = ty match {
case TypeInt(l) =>
val bi = nvb.asInstanceOf[BoxInt].value
l match {
case 8 => MemorySupport.storeByte(loc, bi.byteValue)
case 16 => MemorySupport.storeShort(loc, bi.shortValue)
case 32 => MemorySupport.storeInt(loc, bi.intValue)
case 64 => MemorySupport.storeLong(loc, bi.longValue)
case 8 => memorySupport.storeByte(loc, bi.byteValue)
case 16 => memorySupport.storeShort(loc, bi.shortValue)
case 32 => memorySupport.storeInt(loc, bi.intValue)
case 64 => memorySupport.storeLong(loc, bi.longValue)
case _ => throw new UnimplementedOprationException("Storing int of length %d is not supported".format(l))
}
case _: TypeFloat =>
val fv = nvb.asInstanceOf[BoxFloat].value
MemorySupport.storeFloat(loc, fv)
memorySupport.storeFloat(loc, fv)
case _: TypeDouble =>
val dv = nvb.asInstanceOf[BoxDouble].value
MemorySupport.storeDouble(loc, dv)
memorySupport.storeDouble(loc, dv)
case _: TypeRef =>
val addr = nvb.asInstanceOf[BoxRef].objRef
MemorySupport.storeLong(loc, addr)
memorySupport.storeLong(loc, addr)
case _: TypeIRef =>
val BoxIRef(base, offset) = nvb.asInstanceOf[BoxIRef]
MemorySupport.storeLong(loc, base)
MemorySupport.storeLong(loc + WORD_SIZE_BYTES, offset)
memorySupport.storeLong(loc, base)
memorySupport.storeLong(loc + WORD_SIZE_BYTES, offset)
case _: TypeFunc =>
val fid = nvb.asInstanceOf[BoxFunc].func.map(_.id).getOrElse(0)
MemorySupport.storeLong(loc, fid.toLong & 0xFFFFFFFFL)
memorySupport.storeLong(loc, fid.toLong & 0xFFFFFFFFL)
case _: TypeThread =>
val tid = nvb.asInstanceOf[BoxThread].thread.map(_.id).getOrElse(0)
MemorySupport.storeLong(loc, tid.toLong & 0xFFFFFFFFL)
memorySupport.storeLong(loc, tid.toLong & 0xFFFFFFFFL)
case _: TypeStack =>
val sid = nvb.asInstanceOf[BoxStack].stack.map(_.id).getOrElse(0)
MemorySupport.storeLong(loc, sid.toLong & 0xFFFFFFFFL)
memorySupport.storeLong(loc, sid.toLong & 0xFFFFFFFFL)
case _: TypeTagRef64 =>
val raw = nvb.asInstanceOf[BoxTagRef64].raw
MemorySupport.storeLong(loc, raw)
memorySupport.storeLong(loc, raw)
case _ => throw new UnimplementedOprationException("Storing of type %s is not supporing".format(ty.getClass.getName))
}
......@@ -390,18 +390,18 @@ object MemoryOperations {
/**
* Compare exchange. The result (the old value) is written into br. Return true if successful, false otherwise.
*/
def cmpXchg(ty: Type, loc: Word, eb: ValueBox, db: ValueBox, br: ValueBox, microVM: MicroVM): Boolean = {
def cmpXchg(ty: Type, loc: Word, eb: ValueBox, db: ValueBox, br: ValueBox)(implicit microVM: MicroVM, memorySupport: MemorySupport): Boolean = {
ty match {
case TypeInt(l) =>
val ebi = eb.asInstanceOf[BoxInt].value
val dbi = db.asInstanceOf[BoxInt].value
val (succ, rbi) = l match {
case 32 => {
val (succ2, rv) = MemorySupport.cmpXchgInt(loc, ebi.intValue, dbi.intValue)
val (succ2, rv) = memorySupport.cmpXchgInt(loc, ebi.intValue, dbi.intValue)
(succ2, BigInt(rv))
}
case 64 => {
val (succ2, rv) = MemorySupport.cmpXchgLong(loc, ebi.longValue, dbi.longValue)
val (succ2, rv) = memorySupport.cmpXchgLong(loc, ebi.longValue, dbi.longValue)
(succ2, BigInt(rv))
}
case _ => throw new UnimplementedOprationException("CmpXchg on int of length %d is not supported".format(l))
......@@ -411,33 +411,33 @@ object MemoryOperations {
case _: TypeRef =>
val el = eb.asInstanceOf[BoxRef].objRef
val dl = db.asInstanceOf[BoxRef].objRef
val (succ, rl) = MemorySupport.cmpXchgLong(loc, el, dl)
val (succ, rl) = memorySupport.cmpXchgLong(loc, el, dl)
br.asInstanceOf[BoxRef].objRef = rl
succ
case _: TypeIRef =>
val BoxIRef(el, eh) = eb.asInstanceOf[BoxIRef]
val BoxIRef(dl, dh) = db.asInstanceOf[BoxIRef]
val (succ, (rl, rh)) = MemorySupport.cmpXchgI128(loc, (el, eh), (dl, dh))
val (succ, (rl, rh)) = memorySupport.cmpXchgI128(loc, (el, eh), (dl, dh))
br.asInstanceOf[BoxIRef].oo = (rl, rh)
succ
case _: TypeFunc =>
val el = eb.asInstanceOf[BoxFunc].func.map(_.id).getOrElse(0).toLong
val dl = db.asInstanceOf[BoxFunc].func.map(_.id).getOrElse(0).toLong
val (succ, rl) = MemorySupport.cmpXchgLong(loc, el, dl)
val (succ, rl) = memorySupport.cmpXchgLong(loc, el, dl)
val rf = microVM.globalBundle.funcNs.get(rl.toInt)
br.asInstanceOf[BoxFunc].func = rf
succ
case _: TypeThread =>
val el = eb.asInstanceOf[BoxThread].thread.map(_.id).getOrElse(0).toLong
val dl = db.asInstanceOf[BoxThread].thread.map(_.id).getOrElse(0).toLong
val (succ, rl) = MemorySupport.cmpXchgLong(loc, el, dl)
val (succ, rl) = memorySupport.cmpXchgLong(loc, el, dl)
val rt = microVM.threadStackManager.getThreadByID(rl.toInt)
br.asInstanceOf[BoxThread].thread = rt
succ
case _: TypeStack =>
val el = eb.asInstanceOf[BoxStack].stack.map(_.id).getOrElse(0).toLong
val dl = db.asInstanceOf[BoxStack].stack.map(_.id).getOrElse(0).toLong
val (succ, rl) = MemorySupport.cmpXchgLong(loc, el, dl)
val (succ, rl) = memorySupport.cmpXchgLong(loc, el, dl)
val rs = microVM.threadStackManager.getStackByID(rl.toInt)
br.asInstanceOf[BoxStack].stack = rs
succ
......@@ -445,13 +445,13 @@ object MemoryOperations {
}
}
def atomicRMW(ty: Type, op: AtomicRMWOptr, loc: Word, ob: ValueBox, br: ValueBox, microVM: MicroVM): Unit = {
def atomicRMW(ty: Type, op: AtomicRMWOptr, loc: Word, ob: ValueBox, br: ValueBox)(implicit microVM: MicroVM, memorySupport: MemorySupport): Unit = {
ty match {
case TypeInt(l) =>
val obi = ob.asInstanceOf[BoxInt].value
val rbi: BigInt = l match {
case 32 => MemorySupport.atomicRMWInt(op, loc, obi.intValue)
case 64 => MemorySupport.atomicRMWLong(op, loc, obi.longValue)
case 32 => memorySupport.atomicRMWInt(op, loc, obi.intValue)
case 64 => memorySupport.atomicRMWLong(op, loc, obi.longValue)
case _ => throw new UnimplementedOprationException("AtomicRMW on int of length %d is not supported".format(l))
}
br.asInstanceOf[BoxInt].value = OpHelper.unprepare(rbi, l)
......@@ -462,30 +462,30 @@ object MemoryOperations {
ty match {
case _: TypeRef =>
val ol = ob.asInstanceOf[BoxRef].objRef
val rl = MemorySupport.atomicRMWLong(op, loc, ol)
val rl = memorySupport.atomicRMWLong(op, loc, ol)
br.asInstanceOf[BoxRef].objRef = rl
case _: TypeIRef =>
val BoxIRef(ol, oh) = ob.asInstanceOf[BoxIRef]
val (rl, rh) = MemorySupport.xchgI128(loc, (ol, oh))
val (rl, rh) = memorySupport.xchgI128(loc, (ol, oh))
br.asInstanceOf[BoxIRef].oo = (rl, rh)
case _: TypeFunc =>
val ol = ob.asInstanceOf[BoxFunc].func.map(_.id).getOrElse(0).toLong
val rl = MemorySupport.atomicRMWLong(op, loc, ol)
val rl = memorySupport.atomicRMWLong(op, loc, ol)
val rf = microVM.globalBundle.funcNs.get(rl.toInt)
br.asInstanceOf[BoxFunc].func = rf
case _: TypeThread =>
val ol = ob.asInstanceOf[BoxThread].thread.map(_.id).getOrElse(0).toLong
val rl = MemorySupport.atomicRMWLong(op, loc, ol)
val rl = memorySupport.atomicRMWLong(op, loc, ol)
val rt = microVM.threadStackManager.getThreadByID(rl.toInt)
br.asInstanceOf[BoxThread].thread = rt
case _: TypeStack =>
val ol = ob.asInstanceOf[BoxStack].stack.map(_.id).getOrElse(0).toLong
val rl = MemorySupport.atomicRMWLong(op, loc, ol)
val rl = memorySupport.atomicRMWLong(op, loc, ol)
val rs = microVM.threadStackManager.getStackByID(rl.toInt)
br.asInstanceOf[BoxStack].stack = rs
case _: TypeTagRef64 =>
val ol = ob.asInstanceOf[BoxTagRef64].raw
val rl = MemorySupport.atomicRMWLong(op, loc, ol)
val rl = memorySupport.atomicRMWLong(op, loc, ol)
br.asInstanceOf[BoxTagRef64].raw = rl
case _ =>
throw new UnimplementedOprationException("AtomicRMW XCHG of type %s is not supporing".format(ty.getClass.getName))
......@@ -497,15 +497,15 @@ object MemoryOperations {
/**
* Check if a memory location still holds a particular value. Used by futex.
*/
def cmpInt(len: Int, loc: Word, expected: BoxInt): Boolean = len match {
def cmpInt(len: Int, loc: Word, expected: BoxInt)(implicit memorySupport: MemorySupport): Boolean = len match {
case 64 => {
val expNum = OpHelper.prepareSigned(expected.value, len).longValue
val actualNum = MemorySupport.loadLong(loc)
val actualNum = memorySupport.loadLong(loc)
expNum == actualNum
}
case 32 => {
val expNum = OpHelper.prepareSigned(expected.value, len).intValue
val actualNum = MemorySupport.loadInt(loc)
val actualNum = memorySupport.loadInt(loc)
expNum == actualNum
}
case _ => throw new UnimplementedOprationException("Futex of %d bit int is not supported".format(len))
......
......@@ -7,9 +7,11 @@ 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(begin: Word, size: Word)(
implicit microVM: MicroVM, memorySupport: MemorySupport)
extends Space("GlobalSpace", begin, size) {
val allocator = new RewindableBumpPointerAllocator(begin, size, microVM)
val allocator = new RewindableBumpPointerAllocator(begin, size)
private val locationMap = new HashMap[GlobalCell, Word]()
......
......@@ -6,32 +6,35 @@ import uvm.refimpl.mem.TypeSizes.Word
import com.typesafe.scalalogging._
import org.slf4j.LoggerFactory
/**
* Accessors to object headers. Require MemorySupport.
*/
object HeaderUtils extends StrictLogging {
def postAllocScalar(addr: Word, tag: Word) {
def postAllocScalar(addr: Word, tag: Word)(implicit memorySupport: MemorySupport) {
setTag(addr, tag)
}
def postAllocHybrid(addr: Word, tag: Word, len: Word) {
def postAllocHybrid(addr: Word, tag: Word, len: Word)(implicit memorySupport: MemorySupport) {
postAllocScalar(addr, tag)
setVarLength(addr, len)
}
def getTag(objRef: Word): Word = {
MemorySupport.loadLong(objRef + TypeSizes.GC_HEADER_OFFSET_TAG)
def getTag(objRef: Word)(implicit memorySupport: MemorySupport): Word = {
memorySupport.loadLong(objRef + TypeSizes.GC_HEADER_OFFSET_TAG)
}
def getVarLength(objRef: Word): Word = {
MemorySupport.loadLong(objRef + TypeSizes.GC_HEADER_OFFSET_HYBRID_LENGTH)
def getVarLength(objRef: Word)(implicit memorySupport: MemorySupport): Word = {
memorySupport.loadLong(objRef + TypeSizes.GC_HEADER_OFFSET_HYBRID_LENGTH)
}
def setTag(objRef: Word, tag: Word) {
def setTag(objRef: Word, tag: Word)(implicit memorySupport: MemorySupport) {
logger.debug("Storing tag 0x%x at addr 0x%x".format(tag, objRef + 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: Word) {
MemorySupport.storeLong(objRef + TypeSizes.GC_HEADER_OFFSET_HYBRID_LENGTH, len)
def setVarLength(objRef: Word, len: Word)(implicit memorySupport: MemorySupport) {
memorySupport.storeLong(objRef + TypeSizes.GC_HEADER_OFFSET_HYBRID_LENGTH, len)
}
def getTypeID(tag: Word): Int = (tag & 0x00000000ffffffffL).toInt
......
......@@ -5,22 +5,22 @@ import TypeSizes._
object MemUtils extends StrictLogging {
def zeroRegion(start: Word, length: Word) {
def zeroRegion(start: Word, length: Word)(implicit memorySupport: MemorySupport) {
val end = start + length
logger.debug("Zeroing [0x%x -> 0x%x] %d bytes".format(start, end, length))
var a = start
while (a < end) {
MemorySupport.storeLong(a, 0)
memorySupport.storeLong(a, 0L)
a += WORD_SIZE_BYTES
}
}
def memcpy(src: Word, dst: Word, length: Word) {
def memcpy(src: Word, dst: Word, length: Word)(implicit memorySupport: MemorySupport) {
logger.debug("Copying [0x%x -> 0x%x] %d bytes".format(src, dst, length))
var a: Word = 0
while (a < length) {
val oldWord = MemorySupport.loadLong(src + a)
MemorySupport.storeLong(dst + a, oldWord)
val oldWord = memorySupport.loadLong(src + a)
memorySupport.storeLong(dst + a, oldWord)
a += WORD_SIZE_BYTES
}
}
......
......@@ -3,23 +3,24 @@ package uvm.refimpl.mem
import uvm.refimpl._
import TypeSizes._
import uvm.refimpl.mem.simpleimmix._
import MemoryManager._
object MemoryManager {
val MEMORY_BEGIN = 0x100000L
}
class MemoryManager(val heapSize: Word, val globalSize: Word, val stackSize: Word, microVM: MicroVM) {
val heap = new SimpleImmixHeap(MEMORY_BEGIN, heapSize, microVM)
val globalMemory = new GlobalMemory(MEMORY_BEGIN + heapSize, globalSize, microVM)
class MemoryManager(val heapSize: Word, val globalSize: Word, val stackSize: Word)(implicit microVM: MicroVM) {
val totalMemorySize = heapSize + globalSize
implicit val memorySupport = new MemorySupport(totalMemorySize)
val memoryBegin = memorySupport.muMemoryBegin
val heapBegin = TypeSizes.alignUp(memoryBegin, SimpleImmixSpace.BLOCK_SIZE)
val heap = new SimpleImmixHeap(heapBegin, heapSize)
val globalMemory = new GlobalMemory(heapBegin + heapSize, globalSize)
def makeMutator(): Mutator = heap.makeMutator()
def makeStackMemory(mutator: Mutator): StackMemory = {
val objRef = mutator.newHybrid(InternalTypes.BYTE_ARRAY, stackSize)
val stackMemory = new StackMemory(objRef, stackSize, microVM)
val stackMemory = new StackMemory(objRef, stackSize)
stackMemory
}
}
......@@ -3,100 +3,129 @@ package uvm.refimpl.mem
import uvm.refimpl.mem.TypeSizes.Word
import java.nio.ByteBuffer
import uvm.ssavariables.AtomicRMWOptr._
import jnr.ffi.{ Runtime, Memory, Pointer }
import uvm.refimpl.UvmRuntimeException
import uvm.refimpl.UvmIllegalMemoryAccessException
object MemorySupport {
val MEMORY_SIZE: Word = 1024L * 1024L * 1024L
/**
* Support for native memory access. Backed by JNR-FFI.
*/
class MemorySupport(val muMemorySize: Word) {
val SIZE_LIMIT: Word = Int.MaxValue.toLong
val bb: ByteBuffer = ByteBuffer.allocateDirect(MEMORY_SIZE.toInt)
bb.order(java.nio.ByteOrder.LITTLE_ENDIAN)
if (muMemorySize > SIZE_LIMIT) {
throw new UvmRuntimeException("Memory too large (%d bytes requested)." +
" Due to the limitation of JNR-FFI, the maximum available memory size is %d bytes.".format(muMemorySize, SIZE_LIMIT))
}
val jnrRuntime = Runtime.getSystemRuntime
val muMemory = Memory.allocateDirect(jnrRuntime, muMemorySize.toInt, true)
val muMemoryBegin = muMemory.address()
val muMemoryEnd = muMemoryBegin + muMemorySize
val theMemory = Pointer.wrap(jnrRuntime, 0L)
def isInMuMemory(addr: Word): Boolean = muMemoryBegin <= addr && addr < muMemoryEnd
def assertInMuMemory(inMu: Boolean, addr: Word): Unit = {
if (inMu && !isInMuMemory(addr)) {
throw new UvmIllegalMemoryAccessException("Accessed address 0x%x outside the Mu memory [0x%x-0x%x].".format(addr, muMemoryBegin, muMemoryEnd))
}
}
def loadByte(loc: Word): Byte = bb.get(loc.toInt)
def loadShort(loc: Word): Short = bb.getShort(loc.toInt)
def loadInt(loc: Word): Int = bb.getInt(loc.toInt)
def loadLong(loc: Word): Long = bb.getLong(loc.toInt)
def loadI128(loc: Word): (Long, Long) = (bb.getLong(loc.toInt), bb.getLong(loc.toInt + 8))
def loadFloat(loc: Word): Float = bb.getFloat(loc.toInt)
def loadDouble(loc: Word): Double = bb.getDouble(loc.toInt)
def loadByte(addr: Word, inMu: Boolean = true): Byte = { assertInMuMemory(inMu, addr); theMemory.getByte(addr) }
def loadShort(addr: Word, inMu: Boolean = true): Short = { assertInMuMemory(inMu, addr); theMemory.getShort(addr) }
def loadInt(addr: Word, inMu: Boolean = true): Int = { assertInMuMemory(inMu, addr); theMemory.getInt(addr) }
def loadLong(addr: Word, inMu: Boolean = true): Long = { assertInMuMemory(inMu, addr); theMemory.getLong(addr) }
def loadI128(addr: Word, inMu: Boolean = true): (Long, Long) = { assertInMuMemory(inMu, addr); (theMemory.getLong(addr), theMemory.getLong(addr + 8)) }
def loadFloat(addr: Word, inMu: Boolean = true): Float = { assertInMuMemory(inMu, addr); theMemory.getFloat(addr) }
def loadDouble(addr: Word, inMu: Boolean = true): Double = { assertInMuMemory(inMu, addr); theMemory.getDouble(addr) }
def storeByte(loc: Word, v: Byte): Unit = bb.put(loc.toInt, v)
def storeShort(loc: Word, v: Short): Unit = bb.putShort(loc.toInt, v)
def storeInt(loc: Word, v: Int): Unit = bb.putInt(loc.toInt, v)
def storeLong(loc: Word, v: Long): Unit = bb.putLong(loc.toInt, v)
def storeI128(loc: Word, v: (Long, Long)): Unit = { val (low, high) = v; bb.putLong(loc.toInt, low); bb.putLong(loc.toInt + 8, high) }
def storeFloat(loc: Word, v: Float): Unit = bb.putFloat(loc.toInt, v)
def storeDouble(loc: Word, v: Double): Unit = bb.putDouble(loc.toInt, v)
def storeByte(addr: Word, v: Byte, inMu: Boolean = true): Unit = { assertInMuMemory(inMu, addr); theMemory.putByte(addr, v) }
def storeShort(addr: Word, v: Short, inMu: Boolean = true): Unit = { assertInMuMemory(inMu, addr); theMemory.putShort(addr, v) }
def storeInt(addr: Word, v: Int, inMu: Boolean = true): Unit = { assertInMuMemory(inMu, addr); theMemory.putInt(addr, v) }
def storeLong(addr: Word, v: Long, inMu: Boolean = true): Unit = { assertInMuMemory(inMu, addr); theMemory.putLong(addr, v) }
def storeI128(addr: Word, v: (Long, Long), inMu: Boolean = true): Unit = { assertInMuMemory(inMu, addr); val (low, high) = v; theMemory.putLong(addr, low); theMemory.putLong(addr + 8, high) }
def storeFloat(addr: Word, v: Float, inMu: Boolean = true): Unit = { assertInMuMemory(inMu, addr); theMemory.putFloat(addr, v) }
def storeDouble(addr: Word, v: Double, inMu: Boolean = true): Unit = { assertInMuMemory(inMu, addr); theMemory.putDouble(addr, v) }
def cmpXchgInt(loc: Word, expected: Int, desired: Int): (Boolean, Int) = {
val oldVal = loadInt(loc)
def cmpXchgInt(addr: Word, expected: Int, desired: Int, inMu: Boolean = true): (Boolean, Int) = {
assertInMuMemory(inMu, addr)
val oldVal = loadInt(addr)
if (oldVal == expected) {
storeInt(loc, desired)
storeInt(addr, desired)
return (true, oldVal)
} else {
return (false, oldVal)
}
}