Commit a6c7f08c authored by Kunshan Wang's avatar Kunshan Wang

WIP: Pointer allocs

parent af134956
......@@ -22,6 +22,7 @@ import uvm.refimpl.nat.NativeLibraryHolder
import uvm.staticanalysis.StaticAnalyzer
import uvm.utils.IDFactory
import uvm.utils.WithUtils.tryWithResource
import uvm.refimpl.bootimg.PrimordialInfo
object MicroVM {
val DEFAULT_SOS_SIZE: Word = 2L * 1024L * 1024L; // 2MiB
......@@ -177,17 +178,9 @@ class MicroVM(val vmConf: VMConf) extends IRBuilderListener {
* Make boot image.
*/
def makeBootImage(whiteList: Seq[MuID], outputFile: String): Unit = {
val whiteListObjs = whiteList.map { id =>
val obj = globalBundle.allNs(id)
obj match {
case tl: TopLevel => tl
case _ => throw new UvmRuntimeException(
"White list may only contain top-level definitions. Entity ID %d%s is a %s".format(
obj.id, obj.name.map(n => s" (${n})").getOrElse(""), obj.getClass.getName))
}
}
val whiteListObjs = whiteList.map(globalBundle.topLevelNs.apply)
bootImageBuilder.makeBootImage(whiteListObjs, outputFile)
bootImageBuilder.makeBootImage(whiteListObjs, PrimordialInfo.NO_PRIMORDIAL, Seq(), Seq(), outputFile)
}
/**
......
......@@ -20,6 +20,8 @@ import uvm.ssavariables.AtomicRMWOptr._
import uvm.ssavariables.HasKeepaliveClause
import uvm.ssavariables.MemoryOrder._
import uvm.types._
import uvm.refimpl.bootimg.FieldAndSymbol
import uvm.refimpl.bootimg.PrimordialInfo
object MuCtx {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
......@@ -189,9 +191,9 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
/** Compare general reference types for equality. */
def refEq(lhs: MuGenRefValue, rhs: MuGenRefValue): Boolean = (lhs, rhs) match {
case (l: MuRefValue, r: MuRefValue) => l.vb.objRef == r.vb.objRef
case (l: MuIRefValue, r: MuIRefValue) => l.vb.oo == r.vb.oo
case (l: MuOpaqueRefValue[_], r: MuOpaqueRefValue[_]) => l.vb.obj == r.vb.obj
case (l: MuRefValue, r: MuRefValue) => l.vb.objRef == r.vb.objRef
case (l: MuIRefValue, r: MuIRefValue) => l.vb.oo == r.vb.oo
case (l: MuOpaqueRefValue[_], r: MuOpaqueRefValue[_]) => l.vb.obj == r.vb.obj
case (l, r) => {
throw new IllegalArgumentException("Bad types for refEq: %s and %s".format(
l.showTy, r.showTy))
......@@ -269,11 +271,11 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
val nt = microVM.globalBundle.typeNs(newType)
val nh = (opnd, nt) match {
case (MuRefValue(ty, vb), ty2 @ TypeRef(_)) => MuRefValue(ty2, vb)
case (MuIRefValue(ty, vb), ty2 @ TypeIRef(_)) => MuIRefValue(ty2, vb)
case (MuRefValue(ty, vb), ty2 @ TypeRef(_)) => MuRefValue(ty2, vb)
case (MuIRefValue(ty, vb), ty2 @ TypeIRef(_)) => MuIRefValue(ty2, vb)
case (MuOpaqueRefValue(ty, vb), ty2 @ TypeFuncRef(_)) => {
require(ty.isInstanceOf[TypeFuncRef] && vb.isInstanceOf[BoxOpaque[_]],
"Attempt to cast %s to funcref. funcref value required".format(opnd.showTy))
"Attempt to cast %s to funcref. funcref value required".format(opnd.showTy))
MuFuncRefValue(ty2, vb.asInstanceOf[BoxFunc])
}
case _ => {
......@@ -679,7 +681,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
}
unpin(objRef)
}
def getAddr(loc: MuValue): MuUPtrValue = {
val (objTy, (objRef, offset)) = loc match {
case MuRefValue(t, vb) => (t, (vb.objRef, 0L))
......@@ -690,8 +692,8 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
}
// do nothing
assert(microVM.memoryManager.globalMemory.isInSpace(objRef) || pinSet.contains(objRef),
"Attempt to get address of objref %d 0x%x, offset %d, 0x%x, which is neither a global cell nor pinned by the current thread.".format(
objRef, objRef, offset, offset))
"Attempt to get address of objref %d 0x%x, offset %d, 0x%x, which is neither a global cell nor pinned by the current thread.".format(
objRef, objRef, offset, offset))
val ptrTy = InternalTypePool.ptrOf(objTy)
val box = new BoxPointer(objRef + offset)
addHandle(MuUPtrValue(ptrTy, box))
......@@ -717,12 +719,36 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
def newIRBuilder(): IRBuilder = {
microVM.newIRBuilder()
}
def makeBootImage(whitelist: Seq[MuID],
primordialFunc: Option[MuFuncRefValue], primordialStack: Option[MuStackRefValue], primordialThreadLocal: Option[MuRefValue],
symFields: Seq[MuIRefValue], symStrings: Seq[String], relocFields: Seq[MuIRefValue], relocStrings: Seq[String],
outputFile: String): Unit = {
???
def makeBootImage(whiteList: Seq[MuID],
primordialFunc: Option[MuFuncRefValue], primordialStack: Option[MuStackRefValue], primordialThreadLocal: Option[MuRefValue],
symFields: Seq[MuIRefValue], symStrings: Seq[String], relocFields: Seq[MuIRefValue], relocStrings: Seq[String],
outputFile: String): Unit = {
val whiteListObjs = whiteList.map(microVM.globalBundle.topLevelNs.apply)
val maybePF = primordialFunc.flatMap(_.vb.obj)
val maybePS = primordialStack.flatMap(_.vb.obj)
val maybeTL = primordialThreadLocal.flatMap { h =>
h.vb.objRef match {
case 0 => None
case a => Some(a)
}
}
val primordial = PrimordialInfo(maybePF, maybePS, maybeTL)
val symFlds = symFields.map { h => (h.vb.objRef, h.vb.offset) }
val relocFlds = relocFields.map { h =>
assert(h.ty.ty.isInstanceOf[AbstractPointerType], "Reloc field %d 0x%x is not a pointer field. field type: %s".format(
h.vb.addr, h.vb.addr, h.ty.ty))
(h.vb.objRef, h.vb.offset)
}
val syms = for (((obj, off), name) <- symFlds zip symStrings) yield FieldAndSymbol(obj, off, name)
val relocs = for (((obj, off), name) <- relocFlds zip relocStrings) yield FieldAndSymbol(obj, off, name)
microVM.bootImageBuilder.makeBootImage(whiteListObjs, primordial, syms, relocs, outputFile)
}
// Internal methods for the micro VM
......
......@@ -33,16 +33,26 @@ import uvm.utils.IOHelpers
import uvm.utils.WithUtils.tryWithResource
class BootImageBuilder(implicit microVM: MicroVM) {
def makeBootImage(whiteList: Seq[TopLevel], outputFile: String): Unit = {
implicit val tcb = new TransitiveClosureBuilder(whiteList)
def makeBootImage(whiteList: Seq[TopLevel], primordial: PrimordialInfo,
syms: Seq[FieldAndSymbol], relocs: Seq[FieldAndSymbol], outputFile: String): Unit = {
implicit val tcb = new TransitiveClosureBuilder(whiteList, primordial)
tcb.doTransitiveClosure()
val biw = new BootImageWriter(tcb, outputFile)
val biw = new BootImageWriter(tcb, syms, relocs, outputFile)
biw.writeFile()
}
}
case class PrimordialInfo(maybeFunc: Option[Function], maybeStack: Option[InterpreterStack], maybeThreadLocal: Option[Word])
object PrimordialInfo {
val NO_PRIMORDIAL = PrimordialInfo(None, None, None)
}
case class FieldAndSymbol(objRef: Word, offset: Word, symbol: String) {
def toAddrSymPair: (Word, String) = ((objRef + offset), symbol)
}
object BootImageWriter {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
......@@ -57,12 +67,15 @@ object BootImageWriter {
val AS_IREF = "I"
val AS_TAGREF = "T"
val AS_FUNCREF = "F"
val AS_UPTR = "P"
val TO_GLOBAL = "G"
val TO_HEAP = "H"
val TO_FUNC = "F"
val TO_SYM = "S"
val NO_OFFSET = 0L
val NO_SYM = ""
/**
* Allocation record. For global and heap.
......@@ -88,7 +101,7 @@ object BootImageWriter {
* @param targetOffset If the source is an iref<T>, it is the offset from the beginning of the target allocation unit;
* otherwise 0.
*/
case class FieldRelocRecord(num: Long, fieldOffset: Long, fieldKind: String, targetKind: String, targetNum: Long, targetOffset: Long)
case class FieldRelocRecord(num: Long, fieldOffset: Long, fieldKind: String, targetKind: String, targetNum: Long, targetOffset: Long, targetString: String)
class FileGroup(baseName: String, dir: Path) {
val dataFile = dir.resolve(baseName + FILEEXT_DATA)
......@@ -102,7 +115,8 @@ object BootImageWriter {
}
}
class BootImageWriter(tcb: TransitiveClosureBuilder, outputFile: String)(implicit microVM: MicroVM) {
class BootImageWriter(tcb: TransitiveClosureBuilder, syms: Seq[FieldAndSymbol],
relocs: Seq[FieldAndSymbol], outputFile: String)(implicit microVM: MicroVM) {
import BootImageWriter._
val bundleSerializer = new BundleSerializer(microVM.globalBundle, tcb.tls.set)
......@@ -113,6 +127,10 @@ class BootImageWriter(tcb: TransitiveClosureBuilder, outputFile: String)(implici
val globalGroup = new FileGroup("global", tempDir)
val heapGroup = new FileGroup("heap", tempDir)
val symsMap = syms.map(_.toAddrSymPair).toMap
val symsRevMap = syms.map(_.toAddrSymPair.swap).toMap
val relocsMap = relocs.map(_.toAddrSymPair).toMap
val idNameMapPath = tempDir.resolve(IDNAMEMAP_FILE)
val uirBundlePath = tempDir.resolve(UIRBUNDLE_FILE)
......@@ -149,6 +167,8 @@ class BootImageWriter(tcb: TransitiveClosureBuilder, outputFile: String)(implici
scanForRelocs(globalGroup)
scanForRelocs(heapGroup)
addPointerRelocs()
writeRelocRecs(globalGroup)
writeRelocRecs(heapGroup)
......@@ -203,14 +223,14 @@ class BootImageWriter(tcb: TransitiveClosureBuilder, outputFile: String)(implici
def visitRefField(objRef: Word, iRef: Word, toObj: Word, isWeak: Boolean): Unit = if (toObj != 0L) {
val fieldOffset = iRef - objRef
val targetNum = addrToHeapObjNum(toObj)
val reloc = FieldRelocRecord(num, fieldOffset, AS_REF, TO_HEAP, targetNum, NO_OFFSET)
val reloc = FieldRelocRecord(num, fieldOffset, AS_REF, TO_HEAP, targetNum, NO_OFFSET, NO_SYM)
group.relocRecs += reloc
}
def visitIRefField(objRef: Word, iRef: Word, toObj: Word, toOffset: Word): Unit = if (toObj != 0L) {
val fieldOffset = iRef - objRef
val targetNum = addrToHeapObjNum(toObj)
val reloc = FieldRelocRecord(num, fieldOffset, AS_IREF, TO_HEAP, targetNum, toOffset)
val reloc = FieldRelocRecord(num, fieldOffset, AS_IREF, TO_HEAP, targetNum, toOffset, NO_SYM)
group.relocRecs += reloc
} else {
val fieldOffset = iRef - objRef
......@@ -218,21 +238,21 @@ class BootImageWriter(tcb: TransitiveClosureBuilder, outputFile: String)(implici
val targetNum = gcr.g.id.toLong
val targetAddr = gcr.begin
val targetOffset = toOffset - targetAddr
val reloc = FieldRelocRecord(num, fieldOffset, AS_IREF, TO_GLOBAL, targetNum, targetOffset)
val reloc = FieldRelocRecord(num, fieldOffset, AS_IREF, TO_GLOBAL, targetNum, targetOffset, NO_SYM)
group.relocRecs += reloc
}
def visitTagRefField(objRef: Word, iRef: Word, toObj: Word): Unit = if (toObj != 0L) {
val fieldOffset = iRef - objRef
val targetNum = addrToHeapObjNum(toObj)
val reloc = FieldRelocRecord(num, fieldOffset, AS_TAGREF, TO_HEAP, targetNum, NO_OFFSET)
val reloc = FieldRelocRecord(num, fieldOffset, AS_TAGREF, TO_HEAP, targetNum, NO_OFFSET, NO_SYM)
group.relocRecs += reloc
}
def visitFuncRefField(objRef: Word, iRef: Word, toFunc: Option[Function]): Unit = toFunc.foreach { func =>
val fieldOffset = iRef - objRef
val targetNum = func.id.toLong
val reloc = FieldRelocRecord(num, fieldOffset, AS_FUNCREF, TO_FUNC, targetNum, NO_OFFSET)
val reloc = FieldRelocRecord(num, fieldOffset, AS_FUNCREF, TO_FUNC, targetNum, NO_OFFSET, NO_SYM)
group.relocRecs += reloc
}
......@@ -244,6 +264,10 @@ class BootImageWriter(tcb: TransitiveClosureBuilder, outputFile: String)(implici
})
}
}
private def addPointerRelocs(): Unit = {
???
}
private def writeRelocRecs(group: FileGroup): Unit = {
tryWithResource(Files.newBufferedWriter(group.relocFile, StandardCharsets.UTF_8)) { writer =>
......
......@@ -85,7 +85,8 @@ object TransitiveClosureBuilder {
case class GlobalCellRec(begin: Word, end: Word, g: GlobalCell)
}
class TransitiveClosureBuilder(initialSet: Seq[TopLevel])(implicit microVM: MicroVM) extends MemoryFieldHandler {
class TransitiveClosureBuilder(initialSet: Seq[TopLevel], val primordial: PrimordialInfo)(
implicit microVM: MicroVM) extends MemoryFieldHandler {
import TransitiveClosureBuilder._
private val globalMemory: Space = microVM.memoryManager.globalMemory
......@@ -103,8 +104,27 @@ class TransitiveClosureBuilder(initialSet: Seq[TopLevel])(implicit microVM: Micr
* Global cells + heap objects.
*/
val allocs = TransitiveClosure[Word]()
// Put the primordial function/stack and the thread-local into the set
{
val PrimordialInfo(pf, ps, ptl) = primordial
if (ps.isDefined) {
throw new BootImageBuilderException("Building boot image using a stack is not implemented. The current way is to specify the stack-bottom function.")
}
pf foreach { func =>
// If the primordial function/stack is specified, add it.
tls += func
ptl foreach { addr =>
// Also add the thread-local if specified.
allocs += addr
}
}
}
def getGlobalCellAddr(g: GlobalCell): Word = {
private def getGlobalCellAddr(g: GlobalCell): Word = {
microVM.constantPool.getGlobalVarBox(g).asInstanceOf[BoxIRef].addr
}
......
......@@ -22,10 +22,10 @@ class BootImageWriterTest extends UvmBundleTesterBase with ExtraMatchers {
it should "write everything to files" in {
val everything = microVM.globalBundle.allTopLevels()
val tcb = new TransitiveClosureBuilder(everything)(microVM)
val tcb = new TransitiveClosureBuilder(everything, PrimordialInfo.NO_PRIMORDIAL)(microVM)
tcb.doTransitiveClosure()
val biw = new BootImageWriter(tcb, "target/boot-image-writer-test.muref")(microVM)
val biw = new BootImageWriter(tcb, Seq(), Seq(), "target/boot-image-writer-test.muref")(microVM)
biw.writeFile()
}
......
......@@ -25,77 +25,80 @@ class TransitiveClosureTest extends UvmBundleTesterBase with ExtraMatchers {
microVM.globalBundle.allNs(name).asInstanceOf[TopLevel]
}
def makeTCB(whiteList: TopLevel*): TransitiveClosureBuilder = {
new TransitiveClosureBuilder(whiteList, PrimordialInfo.NO_PRIMORDIAL)(microVM)
}
it should "compute transitive closure over types" in {
val tsb = new TransitiveClosureBuilder(Seq("@refi64"))(microVM)
tsb.doTransitiveClosure()
val tcb = makeTCB("@refi64")
tcb.doTransitiveClosure()
tsb.tls.set should contain(our ty "@i64")
tsb.tls.set shouldNot contain(our ty "@i32")
tcb.tls.set should contain(our ty "@i64")
tcb.tls.set shouldNot contain(our ty "@i32")
}
it should "compute transitive closure over function signatures" in {
val tsb = new TransitiveClosureBuilder(Seq("@s1"))(microVM)
tsb.doTransitiveClosure()
val tcb = makeTCB("@s1")
tcb.doTransitiveClosure()
tsb.tls.set should contain(our ty "@i32")
tsb.tls.set should contain(our ty "@i16")
tsb.tls.set shouldNot contain(our ty "@i64")
tcb.tls.set should contain(our ty "@i32")
tcb.tls.set should contain(our ty "@i16")
tcb.tls.set shouldNot contain(our ty "@i64")
}
it should "compute transitive closure over constants" in {
val tsb = new TransitiveClosureBuilder(Seq("@F", "@S"))(microVM)
tsb.doTransitiveClosure()
tsb.tls.set should contain(our const "@S0")
tsb.tls.set should contain(our const "@S1")
tsb.tls.set should contain(our const "@S2")
tsb.tls.set should contain(our ty "@i64")
tsb.tls.set should contain(our ty "@i32")
tsb.tls.set should contain(our ty "@s")
tsb.tls.set should contain(our ty "@f")
tsb.tls.set shouldNot contain(our ty "@d")
val tcb = makeTCB("@F", "@S")
tcb.doTransitiveClosure()
tcb.tls.set should contain(our const "@S0")
tcb.tls.set should contain(our const "@S1")
tcb.tls.set should contain(our const "@S2")
tcb.tls.set should contain(our ty "@i64")
tcb.tls.set should contain(our ty "@i32")
tcb.tls.set should contain(our ty "@s")
tcb.tls.set should contain(our ty "@f")
tcb.tls.set shouldNot contain(our ty "@d")
}
it should "compute transitive closure over global cells" in {
val tsb = new TransitiveClosureBuilder(Seq("@gfoo"))(microVM)
tsb.doTransitiveClosure()
val tcb = makeTCB("@gfoo")
tcb.doTransitiveClosure()
tsb.tls.set should contain(our ty "@foo")
tcb.tls.set should contain(our ty "@foo")
}
it should "compute transitive closure over function decls" in {
val tsb = new TransitiveClosureBuilder(Seq("@fd"))(microVM)
tsb.doTransitiveClosure()
val tcb = makeTCB("@fd")
tcb.doTransitiveClosure()
tsb.tls.set should contain(our sig "@s1")
tsb.tls.set should contain(our ty "@i32")
tsb.tls.set should contain(our ty "@i16")
tsb.tls.set shouldNot contain(our ty "@i64")
tcb.tls.set should contain(our sig "@s1")
tcb.tls.set should contain(our ty "@i32")
tcb.tls.set should contain(our ty "@i16")
tcb.tls.set shouldNot contain(our ty "@i64")
}
it should "compute transitive closure over function defs" in {
val tsb = new TransitiveClosureBuilder(Seq("@gd"))(microVM)
tsb.doTransitiveClosure()
tsb.tls.set should contain(our sig "@s2")
tsb.tls.set should contain(our ty "@i64")
tsb.tls.set should contain(our ty "@i16")
tsb.tls.set shouldNot contain(our ty "@i32")
tsb.tls.set should contain(our const "@S0")
tsb.tls.set should contain(our const "@S1")
tsb.tls.set shouldNot contain(our const "@S2")
val tcb = makeTCB("@gd")
tcb.doTransitiveClosure()
tcb.tls.set should contain(our sig "@s2")
tcb.tls.set should contain(our ty "@i64")
tcb.tls.set should contain(our ty "@i16")
tcb.tls.set shouldNot contain(our ty "@i32")
tcb.tls.set should contain(our const "@S0")
tcb.tls.set should contain(our const "@S1")
tcb.tls.set shouldNot contain(our const "@S2")
}
it should "compute transitive closure over exposed functions" in {
val tsb = new TransitiveClosureBuilder(Seq("@ef"))(microVM)
tsb.doTransitiveClosure()
tsb.tls.set should contain(our func "@fd")
tsb.tls.set should contain(our sig "@s1")
tsb.tls.set should contain(our ty "@i32")
tsb.tls.set should contain(our ty "@i16")
tsb.tls.set should contain(our const "@S1")
val tcb = makeTCB("@ef")
tcb.doTransitiveClosure()
tcb.tls.set should contain(our func "@fd")
tcb.tls.set should contain(our sig "@s1")
tcb.tls.set should contain(our ty "@i32")
tcb.tls.set should contain(our ty "@i16")
tcb.tls.set should contain(our const "@S1")
}
def getType(obj: Word): Type = {
......@@ -105,14 +108,14 @@ class TransitiveClosureTest extends UvmBundleTesterBase with ExtraMatchers {
}
it should "scan the heap for objects" in {
val tsb = new TransitiveClosureBuilder(Seq("@llhead"))(microVM)
tsb.doTransitiveClosure()
val tcb = makeTCB("@llhead")
tcb.doTransitiveClosure()
tsb.tls.set should contain(our ty "@refll")
tsb.tls.set should contain(our ty "@ll")
tsb.tls.set should contain(our ty "@i64")
tcb.tls.set should contain(our ty "@refll")
tcb.tls.set should contain(our ty "@ll")
tcb.tls.set should contain(our ty "@i64")
val objs = tsb.allocs.set.toSeq
val objs = tcb.allocs.set.toSeq
objs.length shouldBe 4
for (obj <- objs) {
......@@ -122,16 +125,16 @@ class TransitiveClosureTest extends UvmBundleTesterBase with ExtraMatchers {
}
it should "scan the types reachable from objects" in {
val tsb = new TransitiveClosureBuilder(Seq("@llhead_void"))(microVM)
tsb.doTransitiveClosure()
val tcb = makeTCB("@llhead_void")
tcb.doTransitiveClosure()
tsb.tls.set should contain(our ty "@refll")
tsb.tls.set should contain(our ty "@ll")
tsb.tls.set should contain(our ty "@i64")
tsb.tls.set should contain(our ty "@refvoid")
tsb.tls.set should contain(our ty "@void")
tcb.tls.set should contain(our ty "@refll")
tcb.tls.set should contain(our ty "@ll")
tcb.tls.set should contain(our ty "@i64")
tcb.tls.set should contain(our ty "@refvoid")
tcb.tls.set should contain(our ty "@void")
val objs = tsb.allocs.set.toSeq
val objs = tcb.allocs.set.toSeq
objs.length shouldBe 4
for (obj <- objs) {
......@@ -148,14 +151,14 @@ class TransitiveClosureTest extends UvmBundleTesterBase with ExtraMatchers {
val content1= NativeSupport.theMemory.getLong(addr+8)
ctx.closeContext()
val tsb = new TransitiveClosureBuilder(Seq("@gr2"))(microVM)
tsb.doTransitiveClosure()
val tcb = makeTCB("@gr2")
tcb.doTransitiveClosure()
tsb.tls.set should contain(our ty "@irefi64")
tsb.tls.set should contain(our ty "@i64")
tsb.tls.set should contain(our globalCell "@gr1")
tcb.tls.set should contain(our ty "@irefi64")
tcb.tls.set should contain(our ty "@i64")
tcb.tls.set should contain(our globalCell "@gr1")
val objs = tsb.allocs.set.toSeq
val objs = tcb.allocs.set.toSeq
objs.length shouldBe 2
for (obj <- objs) {
......
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