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.

To protect your data, the CISO officer has suggested users to enable 2FA as soon as possible.
Currently 2.7% of users enabled 2FA.

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

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