Commit 5c2d1c03 authored by Kunshan Wang's avatar Kunshan Wang
Browse files

Adding uvm.meta.* comminsts...

parent 6b3ecf77
......@@ -39,4 +39,23 @@ object CommInsts extends SimpleNamespace[CommInst] {
commInst(0x242, "@uvm.native.expose")
commInst(0x243, "@uvm.native.unexpose")
commInst(0x244, "@uvm.native.get_cookie")
commInst(0x250, "@uvm.meta.id_of")
commInst(0x251, "@uvm.meta.name_of")
commInst(0x252, "@uvm.meta.load_bundle")
commInst(0x253, "@uvm.meta.load_hail")
commInst(0x254, "@uvm.meta.cur_func")
commInst(0x255, "@uvm.meta.cur_func_ver")
commInst(0x256, "@uvm.meta.cur_inst")
commInst(0x257, "@uvm.meta.dump_keepalives")
commInst(0x258, "@uvm.meta.pop_frame")
commInst(0x259, "@uvm.meta.push_frame")
commInst(0x25a, "@uvm.meta.enable_watchpoint")
commInst(0x25b, "@uvm.meta.disable_watchpoint")
commInst(0x25c, "@uvm.meta.set_trap_handler")
}
\ No newline at end of file
package uvm.refimpl
import java.io.Reader
import uvm.refimpl.mem.Mutator
/** Common implementations of operations on the MicroVM. Used by both the MuCtx and many comminsts. */
object MetaOperations {
/** Load a Mu IR bundle */
def loadBundle(r: Reader)(implicit microVM: MicroVM): Unit = {
val bundle = microVM.irReader.read(r, microVM.globalBundle)
microVM.addBundle(bundle)
}
/** Load a Mu IR bundle */
def loadBundle(s: String)(implicit microVM: MicroVM): Unit = {
val bundle = microVM.irReader.read(s, microVM.globalBundle)
microVM.addBundle(bundle)
}
/** Load a HAIL script */
def loadHail(r: Reader)(implicit microVM: MicroVM, mutator: Mutator): Unit = ???
/** Load a HAIL script */
def loadHail(s: String)(implicit microVM: MicroVM, mutator: Mutator): Unit = ???
}
\ No newline at end of file
......@@ -42,6 +42,12 @@ class MicroVM(heapSize: Word = MicroVM.DEFAULT_HEAP_SIZE,
globalBundle.typeNs.add(InternalTypes.VOID)
globalBundle.typeNs.add(InternalTypes.BYTE)
globalBundle.typeNs.add(InternalTypes.BYTE_ARRAY)
// Types for the @uvm.meta.* common instructions.
globalBundle.typeNs.add(InternalTypes.BYTES)
globalBundle.typeNs.add(InternalTypes.BYTES_R)
globalBundle.typeNs.add(InternalTypes.REFS)
globalBundle.typeNs.add(InternalTypes.REFS_R)
}
/**
......
......@@ -13,23 +13,24 @@ import scala.collection.mutable.ArrayBuffer
import uvm.ssavariables.Flag
import uvm.refimpl.itpr.{ HowToResume => ItprHowToResume }
import scala.collection.mutable.Buffer
import java.nio.charset.Charset
object MuValue {
def apply(ty: Type, vb: ValueBox): MuValue = (ty, vb) match {
case (t: TypeInt, v: BoxInt) => MuIntValue(t, v)
case (t: TypeFloat, v: BoxFloat) => MuFloatValue(t, v)
case (t: TypeDouble, v: BoxDouble) => MuDoubleValue(t, v)
case (t: TypeRef, v: BoxRef) => MuRefValue(t, v)
case (t: TypeIRef, v: BoxIRef) => MuIRefValue(t, v)
case (t: TypeStruct, v: BoxSeq) => MuStructValue(t, v)
case (t: TypeArray, v: BoxSeq) => MuArrayValue(t, v)
case (t: TypeVector, v: BoxSeq) => MuVectorValue(t, v)
case (t: TypeFuncRef, v: BoxFunc) => MuFuncRefValue(t, v)
case (t: TypeThreadRef, v: BoxThread) => MuThreadRefValue(t, v)
case (t: TypeStackRef, v: BoxStack) => MuStackRefValue(t, v)
case (t: TypeInt, v: BoxInt) => MuIntValue(t, v)
case (t: TypeFloat, v: BoxFloat) => MuFloatValue(t, v)
case (t: TypeDouble, v: BoxDouble) => MuDoubleValue(t, v)
case (t: TypeRef, v: BoxRef) => MuRefValue(t, v)
case (t: TypeIRef, v: BoxIRef) => MuIRefValue(t, v)
case (t: TypeStruct, v: BoxSeq) => MuStructValue(t, v)
case (t: TypeArray, v: BoxSeq) => MuArrayValue(t, v)
case (t: TypeVector, v: BoxSeq) => MuVectorValue(t, v)
case (t: TypeFuncRef, v: BoxFunc) => MuFuncRefValue(t, v)
case (t: TypeThreadRef, v: BoxThread) => MuThreadRefValue(t, v)
case (t: TypeStackRef, v: BoxStack) => MuStackRefValue(t, v)
case (t: TypeTagRef64, v: BoxTagRef64) => MuTagRef64Value(t, v)
case (t: TypeUPtr, v: BoxPointer) => MuUPtrValue(t, v)
case (t: TypeUFuncPtr, v: BoxPointer) => MuUFPValue(t, v)
case (t: TypeUPtr, v: BoxPointer) => MuUPtrValue(t, v)
case (t: TypeUFuncPtr, v: BoxPointer) => MuUFPValue(t, v)
case (t, v) => {
throw new IllegalArgumentException("Improper type-box pair: %s,%s".format(t.toString, vb.getClass.getSimpleName))
}
......@@ -91,12 +92,19 @@ trait UndefinedFunctionHandler {
def handleUndefinedFunction(functionID: Int): Unit
}
object MuCtx {
val US_ASCII = Charset.forName("US-ASCII")
}
/**
* A client context. The main part of the API. It keeps thread-local states, including a set of handles. It provides
* operations on the Mu VM.
*/
class MuCtx(mutator: Mutator)(
class MuCtx(_mutator: Mutator)(
implicit microVM: MicroVM, memorySupport: MemorySupport) extends ObjectPinner {
implicit def mutator = _mutator
val handles = new HashSet[MuValue]()
val pinSet = new ArrayBuffer[Word]
......@@ -116,21 +124,23 @@ class MuCtx(mutator: Mutator)(
/** Load a Mu IR bundle */
def loadBundle(r: Reader): Unit = {
val bundle = microVM.irReader.read(r, microVM.globalBundle)
microVM.addBundle(bundle)
MetaOperations.loadBundle(r)
}
/** Load a Mu IR bundle */
def loadBundle(s: String): Unit = {
val bundle = microVM.irReader.read(s, microVM.globalBundle)
microVM.addBundle(bundle)
MetaOperations.loadBundle(s)
}
/** Load a HAIL script */
def loadHail(r: Reader): Unit = ???
def loadHail(r: Reader): Unit = {
MetaOperations.loadHail(r)
}
/** Load a HAIL script */
def loadHail(s: String): Unit = ???
def loadHail(s: String): Unit = {
MetaOperations.loadHail(s)
}
private def addHandle[T <: MuValue](h: T): T = {
handles.add(h)
......@@ -244,11 +254,11 @@ class MuCtx(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: MuFuncRefValue, r: MuFuncRefValue) => l.vb.func == r.vb.func
case (l: MuRefValue, r: MuRefValue) => l.vb.objRef == r.vb.objRef
case (l: MuIRefValue, r: MuIRefValue) => l.vb.oo == r.vb.oo
case (l: MuFuncRefValue, r: MuFuncRefValue) => l.vb.func == r.vb.func
case (l: MuThreadRefValue, r: MuThreadRefValue) => l.vb.thread == r.vb.thread
case (l: MuStackRefValue, r: MuStackRefValue) => l.vb.stack == r.vb.stack
case (l: MuStackRefValue, r: MuStackRefValue) => l.vb.stack == r.vb.stack
case (l, r) => {
throw new IllegalArgumentException("Bad types for refEq: %s and %s".format(
l.showTy, r.showTy))
......@@ -326,8 +336,8 @@ class MuCtx(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 (MuFuncRefValue(ty, vb), ty2 @ TypeFuncRef(_)) => MuFuncRefValue(ty2, vb)
case _ => {
throw new IllegalArgumentException("Bad types for refcast: opnd:%s, newType:%s".format(
......@@ -431,7 +441,7 @@ class MuCtx(mutator: Mutator)(
/** Perform compare exchange on a location. */
def cmpXchg(ordSucc: MemoryOrder, ordFail: MemoryOrder, weak: Boolean,
loc: MuIRefValue, expected: MuValue, desired: MuValue): (MuValue, Boolean) = {
loc: MuIRefValue, expected: MuValue, desired: MuValue): (MuValue, Boolean) = {
val (ptr, ty) = loc.ty match {
case TypeIRef(t) => (false, t)
}
......@@ -485,7 +495,7 @@ class MuCtx(mutator: Mutator)(
val sv = getStackNotNull(stack)
val itprHtr = htr match {
case HowToResume.PassValues(values) => ItprHowToResume.PassValues(values.map(_.vb))
case HowToResume.ThrowExc(exc) => ItprHowToResume.ThrowExc(exc.vb.objRef)
case HowToResume.ThrowExc(exc) => ItprHowToResume.ThrowExc(exc.vb.objRef)
}
val thr = microVM.threadStackManager.newThread(sv, itprHtr)
......@@ -500,31 +510,10 @@ class MuCtx(mutator: Mutator)(
sv.kill()
}
private def nthFrame(stack: InterpreterStack, n: Int): InterpreterFrame = {
val it = stack.frames
for (i <- (0 until n)) {
if (it.hasNext) {
it.next()
} else {
throw new UvmRuntimeException("The stack %d only has %d frames, but the %d-th frame is requested.".format(i, n))
}
}
if (it.hasNext) {
it.next()
} else {
throw new UvmRuntimeException("The stack %d only has %d frames, but the %d-th frame is requested.".format(n, n))
}
}
/** Get the ID of the current function of a frame. Return 0 for native frames. */
def curFunc(stack: MuStackRefValue, frame: Int): Int = {
val sv = getStackNotNull(stack)
val fr = nthFrame(sv, frame)
fr match {
case f: NativeFrame => 0
case f: MuFrame => f.func.id
}
sv.nthFrame(frame).curFuncID
}
/**
......@@ -533,12 +522,7 @@ class MuCtx(mutator: Mutator)(
*/
def curFuncVer(stack: MuStackRefValue, frame: Int): Int = {
val sv = getStackNotNull(stack)
val fr = nthFrame(sv, frame)
fr match {
case f: NativeFrame => 0
case f: UndefinedMuFrame => 0
case f: DefinedMuFrame => f.funcVer.id
}
sv.nthFrame(frame).curFuncVerID
}
/**
......@@ -547,18 +531,13 @@ class MuCtx(mutator: Mutator)(
*/
def curInst(stack: MuStackRefValue, frame: Int): Int = {
val sv = getStackNotNull(stack)
val fr = nthFrame(sv, frame)
fr match {
case f: NativeFrame => 0
case f: UndefinedMuFrame => 0
case f: DefinedMuFrame => if (f.justCreated) 0 else f.curInst.id
}
sv.nthFrame(frame).curInstID
}
/** Dump keep-alive variables of the current instruction. */
def dumpKeepalives(stack: MuStackRefValue, frame: Int): Seq[MuValue] = {
val sv = getStackNotNull(stack)
val fr = nthFrame(sv, frame)
val fr = sv.nthFrame(frame)
fr match {
case f: NativeFrame => {
throw new UvmRefImplException("Attempt to dump keepalives from a native frame. Funciton 0x%x".format(f.func))
......@@ -681,10 +660,10 @@ class MuCtx(mutator: Mutator)(
def pin(loc: MuValue): MuUPtrValue = {
val (objTy, (objRef, offset)) = loc match {
case MuRefValue(t, vb) => (t, (vb.objRef, 0L))
case MuRefValue(t, vb) => (t, (vb.objRef, 0L))
case MuIRefValue(t, vb) => (t, vb.oo)
case _ => {
throw new IllegalArgumentException("loc must be ref or iref. Found %s".format())
throw new IllegalArgumentException("loc must be ref or iref. Found %s".format(loc.ty))
}
}
pin(objRef)
......@@ -695,10 +674,10 @@ class MuCtx(mutator: Mutator)(
def unpin(loc: MuValue): Unit = {
val (objTy, objRef) = loc match {
case MuRefValue(t, vb) => (t, vb.objRef)
case MuRefValue(t, vb) => (t, vb.objRef)
case MuIRefValue(t, vb) => (t, vb.objRef)
case _ => {
throw new IllegalArgumentException("loc must be ref or iref. Found %s".format())
throw new IllegalArgumentException("loc must be ref or iref. Found %s".format(loc.ty))
}
}
unpin(objRef)
......@@ -748,14 +727,18 @@ object RichMuCtx {
def handleFromInt52(num: BigInt) = ctx.handleFromInt(num, 52)
def handleFromInt64(num: BigInt) = ctx.handleFromInt(num, 64)
def deleteValue(vs: MuValue*) = vs.foreach(ctx.deleteValue)
class DelayedDisposer(garbageList: Buffer[MuValue]) {
def apply[T<:MuValue](v: T): T = {
def apply[T <: MuValue](v: T): T = {
garbageList += v
v
}
def <<[T <: MuValue](v: T): T = {
garbageList += v
v
}
}
def autoDispose[T](f: DelayedDisposer => T) = {
val garbages = ArrayBuffer[MuValue]()
val dd = new DelayedDisposer(garbages)
......@@ -763,7 +746,7 @@ object RichMuCtx {
garbages.foreach(ctx.deleteValue)
rv
}
def loadInt(ord: MemoryOrder, loc: MuIRefValue) = ctx.load(ord, loc).asInstanceOf[MuIntValue]
def loadFloat(ord: MemoryOrder, loc: MuIRefValue) = ctx.load(ord, loc).asInstanceOf[MuFloatValue]
def loadDouble(ord: MemoryOrder, loc: MuIRefValue) = ctx.load(ord, loc).asInstanceOf[MuDoubleValue]
......@@ -785,5 +768,24 @@ object RichMuCtx {
def storeStackRef(ord: MemoryOrder, loc: MuIRefValue, newval: MuValue) = ctx.store(ord, loc, newval).asInstanceOf[MuStackRefValue]
def storeTagRef64(ord: MemoryOrder, loc: MuIRefValue, newval: MuValue) = ctx.store(ord, loc, newval).asInstanceOf[MuTagRef64Value]
def storeVector(ord: MemoryOrder, loc: MuIRefValue, newval: MuValue) = ctx.store(ord, loc, newval).asInstanceOf[MuVectorValue]
def bytesToStr(bytes: MuRefValue): String = ctx.autoDispose { x =>
val hIR = x << ctx.getIRef(bytes)
val hFix = x << ctx.getFieldIRef(hIR, 0)
val hLen = x << ctx.loadInt(NOT_ATOMIC, hFix)
val len = ctx.handleToSInt(hLen).toLong
val hVar = x << ctx.getVarPartIRef(hIR)
val byteValues = for (i <- 0L until len) yield ctx.autoDispose { x =>
val hI = x << ctx.handleFromInt64(i)
val hVarI = x << ctx.shiftIRef(hVar, hI)
val hByte = x << ctx.loadInt(NOT_ATOMIC, hVarI)
val byte = ctx.handleToSInt(hByte).toByte
byte
}
val bytesArray = byteValues.toArray
val str = new String(bytesArray, MuCtx.US_ASCII)
str
}
}
}
\ No newline at end of file
......@@ -18,12 +18,21 @@ object InternalTypes {
i.name = Some(name)
i
}
def :=(idName: (Int, String)): T = {
val (id, name) = idName
i.id = id
i.name = Some(name)
i
}
}
def internal(name: String) = "@uvm.internal.types." + name
val I1 = TypeInt(1) := internal("i1")
val I6 = TypeInt(6) := internal("i6")
val I8 = TypeInt(6) := internal("i8")
val I16 = TypeInt(6) := internal("i16")
val I32 = TypeInt(32) := internal("i32")
val I52 = TypeInt(52) := internal("i52")
val I64 = TypeInt(52) := internal("i64")
......@@ -39,6 +48,11 @@ object InternalTypes {
val STACK = TypeStackRef() := internal("stack")
val THREAD = TypeThreadRef() := internal("thread")
val TAGREF64 = TypeTagRef64() := internal("tagref64")
val BYTES = TypeHybrid(Seq(I64), I8) := (0x260, "@uvm.meta.bytes")
val BYTES_R = TypeRef(BYTES) := (0x261, "@uvm.meta.bytes_r")
val REFS = TypeHybrid(Seq(I64), REF_VOID) := (0x262, "@uvm.meta.refs")
val REFS_R = TypeRef(BYTES) := (0x263, "@uvm.meta.refs_r")
}
object InternalTypePool {
......@@ -146,10 +160,28 @@ object TypeInferer {
case TypeRef(t) => Seq(ptrOf(t))
case TypeIRef(t) => Seq(ptrOf(t))
}
case "@uvm.native.unpin" => Seq()
case "@uvm.native.expose" => Seq(funcPtrOf(i.funcSigList(0)))
case "@uvm.native.unexpose" => Seq()
case "@uvm.native.get_cookie" => Seq(I64)
case "@uvm.native.unpin" => Seq()
case "@uvm.native.expose" => Seq(funcPtrOf(i.funcSigList(0)))
case "@uvm.native.unexpose" => Seq()
case "@uvm.native.get_cookie" => Seq(I64)
case "@uvm.meta.id_of" => Seq(I32)
case "@uvm.meta.name_of" => Seq(BYTES_R)
case "@uvm.meta.load_bundle" => Seq(BYTES_R)
case "@uvm.meta.load_hail" => Seq(BYTES_R)
case "@uvm.meta.cur_func" => Seq(I32)
case "@uvm.meta.cur_func_ver" => Seq(I32)
case "@uvm.meta.cur_inst" => Seq(I32)
case "@uvm.meta.dump_keepalives" => Seq(REFS_R)
case "@uvm.meta.pop_frame" => Seq()
case "@uvm.meta.push_frame" => Seq()
case "@uvm.meta.enable_watchpoint" => Seq()
case "@uvm.meta.disable_watchpoint" => Seq()
case "@uvm.meta.set_trap_handler" => Seq()
}
}
}
\ No newline at end of file
......@@ -17,7 +17,7 @@ import uvm.refimpl.nat.NativeCallResult
trait CommInstExecutor extends InterpreterActions with ObjectPinner {
import InterpreterThread.logger
protected def mutator: Mutator
implicit protected def mutator: Mutator
implicit protected def memorySupport: MemorySupport
override def interpretCurrentCommonInstruction(): Unit = {
......@@ -314,6 +314,45 @@ trait CommInstExecutor extends InterpreterActions with ObjectPinner {
continueNormally()
}
case "@uvm.meta.id_of" => {
val Seq(name) = argList
val nameStr = MemoryOperations.bytesToStr(boxOf(name).asInstanceOf[BoxRef].objRef)
val theID = microVM.idOf(nameStr)
resultBox(0).asInstanceOf[BoxInt].value = OpHelper.unprepare(theID, 32)
continueNormally()
}
case "@uvm.meta.name_of" => {
val Seq(theID) = argList
val idInt = boxOf(theID).asInstanceOf[BoxInt].value.toInt
val name = microVM.nameOf(idInt)
val bytesRef = MemoryOperations.strToBytes(name)
resultBox(0).asInstanceOf[BoxRef].objRef = bytesRef
continueNormally()
}
case "@uvm.meta.load_bundle" => {
val Seq(bundle) = argList
val bundleStr = MemoryOperations.bytesToStr(boxOf(bundle).asInstanceOf[BoxRef].objRef)
MetaOperations.loadBundle(bundleStr)
continueNormally()
}
case "@uvm.meta.load_hail" => {
val Seq(hailScript) = argList
val hailStr = MemoryOperations.bytesToStr(boxOf(hailScript).asInstanceOf[BoxRef].objRef)
MetaOperations.loadHail(hailStr)
continueNormally()
}
// Insert more CommInsts here.
case ciName => {
......
package uvm.refimpl.itpr
import uvm.types._
import uvm.ssavariables._
import java.nio.charset.Charset
import uvm.refimpl._
import uvm.refimpl.mem.TypeSizes._
import uvm.refimpl.mem.MemorySupport
import AtomicRMWOptr._
import uvm.refimpl.mem.Mutator
import uvm.refimpl.mem.TypeSizes._
import uvm.refimpl.mem.TypeSizes
import uvm.ssavariables._
import uvm.ssavariables.AtomicRMWOptr._
import uvm.types._
object OpHelper {
......@@ -564,5 +568,39 @@ object MemoryOperations {
}
case _ => throw new UnimplementedOprationException("Futex of %d bit int is not supported".format(len))
}
val US_ASCII = Charset.forName("US-ASCII")
/**
* Read an ASCII string from the memory.
*
* @param loc A ref to a @uvm.meta.bytes object.
*/
def bytesToStr(loc: Word)(implicit memorySupport: MemorySupport): String = {
// It is a hybrid<@i64 @i8> object. The length is determined by the fixed part.
val len = memorySupport.loadLong(loc)
val bytes = new Array[Byte](len.toInt)
val begin = loc + TypeSizes.WORD_SIZE_BYTES
memorySupport.loadBytes(begin, bytes, 0, len, true)
val result = new String(bytes, US_ASCII)
result
}
/**
* Create a Mu @uvm.meta.bytes object to hold an ASCII string.
*
* @return The address of the allocated object.
*/
def strToBytes(str: String)(implicit memorySupport: MemorySupport, mutator: Mutator): Word = {
val bytes = str.getBytes(US_ASCII)
val len = bytes.length
val loc = mutator.newHybrid(InternalTypes.BYTES, len)
memorySupport.storeLong(loc, bytes.length.toLong)
val begin = loc + TypeSizes.WORD_SIZE_BYTES
memorySupport.storeBytes(begin, bytes, 0, len, true)
loc
}
}
......@@ -258,6 +258,18 @@ class InterpreterStack(val id: Int, val stackMemory: StackMemory, stackBottomFun
}
}
/**
* Return the n-th frame of the current stack.
*/
def nthFrame(n: Int): InterpreterFrame = {
val dropped = frames.drop(n)
if (dropped.hasNext) {
dropped.next
} else {
throw new UvmRuntimeException("The stack %d only has %d frames, but the %d-th frame is requested.".format(id, n))
}
}
/** Pop a frame. Part of the API. Also used by THROW */
def popFrame(): Unit = {
top match {
......@@ -281,6 +293,16 @@ abstract class InterpreterFrame(val prev: Option[InterpreterFrame]) {
* The state of the frame. Must be set when creating the frame.
*/
var state: FrameState = _
/** ID of the current function. Return 0 for native frames. */
def curFuncID: Int
/** ID of the current function version Return 0 for native frames or undefined Mu frames. */
def curFuncVerID: Int
/** ID of the current instruction. Return 0 for native frames, undefined Mu frames, or a just-created frame. */
def curInstID: Int
}
object InterpreterFrame {
......@@ -305,7 +327,11 @@ object InterpreterFrame {
}
}
class NativeFrame(val func: Word, prev: Option[InterpreterFrame]) extends InterpreterFrame(prev)
class NativeFrame(val func: Word, prev: Option[InterpreterFrame]) extends InterpreterFrame(prev) {
override def curFuncID: Int = 0
override def curFuncVerID: Int = 0
override def curInstID: Int = 0
}
abstract class MuFrame(val func: Function, prev: Option[InterpreterFrame]) extends InterpreterFrame(prev) {
/**
......@@ -354,6 +380,10 @@ class UndefinedMuFrame(func: Function, prev: Option[InterpreterFrame]) extends M
var virtInst = VIRT_INST_NOT_STARTED
override def scannableBoxes = boxes
override def curFuncID: Int = func.id
override def curFuncVerID: Int = 0
override def curInstID: Int = 0