Commit 58cf0076 authored by Kunshan Wang's avatar Kunshan Wang

Fixes transitive closure. Runs bootimg echo.

parent 10171176
......@@ -22,54 +22,17 @@ object EntityUtils {
def isMetaEntity(id: Int): Boolean = {
id < 65536
}
def isMetaEntity(obj: Identified): Boolean = {
isMetaEntity(obj.id)
}
}
class BundleSerializer(val bundle: GlobalBundle, val whiteList: Set[TopLevel]) {
abstract class AbstractBundleSerializer(bundle: Bundle) {
import EntityUtils._
import BundleSerializer._
import AbstractBundleSerializer._
def filter(obj: TopLevel): Boolean = {
!isMetaEntity(obj) && whiteList.contains(obj)
}
def writeIDNameMap(output: Writer): Unit = {
val sb = new StringBuilder()
writeIDNameMap(sb)
output.append(sb)
output.flush()
}
def writeIDNameMap(output: StringBuilder): Unit = {
for (obj <- whiteList if !isMetaEntity(obj)) {
writeIDNamePair(obj, output)
obj match {
case func: Function => {
bundle.funcToVers(func).headOption match {
case Some(fv) => {
writeIDNamePair(fv, output)
fv.bbs foreach { bb =>
writeIDNamePair(bb, output)
bb.localVarNs.all foreach { lv => writeIDNamePair(lv, output) }
bb.insts foreach { inst => writeIDNamePair(inst, output) }
}
}
case None => // ignore
}
}
case _ => // ignore
}
}
}
private def writeIDNamePair(obj: Identified, output: StringBuilder): Unit = {
val id = obj.id
val name = getName(obj)
output.append("%d,%s\n".format(id, name))
}
def writeUIR(sb: StringBuilder): Unit
def writeUIR(output: Writer): Unit = {
val sb = new StringBuilder()
......@@ -78,16 +41,6 @@ class BundleSerializer(val bundle: GlobalBundle, val whiteList: Set[TopLevel]) {
output.flush()
}
def writeUIR(output: StringBuilder): Unit = {
for (obj <- bundle.typeNs.all if filter(obj)) { writeType(obj, output) }
for (obj <- bundle.funcSigNs.all if filter(obj)) { writeSig(obj, output) }
for (obj <- bundle.constantNs.all if filter(obj)) { writeConst(obj, output) }
for (obj <- bundle.globalCellNs.all if filter(obj)) { writeGlobal(obj, output) }
for (obj <- bundle.expFuncNs.all if filter(obj)) { writeExpFunc(obj, output) }
for (obj <- bundle.funcNs.all if filter(obj)) { writeFunc(obj, output) }
}
def writeType(ty: Type, output: StringBuilder): Unit = {
val ctor = ty match {
case TypeInt(l) => s"int<${l}>"
......@@ -141,16 +94,16 @@ class BundleSerializer(val bundle: GlobalBundle, val whiteList: Set[TopLevel]) {
}
def writeFunc(func: Function, output: StringBuilder): Unit = {
bundle.funcToVers(func).headOption match {
case None =>
output.append(s".funcdecl ${func.n} <${func.sig.n}>\n")
case Some(ver) =>
output.append(s".funcdef ${func.n} VERSION ${ver.n} <${func.sig.n}> {\n")
for (bb <- ver.bbs) {
writeBB(bb, output)
}
output.append("}\n")
output.append(s".funcdecl ${func.n} <${func.sig.n}>\n")
}
def writeFuncVer(ver: FuncVer, output: StringBuilder): Unit = {
val func = ver.func
output.append(s".funcdef ${func.n} VERSION ${ver.n} <${func.sig.n}> {\n")
for (bb <- ver.bbs) {
writeBB(bb, output)
}
output.append("}\n")
}
def norParamToString(p: NorParam): String = {
......@@ -225,7 +178,7 @@ class BundleSerializer(val bundle: GlobalBundle, val whiteList: Set[TopLevel]) {
}
}
object BundleSerializer {
object AbstractBundleSerializer {
import EntityUtils._
def destToString(dest: DestClause): String = {
......@@ -295,4 +248,89 @@ object BundleSerializer {
def p: String = if (value) "PTR" else ""
def w: String = if (value) "WEAK" else ""
}
}
/**
* This class serialises TrantientBundle, suitable for debugging (the dumpBundle VMConf option uses this).
*/
class DebugBundleSerializer(val bundle: TrantientBundle) extends AbstractBundleSerializer(bundle) {
def writeUIR(output: StringBuilder): Unit = {
for (obj <- bundle.typeNs.all) { writeType(obj, output) }
for (obj <- bundle.funcSigNs.all) { writeSig(obj, output) }
for (obj <- bundle.constantNs.all) { writeConst(obj, output) }
for (obj <- bundle.globalCellNs.all) { writeGlobal(obj, output) }
for (obj <- bundle.expFuncNs.all) { writeExpFunc(obj, output) }
val funcSet = bundle.funcNs.all.toSet
val verFuncSet = bundle.funcVerNs.all.map(_.func).toSet
val declSet = funcSet diff verFuncSet
for (obj <- declSet) { writeFunc(obj, output) }
for (obj <- bundle.funcVerNs.all) { writeFuncVer(obj, output) }
}
}
/**
* This class serialises GlobalBundle using a whiteList of top-levels, suitable for building boot image.
*/
class BundleSerializer(val bundle: GlobalBundle, val whiteList: Set[TopLevel]) extends AbstractBundleSerializer(bundle) {
import EntityUtils._
import AbstractBundleSerializer._
def filter(obj: TopLevel): Boolean = {
!isMetaEntity(obj) && whiteList.contains(obj)
}
def writeIDNameMap(output: Writer): Unit = {
val sb = new StringBuilder()
writeIDNameMap(sb)
output.append(sb)
output.flush()
}
def writeIDNameMap(output: StringBuilder): Unit = {
for (obj <- whiteList if !isMetaEntity(obj)) {
writeIDNamePair(obj, output)
obj match {
case func: Function => {
bundle.funcToVers(func).headOption match {
case Some(fv) => {
writeIDNamePair(fv, output)
fv.bbs foreach { bb =>
writeIDNamePair(bb, output)
bb.localVarNs.all foreach { lv => writeIDNamePair(lv, output) }
bb.insts foreach { inst => writeIDNamePair(inst, output) }
}
}
case None => // ignore
}
}
case _ => // ignore
}
}
}
private def writeIDNamePair(obj: Identified, output: StringBuilder): Unit = {
val id = obj.id
val name = getName(obj)
output.append("%d,%s\n".format(id, name))
}
def writeUIR(output: StringBuilder): Unit = {
for (obj <- bundle.typeNs.all if filter(obj)) { writeType(obj, output) }
for (obj <- bundle.funcSigNs.all if filter(obj)) { writeSig(obj, output) }
for (obj <- bundle.constantNs.all if filter(obj)) { writeConst(obj, output) }
for (obj <- bundle.globalCellNs.all if filter(obj)) { writeGlobal(obj, output) }
for (obj <- bundle.expFuncNs.all if filter(obj)) { writeExpFunc(obj, output) }
for (obj <- bundle.funcNs.all if filter(obj)) { writeFuncWithMaybeVersion(obj, output) }
}
def writeFuncWithMaybeVersion(func: Function, output: StringBuilder): Unit = {
bundle.funcToVers(func).headOption match {
case None => writeFunc(func, output)
case Some(ver) => writeFuncVer(ver, output)
}
}
}
\ No newline at end of file
......@@ -22,6 +22,7 @@ import uvm.refimpl.nat.NativeLibraryHolder
import uvm.staticanalysis.StaticAnalyzer
import uvm.utils.IDFactory
import uvm.utils.WithUtils.tryWithResource
import uvm.ir.textoutput.DebugBundleSerializer
object MicroVM {
val DEFAULT_SOS_SIZE: Word = 2L * 1024L * 1024L; // 2MiB
......@@ -92,6 +93,11 @@ class MicroVM(val vmConf: VMConf) {
* Add things from a bundle to the Micro VM.
*/
def addBundle(bundle: TrantientBundle) {
if (vmConf.dumpBundle) {
val dbs = new DebugBundleSerializer(bundle)
dbs.writeUIR(new OutputStreamWriter(System.err))
}
if (vmConf.staticCheck) {
staticAnalyzer.checkBundle(bundle, Some(globalBundle))
}
......
......@@ -87,6 +87,12 @@ object VMConfParser {
parser = sizeWithSuffix,
default = VMConf.DEFAULT_CONF.stackSize)
val dumpBundle = opt[Boolean](
name = "dumpBundle",
desc = """Dump the bundle when a bundle is loaded.""",
parser = parseBoolean,
default = VMConf.DEFAULT_CONF.staticCheck)
val staticCheck = opt[Boolean](
name = "staticCheck",
desc = """Run static checker after each bundle is loaded.""",
......@@ -153,6 +159,7 @@ object VMConf {
losSize = VMConfParser.losSize(kvMap),
globalSize = VMConfParser.globalSize(kvMap),
stackSize = VMConfParser.stackSize(kvMap),
dumpBundle = VMConfParser.dumpBundle(kvMap),
staticCheck = VMConfParser.staticCheck(kvMap),
sourceInfo = VMConfParser.sourceInfo(kvMap),
extraLibs = VMConfParser.extraLibs(kvMap),
......@@ -177,6 +184,7 @@ class VMConf(
val losSize: Word = MicroVM.DEFAULT_LOS_SIZE,
val globalSize: Word = MicroVM.DEFAULT_GLOBAL_SIZE,
val stackSize: Word = MicroVM.DEFAULT_STACK_SIZE,
val dumpBundle: Boolean = false,
val staticCheck: Boolean = true,
val sourceInfo: Boolean = false,
val extraLibs: Seq[String] = Seq(),
......
......@@ -47,18 +47,40 @@ object TransitiveClosureBuilder {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
implicit class RichTransitiveClosure[T <: Identified](val tc: TransitiveClosure[T]) extends AnyVal {
def ?=(elem: SSAVariable) = {
def ?=(elem: SSAVariable): TransitiveClosure[T] = {
if (elem.isInstanceOf[GlobalVariable]) {
tc += elem.asInstanceOf[T]
}
tc
}
def ??=(elems: Seq[SSAVariable]) = {
def ??=(elems: Seq[SSAVariable]): TransitiveClosure[T] = {
for (elem <- elems) {
this ?= elem
}
tc
}
def ??=(dest: DestClause): TransitiveClosure[T] = {
this ??= dest.args
tc
}
def ??=(maybeExcClause: Option[ExcClause]): TransitiveClosure[T] = {
maybeExcClause foreach { excClause =>
this ??= excClause.nor.args ??= excClause.exc.args
}
tc
}
def ???=(maybeElem: Option[SSAVariable]): TransitiveClosure[T] = { // More ? to work around type erasure
for (elem <- maybeElem) {
this ?= elem
}
tc
}
def ????=(maybeDest: Option[DestClause]): TransitiveClosure[T] = {
for (dest <- maybeDest) {
this ??= dest.args
}
tc
}
}
case class GlobalCellRec(begin: Word, end: Word, g: GlobalCell)
......@@ -203,14 +225,14 @@ class TransitiveClosureBuilder(initialSet: Seq[TopLevel])(implicit microVM: Micr
}
private def visitInstruction(inst: Instruction): Unit = inst match {
case InstBinOp(op, opndTy, op1, op2, excClause) => tls += opndTy ?= op1 ?= op2
case InstBinOp(op, opndTy, op1, op2, excClause) => tls += opndTy ?= op1 ?= op2 ??= excClause
case InstCmp(op, opndTy, op1, op2) => tls += opndTy ?= op1 ?= op2
case InstConv(op, fromTy, toTy, opnd) => tls += fromTy += toTy ?= opnd
case InstSelect(condTy, opndTy, cond, ifTrue, ifFalse) => tls += condTy += opndTy ?= cond ?= ifTrue ?= ifFalse
case InstBranch(dest) =>
case InstBranch2(cond, ifTrue, ifFalse) => tls ?= cond
case i @ InstSwitch(opndTy, opnd, defDest, cases) => tls += opndTy ?= opnd ??= cases.map(_._1)
case InstCall(sig, callee, argList, excClause, keepalives) => tls += sig ?= callee ??= argList
case InstBranch(dest) => tls ??= dest
case InstBranch2(cond, ifTrue, ifFalse) => tls ?= cond ??= ifTrue ??= ifFalse
case i @ InstSwitch(opndTy, opnd, defDest, cases) => tls += opndTy ?= opnd ??= defDest ??= cases.map(_._1)
case InstCall(sig, callee, argList, excClause, keepalives) => tls += sig ?= callee ??= argList ??= excClause
case InstTailCall(sig, callee, argList) => tls += sig ?= callee ??= argList
case InstRet(funcVer, retVals) => tls ??= retVals
case InstThrow(excVal) => tls ?= excVal
......@@ -219,33 +241,32 @@ class TransitiveClosureBuilder(initialSet: Seq[TopLevel])(implicit microVM: Micr
case InstExtractElement(seqTy, indTy, opnd, index) => tls += seqTy += indTy ?= opnd ?= index
case InstInsertElement(seqTy, indTy, opnd, index, newVal) => tls += seqTy += indTy ?= opnd ?= index ?= newVal
case InstShuffleVector(vecTy, maskTy, vec1, vec2, mask) => tls += vecTy += maskTy ?= vec1 ?= vec2 ?= mask
case InstNew(allocTy, excClause) => tls += allocTy
case InstNewHybrid(allocTy, lenTy, length, excClause) => tls += allocTy += lenTy ?= length
case InstAlloca(allocTy, excClause) => tls += allocTy
case InstAllocaHybrid(allocTy, lenTy, length, excClause) => tls += allocTy += lenTy ?= length
case InstNew(allocTy, excClause) => tls += allocTy ??= excClause
case InstNewHybrid(allocTy, lenTy, length, excClause) => tls += allocTy += lenTy ?= length ??= excClause
case InstAlloca(allocTy, excClause) => tls += allocTy ??= excClause
case InstAllocaHybrid(allocTy, lenTy, length, excClause) => tls += allocTy += lenTy ?= length ??= excClause
case InstGetIRef(referentTy, opnd) => tls += referentTy ?= opnd
case InstGetFieldIRef(ptr, referentTy, index, opnd) => tls += referentTy ?= opnd
case InstGetElemIRef(ptr, referentTy, indTy, opnd, index) => tls += referentTy += indTy ?= opnd ?= index
case InstShiftIRef(ptr, referentTy, offTy, opnd, offset) => tls += referentTy += offTy ?= opnd ?= offset
case InstGetVarPartIRef(ptr, referentTy, opnd) => tls += referentTy ?= opnd
case InstLoad(ptr, ord, referentTy, loc, excClause) => tls += referentTy ?= loc
case InstStore(ptr, ord, referentTy, loc, newVal, excClause) => tls += referentTy ?= loc ?= newVal
case InstLoad(ptr, ord, referentTy, loc, excClause) => tls += referentTy ?= loc ??= excClause
case InstStore(ptr, ord, referentTy, loc, newVal, excClause) => tls += referentTy ?= loc ?= newVal ??= excClause
case InstCmpXchg(ptr, weak, ordSucc, ordFail, referentTy, loc, expected, desired, excClause) // This line is long ...
=> tls += referentTy ?= loc ?= expected ?= desired
case InstAtomicRMW(ptr, ord, op, referentTy, loc, opnd, excClause) => tls += referentTy ?= loc ?= opnd
=> tls += referentTy ?= loc ?= expected ?= desired ??= excClause
case InstAtomicRMW(ptr, ord, op, referentTy, loc, opnd, excClause) => tls += referentTy ?= loc ?= opnd ??= excClause
case InstFence(ord) =>
case InstTrap(retTys, excClause, keepalives) => tls ++= retTys
case InstWatchPoint(wpID, retTys, dis, ena, exc, keepalives) => tls ++= retTys
case InstWPBranch(wpID, dis, ena) =>
case InstTrap(retTys, excClause, keepalives) => tls ++= retTys ??= excClause
case InstWatchPoint(wpID, retTys, dis, ena, exc, keepalives) => tls ++= retTys ??= dis ??= ena ????= exc
case InstWPBranch(wpID, dis, ena) => tls ??= dis ??= ena
case InstCCall(callConv, funcTy, sig, callee, argList, excClause, keepalives) // This line is long, too...
=> tls += funcTy += sig ?= callee ??= argList
=> tls += funcTy += sig ?= callee ??= argList ??= excClause
case InstNewThread(stack, threadLocal, newStackAction, excClause) => {
tls ?= stack
threadLocal.foreach(tls.?=)
tls ?= stack ???= threadLocal ??= excClause
visitNewStackAction(newStackAction)
}
case InstSwapStack(swappee, curStackAction, newStackAction, excClause, keepalives) => {
tls ?= swappee
tls ?= swappee ??= excClause
curStackAction match {
case RetWith(ts) => tls ++= ts
case KillOld() =>
......@@ -253,7 +274,7 @@ class TransitiveClosureBuilder(initialSet: Seq[TopLevel])(implicit microVM: Micr
visitNewStackAction(newStackAction)
}
case InstCommInst(ci, flagList, typeList, funcSigList, argList, excClause, keepalives) =>
tls ++= typeList ++= funcSigList ??= argList
tls ++= typeList ++= funcSigList ??= argList ??= excClause
case _ => throw new BootImageBuilderException("Unknown instruction: " + inst.getClass.getName)
}
......@@ -307,10 +328,10 @@ class TransitiveClosureBuilder(initialSet: Seq[TopLevel])(implicit microVM: Micr
if (largeObjectSpace.isInSpace(toOffset)) {
throw new BootImageBuilderException(("Error: non-object iref to LOS found. This is probably a reference to " +
"a stack cell (ALLOCA). It should not exist during boot image building. source: [0x%x + 0x%x] -> dest 0x%x").format(
objRef, iRef, toOffset))
objRef, iRef, toOffset))
} else {
throw new BootImageBuilderException(("Error: non-object iref not referring to global. source: [0x%x + 0x%x] -> dest 0x%x").format(
objRef, iRef, toOffset))
objRef, iRef, toOffset))
}
}
} else {
......@@ -319,7 +340,7 @@ class TransitiveClosureBuilder(initialSet: Seq[TopLevel])(implicit microVM: Micr
}
}
}
override def visitTagRefField(objRef: Word, iRef: Word, toObj: Word): Unit = {
if (toObj != 0L) {
allocs += toObj
......@@ -329,18 +350,18 @@ class TransitiveClosureBuilder(initialSet: Seq[TopLevel])(implicit microVM: Micr
override def visitFuncRefField(objRef: Word, iRef: Word, toFunc: Option[Function]): Unit = {
toFunc.foreach(tls+=)
}
override def visitStackRefField(objRef: Word, iRef: Word, toStack: Option[InterpreterStack]): Unit =
override def visitStackRefField(objRef: Word, iRef: Word, toStack: Option[InterpreterStack]): Unit =
toStack.foreach(o => throw noReach("stack", objRef, iRef, o))
override def visitThreadRefField(objRef: Word, iRef: Word, toThread: Option[InterpreterThread]): Unit =
override def visitThreadRefField(objRef: Word, iRef: Word, toThread: Option[InterpreterThread]): Unit =
toThread.foreach(o => throw noReach("thread", objRef, iRef, o))
override def visitFCRefField(objRef: Word, iRef: Word, toFCRef: Option[FrameCursor]): Unit =
override def visitFCRefField(objRef: Word, iRef: Word, toFCRef: Option[FrameCursor]): Unit =
toFCRef.foreach(o => throw noReach("frame cursor", objRef, iRef, o))
override def visitIRNodeRefField(objRef: Word, iRef: Word, toIRNode: Option[IRNode]): Unit =
override def visitIRNodeRefField(objRef: Word, iRef: Word, toIRNode: Option[IRNode]): Unit =
toIRNode.foreach(o => throw noReach("IR node", objRef, iRef, o))
private def noReach(kind: String, objRef: Word, iRef: Word, obj: AnyRef) =
new BootImageBuilderException(
"Error: Non-null %s field is not allowed in boot image. From: obj 0x%x, iref 0x%x. To stack id: %s".format(
objRef, iRef, obj))
"Error: Non-null %s field is not allowed in boot image. From: obj 0x%x, iref 0x%x. To stack id: %s".format(
objRef, iRef, obj))
}
\ No newline at end of file
......@@ -87,14 +87,14 @@ object RunMu {
val argc = appArgs.size + 1
val argvSB = new StringBuilder()
val argvOffs = new Array[Long](argc)
for ((arg, i) <- (bootImg :: appArgs).zipWithIndex) {
argvOffs(i) = argvOffs.length
argvOffs(i) = argvSB.length
argvSB ++= arg += '\0'
}
val cArgv = NativeSupport.jnrMemoryManager.allocate(argvOffs.length * PlatformConstants.WORD_SIZE_BYTES.toInt)
val cArgvBuf = NativeSupport.jnrMemoryManager.allocate(argvSB.length)
val cArgv = NativeSupport.jnrMemoryManager.allocateDirect(argvOffs.length * PlatformConstants.WORD_SIZE_BYTES.toInt)
val cArgvBuf = NativeSupport.jnrMemoryManager.allocateDirect(argvSB.length)
for (i <- 0 until argvOffs.length) {
cArgv.putAddress(i * PlatformConstants.WORD_SIZE_BYTES, cArgvBuf.address() + argvOffs(i))
}
......
.newhybrid $hw <@charh> 14
.newhybrid $hw <@charh> 13
// "Hello world!\n"
.init $hw = {{72 101 108 108 111 32 119 111 114 108 100 33 10 0}}
// "Hello world!"
.init $hw = {{72 101 108 108 111 32 119 111 114 108 100 33 0}}
.init @hw = $hw
......@@ -31,8 +31,9 @@
BRANCH2 %inbound %body(%argc %argv %i) %exit()
%body(<@int> %argc <@charpp> %argv <@int> %i):
%p = SHIFTIREF PTR <@charpp @int> %argv %i
%n = CCALL #DEFAULT <@puts.fp @puts.sig> @puts (%p)
%pp = SHIFTIREF PTR <@charpp @int> %argv %i
%p = LOAD PTR <@charp> %pp
%n = CCALL #DEFAULT <@puts.fp @puts.sig> @puts (%p)
%i2 = ADD <@int> %i @I32_1
BRANCH %head(%argc %argv %i2)
......
......@@ -48,3 +48,4 @@
.typedef @irefi64 = iref<@i64>
.global @gr1 <@i64>
.global @gr2 <@irefi64>
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