Commit f2aac08e authored by Kunshan Wang's avatar Kunshan Wang

Type inferer as class, and stricter static check.

Type inferer and predefined entities are no longer single objects.  They
can be instantiated like other classes.

An SSA variable now has an `inferred type` field which represents its
type.  The type is filled in when loading a bundle, and can be dependedn
on during execution.

Added stricter static checking related to variable types.
parent fb6c7513
......@@ -65,6 +65,8 @@ class MicroVM private (val vmConf: VMConf, val allArgs: Option[Seq[String]]) ext
val stats = new VMStats()
val staticAnalyzer = new StaticAnalyzer()
val globalBundle = new GlobalBundle()
val constantPool = new ConstantPool()
......@@ -76,7 +78,7 @@ class MicroVM private (val vmConf: VMConf, val allArgs: Option[Seq[String]]) ext
// BYTES, BYTES_R, REFS, REFS_R: Types for the @uvm.meta.* common instructions.
import InternalTypes._
import staticAnalyzer.predefinedEntities._
for (ty <- Seq(VOID, BYTE, BYTE_ARRAY, BYTES, BYTES_R, REFS, REFS_R)) {
globalBundle.typeNs.add(ty)
}
......@@ -93,6 +95,9 @@ class MicroVM private (val vmConf: VMConf, val allArgs: Option[Seq[String]]) ext
for (ty <- Seq(C_INT, C_CHAR, C_CHARP, C_CHARPP)) {
globalBundle.typeNs.add(ty)
}
// Perform type inference on all preloaded s
staticAnalyzer.typeInferer.inferBundle(globalBundle)
}
/**
......@@ -126,7 +131,6 @@ class MicroVM private (val vmConf: VMConf, val allArgs: Option[Seq[String]]) ext
val irBuilderRegistry = new IDObjectKeeper[IRBuilder]("IR builder")
val irReader = new UIRTextReader(idFactory, recordSourceInfo = vmConf.sourceInfo)
val hailScriptLoader = new HailScriptLoader(recordSourceInfo = vmConf.sourceInfo)
val staticAnalyzer = new StaticAnalyzer()
val bootImageBuilder = new BootImageBuilder()
......@@ -151,13 +155,16 @@ class MicroVM private (val vmConf: VMConf, val allArgs: Option[Seq[String]]) ext
* Add things from a bundle to the Micro VM.
*/
def addBundle(bundle: TrantientBundle) {
// Make sure all SSA variables have undergone type inference
staticAnalyzer.typeInferer.inferBundle(bundle)
if (vmConf.dumpBundle) {
val dbs = new DebugBundleSerializer(bundle)
dbs.writeUIR(new OutputStreamWriter(System.err))
}
if (vmConf.staticCheck) {
staticAnalyzer.checkBundle(bundle, Some(globalBundle))
staticAnalyzer.bundleChecker.checkBundle(bundle, Some(globalBundle))
}
globalBundle.merge(bundle);
......
......@@ -36,6 +36,9 @@ object MuCtx {
class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
implicit protected val microVM: MicroVM, memorySupport: MemorySupport)
extends ObjectPinner with AutoCloseable {
private val predefinedEntities = microVM.staticAnalyzer.predefinedEntities
private val internalEntityPool = microVM.staticAnalyzer.internalEntityPool
implicit def mutator = _mutator
......@@ -86,20 +89,20 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
/** Convert any int (BigInt) to a handle. */
def handleFromInt(num: BigInt, len: Int): MuIntValue = {
val t = InternalTypePool.intOf(len)
val t = internalEntityPool.intOf(len)
val v = OpHelper.unprepare(num, len)
addHandle(MuIntValue(t, BoxInt(v)))
}
/** Convert float to a handle. */
def handleFromFloat(num: Float): MuFloatValue = {
val t = InternalTypes.FLOAT
val t = predefinedEntities.FLOAT
addHandle(MuFloatValue(t, BoxFloat(num)))
}
/** Convert double to a handle. */
def handleFromDouble(num: Double): MuDoubleValue = {
val t = InternalTypes.DOUBLE
val t = predefinedEntities.DOUBLE
addHandle(MuDoubleValue(t, BoxDouble(num)))
}
......@@ -159,7 +162,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
/** Make a handle for a global cell (its iref). */
def handleFromGlobal(id: MuID): MuIRefValue = {
val g = microVM.globalBundle.globalCellNs(id)
val t = InternalTypePool.irefOf(g.cellTy)
val t = internalEntityPool.irefOf(g.cellTy)
val a = microVM.memoryManager.globalMemory.addrForGlobalCell(g)
val box = BoxIRef(0L, a)
addHandle(MuIRefValue(t, box))
......@@ -168,7 +171,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
/** Make a handle for a function (funcref). */
def handleFromFunc(id: MuID): MuFuncRefValue = {
val f = microVM.globalBundle.funcNs(id)
val t = InternalTypePool.funcOf(f.sig)
val t = internalEntityPool.funcOf(f.sig)
val box = BoxFunc(Some(f))
addHandle(MuFuncRefValue(t, box))
}
......@@ -179,7 +182,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
*/
def handleFromExpose(id: MuID): MuUFPValue = {
val ef = microVM.globalBundle.expFuncNs(id)
val t = InternalTypePool.funcPtrOf(ef.func.sig)
val t = internalEntityPool.funcPtrOf(ef.func.sig)
val box = BoxPointer(microVM.nativeCallHelper.getStaticExpFuncAddr(ef))
addHandle(MuUFPValue(t, box))
}
......@@ -252,7 +255,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
val t = microVM.globalBundle.typeNs(muType)
val objRef = mutator.newScalar(t)
val b = BoxRef(objRef)
val rt = InternalTypePool.refOf(t)
val rt = internalEntityPool.refOf(t)
addHandle(MuRefValue(rt, b))
}
......@@ -262,7 +265,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
val len = handleToUInt(length).longValue
val objRef = mutator.newHybrid(t, len)
val b = BoxRef(objRef)
val rt = InternalTypePool.refOf(t)
val rt = internalEntityPool.refOf(t)
addHandle(MuRefValue(rt, b))
}
......@@ -289,7 +292,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
/** Convert ref to iref */
def getIRef(opnd: MuRefValue): MuIRefValue = {
val nt = InternalTypePool.irefOf(opnd.ty.ty)
val nt = internalEntityPool.irefOf(opnd.ty.ty)
val nb = BoxIRef(opnd.vb.objRef, 0L)
addHandle(MuIRefValue(nt, nb))
}
......@@ -304,7 +307,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
}
val ft = st.fieldTys(field)
val nt = InternalTypePool.irefOf(ft)
val nt = internalEntityPool.irefOf(ft)
val ob = opnd.vb
val nb = BoxIRef(ob.objRef, ob.offset + TypeSizes.fieldOffsetOf(st, field))
addHandle(MuIRefValue(nt, nb))
......@@ -320,7 +323,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
}
val i = handleToUInt(index).longValue
val et = st.elemTy
val nt = InternalTypePool.irefOf(et)
val nt = internalEntityPool.irefOf(et)
val ob = opnd.vb
val nb = BoxIRef(ob.objRef, ob.offset + TypeSizes.elemOffsetOf(st, i))
addHandle(MuIRefValue(nt, nb))
......@@ -346,7 +349,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
"opnd must refer to a hybrid location. Actual referenct type: %s".format(opnd.ty.ty.repr), e)
}
val vt = ht.varTy
val nt = InternalTypePool.irefOf(vt)
val nt = internalEntityPool.irefOf(vt)
val ob = opnd.vb
val nb = BoxIRef(ob.objRef, ob.offset + TypeSizes.varPartOffsetOf(ht))
addHandle(MuIRefValue(nt, nb))
......@@ -358,7 +361,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
case TypeIRef(t) => (false, t)
}
val uty = InternalTypePool.unmarkedOf(ty)
val uty = internalEntityPool.unmarkedOf(ty)
val addr = MemoryOperations.addressOf(ptr, loc.vb)
val nb = ValueBox.makeBoxForType(uty)
......@@ -372,7 +375,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
val (ptr, ty) = loc.ty match {
case TypeIRef(t) => (false, t)
}
val uty = InternalTypePool.unmarkedOf(ty)
val uty = internalEntityPool.unmarkedOf(ty)
val addr = MemoryOperations.addressOf(ptr, loc.vb)
val nvb = newVal.vb
......@@ -385,7 +388,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
val (ptr, ty) = loc.ty match {
case TypeIRef(t) => (false, t)
}
val uty = InternalTypePool.unmarkedOf(ty)
val uty = internalEntityPool.unmarkedOf(ty)
val addr = MemoryOperations.addressOf(ptr, loc.vb)
val eb = expected.vb
val db = desired.vb
......@@ -399,7 +402,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
val (ptr, ty) = loc.ty match {
case TypeIRef(t) => (false, t)
}
val uty = InternalTypePool.unmarkedOf(ty)
val uty = internalEntityPool.unmarkedOf(ty)
val addr = MemoryOperations.addressOf(ptr, loc.vb)
val ob = opnd.vb
val br = ValueBox.makeBoxForType(uty)
......@@ -421,7 +424,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
val sta = microVM.threadStackManager.newStack(funcVal, mutator)
val nb = BoxStack(Some(sta))
addHandle(MuStackRefValue(InternalTypes.STACKREF, nb))
addHandle(MuStackRefValue(predefinedEntities.STACKREF, nb))
}
private def getStackNotNull(stack: MuStackRefValue): InterpreterStack = {
......@@ -448,7 +451,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
val thr = microVM.threadStackManager.newThread(sv, threadLocalAddr, itprHtr)
val nb = BoxThread(Some(thr))
addHandle(MuThreadRefValue(InternalTypes.THREADREF, nb))
addHandle(MuThreadRefValue(predefinedEntities.THREADREF, nb))
}
/** Kill a Mu stack. */
......@@ -472,7 +475,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
val threadLocalAddr = th.threadLocal.objRef
val nb = BoxRef(threadLocalAddr)
addHandle(MuRefValue(InternalTypes.REF_VOID, nb))
addHandle(MuRefValue(predefinedEntities.REF_VOID, nb))
}
private def getCursorNotNull(cursor: MuFCRefValue): FrameCursor = {
......@@ -486,7 +489,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
val s = getStackNotNull(stack)
val c = microVM.threadStackManager.newFrameCursor(s)
val nb = BoxFrameCursor(Some(c))
addHandle(MuFCRefValue(InternalTypes.FRAMECURSORREF, nb))
addHandle(MuFCRefValue(predefinedEntities.FRAMECURSORREF, nb))
}
/** Move cursor to the frame below the current frame. */
......@@ -499,7 +502,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
val c = getCursorNotNull(cursor)
val nc = microVM.threadStackManager.copyCursor(c)
val nb = BoxFrameCursor(Some(nc))
addHandle(MuFCRefValue(InternalTypes.FRAMECURSORREF, nb))
addHandle(MuFCRefValue(predefinedEntities.FRAMECURSORREF, nb))
}
/** Close a frame cursor. */
......@@ -552,7 +555,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
val kas = hkac.keepalives
for (ka <- kas) yield {
val box = f.boxes(ka)
val ty = TypeInferer.inferType(ka)
val ty = ka.inferredType
addHandle(MuValue(ty, box))
}
}
......@@ -601,35 +604,35 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
def tr64ToFP(value: MuTagRef64Value): MuDoubleValue = {
val raw = value.vb.raw
val box = new BoxDouble(OpHelper.tr64ToFP(raw))
addHandle(MuDoubleValue(InternalTypes.DOUBLE, box))
addHandle(MuDoubleValue(predefinedEntities.DOUBLE, box))
}
/** Extract the int held by a tagref64. */
def tr64ToInt(value: MuTagRef64Value): MuIntValue = {
val raw = value.vb.raw
val box = new BoxInt(OpHelper.tr64ToInt(raw))
addHandle(MuIntValue(InternalTypes.I52, box))
addHandle(MuIntValue(predefinedEntities.I52, box))
}
/** Extract the object ref held by a tagref64. */
def tr64ToRef(value: MuTagRef64Value): MuRefValue = {
val raw = value.vb.raw
val box = new BoxRef(OpHelper.tr64ToRef(raw))
addHandle(MuRefValue(InternalTypes.REF_VOID, box))
addHandle(MuRefValue(predefinedEntities.REF_VOID, box))
}
/** Extract the tag held by a tagref64. */
def tr64ToTag(value: MuTagRef64Value): MuIntValue = {
val raw = value.vb.raw
val box = new BoxInt(OpHelper.tr64ToTag(raw))
addHandle(MuIntValue(InternalTypes.I6, box))
addHandle(MuIntValue(predefinedEntities.I6, box))
}
/** Convert a double to a tagref64. */
def tr64FromFP(value: MuDoubleValue): MuTagRef64Value = {
val fp = value.vb.value
val box = new BoxTagRef64(OpHelper.fpToTr64(fp))
addHandle(MuTagRef64Value(InternalTypes.TAGREF64, box))
addHandle(MuTagRef64Value(predefinedEntities.TAGREF64, box))
}
/** Convert an int to a tagref64. */
......@@ -637,7 +640,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
if (value.ty.length != 52) throw new IllegalArgumentException("Expect int<52>, found %s".format(value.ty.repr))
val i = value.vb.value
val box = new BoxTagRef64(OpHelper.intToTr64(i.longValue))
addHandle(MuTagRef64Value(InternalTypes.TAGREF64, box))
addHandle(MuTagRef64Value(predefinedEntities.TAGREF64, box))
}
/** Convert an object ref and a tag to a tagref64. */
......@@ -646,7 +649,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
val refv = ref.vb.objRef
val tagv = tag.vb.value
val box = new BoxTagRef64(OpHelper.refToTr64(refv, tagv.longValue))
addHandle(MuTagRef64Value(InternalTypes.TAGREF64, box))
addHandle(MuTagRef64Value(predefinedEntities.TAGREF64, box))
}
def enableWatchPoint(wpID: MuID): Unit = {
......@@ -666,7 +669,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
}
}
pin(objRef)
val ptrTy = InternalTypePool.ptrOf(objTy)
val ptrTy = internalEntityPool.ptrOf(objTy)
val box = new BoxPointer(objRef + offset)
addHandle(MuUPtrValue(ptrTy, box))
}
......@@ -695,7 +698,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
assert(microVM.memoryManager.globalMemory.isInSpace(addr) || 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))
val ptrTy = InternalTypePool.ptrOf(objTy)
val ptrTy = internalEntityPool.ptrOf(objTy)
val box = new BoxPointer(addr)
addHandle(MuUPtrValue(ptrTy, box))
}
......@@ -709,7 +712,7 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
val c = cookie.vb.value.toLong
val addr = microVM.nativeCallHelper.exposeFuncDynamic(f, c)
addHandle(MuUFPValue(InternalTypePool.funcPtrOf(sig), BoxPointer(addr)))
addHandle(MuUFPValue(internalEntityPool.funcPtrOf(sig), BoxPointer(addr)))
}
def unexpose(callConv: Flag, addr: MuUFPValue): Unit = {
......@@ -755,19 +758,19 @@ class MuCtx(val ctxID: MuInternalID, _mutator: Mutator)(
// Internal methods for the micro VM
def handleFromInterpreterThread(thr: Option[InterpreterThread]): MuThreadRefValue = {
val t = InternalTypes.THREADREF
val t = predefinedEntities.THREADREF
val box = BoxThread(thr)
addHandle(MuThreadRefValue(t, box))
}
def handleFromInterpreterStack(sta: Option[InterpreterStack]): MuStackRefValue = {
val s = InternalTypes.STACKREF
val s = predefinedEntities.STACKREF
val box = BoxStack(sta)
addHandle(MuStackRefValue(s, box))
}
def handleFromAddr(addr: Long): MuRefValue = {
val t = InternalTypes.REF_VOID
val t = predefinedEntities.REF_VOID
val box = BoxRef(addr)
addHandle(MuRefValue(t, box))
}
......
......@@ -14,27 +14,26 @@ import java.util.zip.ZipFile
import scala.collection.Map
import scala.collection.mutable.HashMap
import org.slf4j.LoggerFactory
import com.typesafe.scalalogging.Logger
import uvm.{ MuID, MuName }
import uvm.refimpl.{ Word, WORD_SIZE_BYTES }
import uvm.refimpl.{ WORD_SIZE_BYTES, Word }
import uvm.refimpl.MicroVM
import uvm.refimpl.cmdline.NativeArgv
import uvm.refimpl.itpr.BoxInt
import uvm.refimpl.itpr.BoxPointer
import uvm.refimpl.itpr.HowToResume
import uvm.refimpl.itpr.OpHelper
import uvm.refimpl.mem.HeaderUtils
import uvm.refimpl.mem.TypeSizes
import uvm.refimpl.nat.NativeSupport
import uvm.types.TypeHybrid
import uvm.utils.IOHelpers
import uvm.utils.IOHelpers.forEachLine
import uvm.utils.MappedIDFactory
import uvm.utils.WithUtils.tryWithResource
import scala.collection.mutable.ArrayBuffer
import uvm.refimpl.itpr.HowToResume
import uvm.refimpl.cmdline.NativeArgv
import uvm.refimpl.itpr.BoxInt
import uvm.refimpl.InternalTypePool
import uvm.refimpl.InternalTypes
import uvm.refimpl.itpr.BoxPointer
import uvm.utils.IOHelpers
import com.typesafe.scalalogging.Logger
import org.slf4j.LoggerFactory
import uvm.refimpl.mem.HeaderUtils
object BootImageLoader {
val logger = Logger(LoggerFactory.getLogger(getClass.getName))
......@@ -44,8 +43,8 @@ object BootImageLoader {
}
class BootImageLoader(file: String, maybeAllArgs: Option[Seq[String]])(implicit microVM: MicroVM) extends AutoCloseable {
import BootImageLoader._
import BootImageFile._
import BootImageLoader._
private val globalBundle = microVM.globalBundle
private val memoryManager = microVM.memoryManager
......
package uvm.refimpl.cmdline
import java.io.BufferedReader
import java.io.InputStreamReader
import java.nio.charset.StandardCharsets
import java.util.zip.ZipFile
import scala.collection.mutable.HashMap
import uvm.{MuID, MuName}
import uvm.refimpl.HowToResume.PassValues
import uvm.refimpl.InternalTypes
import uvm.refimpl.MicroVM
import uvm.refimpl.UvmRuntimeException
import uvm.refimpl.VMConf
import uvm.refimpl.WORD_SIZE_BYTES
import uvm.refimpl.nat.NativeSupport
import uvm.utils.WithUtils.tryWithResource
/** Run Mu from the command line. */
......
......@@ -69,6 +69,8 @@ class HailScriptLoader(recordSourceInfo: Boolean = true)(implicit microVM: Micro
class InstanceHailScriptLoader(microVM: MicroVM, memorySupport: MemorySupport, mc: MuCtx, source: String,
val recordSourceInfo: Boolean) extends AdvancedAntlrHelper {
import HailScriptLoader._
private val predefinedEntities = microVM.staticAnalyzer.predefinedEntities
val sourceLines = source.lines.toIndexedSeq
......@@ -229,7 +231,7 @@ class InstanceHailScriptLoader(microVM: MicroVM, memorySupport: MemorySupport, m
def unexpectedGlobalTypeError(gv: GlobalVariable): Nothing = {
throw new UvmHailParsingException(inCtx(rv, "Unsuitable global variable type. Expected: %s, Found: %s".format(
lty, TypeInferer.inferType(gv))))
lty, gv.inferredType)))
}
// Reused by their types as well as tagref64
......@@ -254,7 +256,7 @@ class InstanceHailScriptLoader(microVM: MicroVM, memorySupport: MemorySupport, m
def resForRefType(rv: RValueContext): (MuRefValue, Boolean) = {
rv match {
case nu: RVNullContext => (mc.handleFromConst(InternalTypes.NULL_REF_VOID.id).asInstanceOf[MuRefValue], true)
case nu: RVNullContext => (mc.handleFromConst(predefinedEntities.NULL_REF_VOID.id).asInstanceOf[MuRefValue], true)
case hr: RVHailRefContext => (resRVHailRef(hr), false)
case _ => unexpectedRValueError()
}
......@@ -367,7 +369,7 @@ class InstanceHailScriptLoader(microVM: MicroVM, memorySupport: MemorySupport, m
}
case t: TypeIRef => {
val hr = rv match {
case nu: RVNullContext => mc.handleFromConst(InternalTypes.NULL_IREF_VOID.id)
case nu: RVNullContext => mc.handleFromConst(predefinedEntities.NULL_IREF_VOID.id)
case io: RVIRefOfContext => evalLValue(io.lValue()).iref
case RVGlobalOf(gv: GlobalCell) => mc.handleFromGlobal(gv.id)
case RVGlobalOf(gv) => unexpectedGlobalTypeError(gv)
......@@ -378,7 +380,7 @@ class InstanceHailScriptLoader(microVM: MicroVM, memorySupport: MemorySupport, m
}
case t: TypeFuncRef => {
val hr = rv match {
case nu: RVNullContext => mc.handleFromConst(InternalTypes.NULL_FUNCREF_VV.id)
case nu: RVNullContext => mc.handleFromConst(predefinedEntities.NULL_FUNCREF_VV.id)
case RVGlobalOf(gv: Function) => mc.handleFromFunc(gv.id)
case RVGlobalOf(gv) => unexpectedGlobalTypeError(gv)
case _ => unexpectedRValueError()
......@@ -388,7 +390,7 @@ class InstanceHailScriptLoader(microVM: MicroVM, memorySupport: MemorySupport, m
}
case t: TypeThreadRef => {
val hr = rv match {
case nu: RVNullContext => mc.handleFromConst(InternalTypes.NULL_THREADREF.id)
case nu: RVNullContext => mc.handleFromConst(predefinedEntities.NULL_THREADREF.id)
case _ => unexpectedRValueError()
}
mc.store(NOT_ATOMIC, lir, hr)
......@@ -396,7 +398,7 @@ class InstanceHailScriptLoader(microVM: MicroVM, memorySupport: MemorySupport, m
}
case t: TypeStackRef => {
val hr = rv match {
case nu: RVNullContext => mc.handleFromConst(InternalTypes.NULL_STACKREF.id)
case nu: RVNullContext => mc.handleFromConst(predefinedEntities.NULL_STACKREF.id)
case _ => unexpectedRValueError()
}
mc.store(NOT_ATOMIC, lir, hr)
......
......@@ -16,6 +16,8 @@ trait InstructionExecutor extends InterpreterActions with CommInstExecutor {
protected def mutator: Mutator
implicit protected def microVM: MicroVM
implicit protected def memorySupport: MemorySupport
private def internalEntityPool = microVM.staticAnalyzer.internalEntityPool
/** Interpret the current instruction. */
protected def interpretCurrentInstruction(): Unit = try {
......@@ -459,7 +461,7 @@ trait InstructionExecutor extends InterpreterActions with CommInstExecutor {
}
case i @ InstLoad(ptr, ord, referentTy, loc, excClause) => {
val uty = InternalTypePool.unmarkedOf(referentTy)
val uty = internalEntityPool.unmarkedOf(referentTy)
val ib = resultBox(0)
val addr = addressOf(ptr, loc)
......@@ -472,7 +474,7 @@ trait InstructionExecutor extends InterpreterActions with CommInstExecutor {
}
case i @ InstStore(ptr, ord, referentTy, loc, newVal, excClause) => {
val uty = InternalTypePool.unmarkedOf(referentTy)
val uty = internalEntityPool.unmarkedOf(referentTy)
val nvb = boxOf(newVal)
val addr = addressOf(ptr, loc)
......@@ -485,7 +487,7 @@ trait InstructionExecutor extends InterpreterActions with CommInstExecutor {
}
case i @ InstCmpXchg(ptr, weak, ordSucc, ordFail, referentTy, loc, expected, desired, excClause) => {
val uty = InternalTypePool.unmarkedOf(referentTy)
val uty = internalEntityPool.unmarkedOf(referentTy)
val eb = boxOf(expected)
val db = boxOf(desired)
val br = resultBox(0)
......@@ -502,7 +504,7 @@ trait InstructionExecutor extends InterpreterActions with CommInstExecutor {
}
case i @ InstAtomicRMW(ptr, ord, op, referentTy, loc, opnd, excClause) => {
val uty = InternalTypePool.unmarkedOf(referentTy)
val uty = internalEntityPool.unmarkedOf(referentTy)
val ob = boxOf(opnd)
val ib = resultBox(0)
......
......@@ -715,10 +715,10 @@ object MemoryOperations {
*
* @return The address of the allocated object.
*/
def strToBytes(str: String)(implicit memorySupport: MemorySupport, mutator: Mutator): Word = {
def strToBytes(str: String)(implicit microVM: MicroVM, memorySupport: MemorySupport, mutator: Mutator): Word = {
val bytes = str.getBytes(US_ASCII)
val len = bytes.length
val loc = mutator.newHybrid(InternalTypes.BYTES, len)
val loc = mutator.newHybrid(microVM.staticAnalyzer.predefinedEntities.BYTES, len)
memorySupport.storeLong(loc, bytes.length.toLong)
val begin = loc + WORD_SIZE_BYTES
memorySupport.storeBytes(begin, bytes, 0, len, true)
......
......@@ -515,7 +515,7 @@ class DefinedMuFrame(
}
private def putBox(lv: LocalVariable) {
val ty = TypeInferer.inferType(lv)
val ty = lv.inferredType
try {
boxes.put(lv, ValueBox.makeBoxForType(ty))
} catch {
......
......@@ -52,7 +52,7 @@ class MemoryManager(val vmConf: VMConf)(implicit microVM: MicroVM) extends AutoC
def makeMutator(name: String): Mutator = heap.makeMutator(name)
def makeStackMemory(mutator: Mutator): StackMemory = {
val objRef = mutator.newHybrid(InternalTypes.BYTE_ARRAY, vmConf.stackSize)
val objRef = mutator.newHybrid(microVM.staticAnalyzer.predefinedEntities.BYTE_ARRAY, vmConf.stackSize)
val stackMemory = new StackMemory(objRef, vmConf.stackSize)
stackMemory
}
......
......@@ -6,7 +6,14 @@ import uvm._
import uvm.comminsts._
import uvm.types._
abstract class SSAVariable extends ChildNode
abstract class SSAVariable extends ChildNode {
/**
* The type is discovered by the static analyser at bundle loading time.
* During the execution of Mu IR programs, the MicroVM implementation can
* assume this field is already assigned.
*/
var inferredType: Type = null
}
// Global variables: Constants, Global Cells and Functions (Function is defined in controlFlow.scala)
......
package uvm.staticanalysis
import org.slf4j.LoggerFactory
import com.typesafe.scalalogging.Logger
import uvm._
import uvm.ssavariables._
import uvm.types._
object BundleChecker {
val logger: Logger = Logger(LoggerFactory.getLogger(getClass.getName))
implicit class RichMuTypes(val tys1: Seq[Type]) extends AnyVal {
def shallowEq(tys2: Seq[Type]): Boolean = {
tys1.size == tys2.size && ((tys1 zip tys2).map {
case (ty1, ty2) => ty1 shallowEq ty2
}).foldLeft(true)((x, y) => x && y)
}
}
implicit class RichMuType(val ty1: Type) extends AnyVal {
def shallowEq(ty2: Type): Boolean = {
(ty1, ty2) match {
case (TypeInt(l1), TypeInt(l2)) => l1 == l2
case (TypeFloat(), TypeFloat()) => true
case (TypeDouble(), TypeDouble()) => true
case (TypeUPtr(_), TypeUPtr(_)) => true
case (TypeUFuncPtr(_), TypeUFuncPtr(_)) => true
case (TypeVoid(), TypeVoid()) => true
case (TypeRef(_), TypeRef(_)) => true
case (TypeIRef(_), TypeIRef(_)) => true
case (TypeWeakRef(_), TypeWeakRef(_)) => true
case (TypeTagRef64(), TypeTagRef64()) => true
case (TypeFuncRef(_), TypeFuncRef(_)) => true
case (TypeThreadRef(), TypeThreadRef()) => true
case (TypeStackRef(), TypeStackRef()) => true
case (TypeFrameCursorRef(), TypeFrameCursorRef()) => true
case (TypeIRBuilderRef(), TypeIRBuilderRef()) => true
case (TypeStruct(tys1), TypeStruct(tys2)) => tys1 shallowEq tys2
case (TypeHybrid(fts1, vt1), TypeHybrid(fts2, vt2)) => (fts1 shallowEq fts2) && (vt1 shallowEq vt2)
case (TypeArray(et1, l1), TypeArray(et2, l2)) => (et1 shallowEq et2) && (l1 == l2)
case (TypeVector(et1, l1), TypeVector(et2, l2)) => (et1 shallowEq et2) && (l1 == l2)
case others => false
}
}
}
val INT_CMP_OPS = {
import CmpOptr._
Seq(EQ, NE, ULT, ULE, UGT, UGE, SLT, SLE, SGT, SGE)
}
val FP_CMP_OPS = {
import CmpOptr._
Seq(FTRUE, FFALSE, FORD, FOEQ, FONE, FOLT, FOLE, FOGT, FOGE,
FUNO, FUEQ, FUNE, FULT, FULE, FUGT, FUGE)
}
}
class BundleChecker {
import BundleChecker._
type MutableSet[T] = collection.mutable.HashSet[T]
val MutableSet = collection.mutable.HashSet
type MutableMap[K, V] = collection.mutable.HashMap[K, V]
val MutableMap = collection.mutable.HashMap
type MutableQueue[T] = collection.mutable.Queue[T]
val MutableQueue = collection.mutable.Queue
type MutableStack[T] = collection.mutable.Stack[T]
val MutableStack = collection.mutable.Stack
def checkBundle(bundle: Bundle, parentBundle: Option[GlobalBundle]): Unit = {
new BundleChecker(bundle, parentBundle).check()
}
class BundleChecker(bundle: Bundle, parentBundle: Option[GlobalBundle]) {
def check(): Unit = {
checkTypes()
checkSigs()
checkConsts()
checkGlobals()
checkExpFuncs()
checkFuncs()
}
def checkTypes(): Unit = {
val compositeTypes = bundle.typeNs.all.flatMap {
case ty: AbstractCompositeType => Some(ty)
case _ => None
}.toSeq
checkCompositeTypesNotRecursive(compositeTypes)
}
def checkCompositeTypesNotRecursive(compTys: Seq[AbstractCompositeType]): Unit = {
val world = MutableSet(compTys: _*) // All types in this bundle. Assume all other types are valid.
val visited = MutableSet[Type]()
for (rootTy <- world if !visited.contains(rootTy)) {
val inStack = MutableSet[AbstractCompositeType]()
def visit(ty: AbstractCompositeType): Unit = {
logger.debug(