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.2% of users enabled 2FA.

Commit c6922e2c authored by Kunshan Wang's avatar Kunshan Wang
Browse files

Implemented the frame cursor API.

Existing code based on Int-based frame selectors should not break with
the help of RichMuCtx.
parent ff2815e8
......@@ -17,20 +17,21 @@ 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: TypeTagRef64, v: BoxTagRef64) => MuTagRef64Value(t, v)
case (t: TypeUPtr, v: BoxPointer) => MuUPtrValue(t, v)
case (t: TypeUFuncPtr, v: BoxPointer) => MuUFPValue(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: TypeFrameCursorRef, v: BoxFrameCursor) => MuFCRefValue(t, v)
case (t, v) => {
throw new IllegalArgumentException("Improper type-box pair: %s,%s".format(t.toString, vb.getClass.getSimpleName))
}
......@@ -71,7 +72,7 @@ case class MuStackRefValue(ty: TypeStackRef, vb: BoxStack) extends MuGenRefValue
case class MuTagRef64Value(ty: TypeTagRef64, vb: BoxTagRef64) extends MuValue
case class MuUPtrValue(ty: TypeUPtr, vb: BoxPointer) extends MuValue
case class MuUFPValue(ty: TypeUFuncPtr, vb: BoxPointer) extends MuValue
case class MuFrameCursorRefValue(ty: TypeFrameCursorRef, vb: BoxFrameCursor) extends MuValue
case class MuFCRefValue(ty: TypeFrameCursorRef, vb: BoxFrameCursor) extends MuValue
abstract class TrapHandlerResult
object TrapHandlerResult {
......@@ -419,7 +420,7 @@ class MuCtx(_mutator: Mutator)(
val (ptr, ty) = loc.ty match {
case TypeIRef(t) => (false, t)
}
val uty = InternalTypePool.unmarkedOf(ty)
val addr = MemoryOperations.addressOf(ptr, loc.vb)
val nb = ValueBox.makeBoxForType(uty)
......@@ -443,7 +444,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)
}
......@@ -512,34 +513,67 @@ class MuCtx(_mutator: Mutator)(
sv.kill()
}
private def getCursorNotNull(cursor: MuFCRefValue): FrameCursor = {
cursor.vb.cursor.getOrElse {
throw new UvmRuntimeException("Frame cursor argument cannot be a NULL framecursorref value.")
}
}
/** Create a frame cursor. */
def newCursor(stack: MuStackRefValue): MuFCRefValue = {
val s = getStackNotNull(stack)
val c = microVM.threadStackManager.newFrameCursor(s)
val nb = BoxFrameCursor(Some(c))
addHandle(MuFCRefValue(InternalTypes.FRAMECURSORREF, nb))
}
/** Move cursor to the frame below the current frame. */
def nextFrame(cursor: MuFCRefValue): Unit = {
getCursorNotNull(cursor).nextFrame()
}
/** Copy a frame cursor. */
def copyCursor(cursor: MuFCRefValue): MuFCRefValue = {
val c = getCursorNotNull(cursor)
val nc = microVM.threadStackManager.copyCursor(c)
val nb = BoxFrameCursor(Some(nc))
addHandle(MuFCRefValue(InternalTypes.FRAMECURSORREF, nb))
}
/** Close a frame cursor. */
def closeCursor(cursor: MuFCRefValue): Unit = {
val c = getCursorNotNull(cursor)
microVM.threadStackManager.closeCursor(c)
}
/** 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)
sv.nthFrame(frame).curFuncID
def curFunc(cursor: MuFCRefValue): Int = {
val c = getCursorNotNull(cursor)
c.frame.curFuncID
}
/**
* Get the ID of the current function version of a frame. Return 0 for native frames
* or Mu frames of undefined functions
*/
def curFuncVer(stack: MuStackRefValue, frame: Int): Int = {
val sv = getStackNotNull(stack)
sv.nthFrame(frame).curFuncVerID
def curFuncVer(cursor: MuFCRefValue): Int = {
val c = getCursorNotNull(cursor)
c.frame.curFuncVerID
}
/**
* Get the ID of the current instruction of a frame. Return 0 for native frames, Mu frames for undefined
* functions, or if the frame is just created by newStack or pushFrame.
*/
def curInst(stack: MuStackRefValue, frame: Int): Int = {
val sv = getStackNotNull(stack)
sv.nthFrame(frame).curInstID
def curInst(cursor: MuFCRefValue): Int = {
val c = getCursorNotNull(cursor)
c.frame.curInstID
}
/** Dump keep-alive variables of the current instruction. */
def dumpKeepalives(stack: MuStackRefValue, frame: Int): Seq[MuValue] = {
val sv = getStackNotNull(stack)
val fr = sv.nthFrame(frame)
def dumpKeepalives(cursor: MuFCRefValue): Seq[MuValue] = {
val c = getCursorNotNull(cursor)
val fr = c.frame
fr match {
case f: NativeFrame => {
throw new UvmRefImplException("Attempt to dump keepalives from a native frame. Funciton 0x%x".format(f.func))
......@@ -569,9 +603,10 @@ class MuCtx(_mutator: Mutator)(
}
/** Pop the top frame of a Mu stack. */
def popFrame(stack: MuStackRefValue): Unit = {
val st = getStackNotNull(stack)
st.popFrame()
def popFramesTo(cursor: MuFCRefValue): Unit = {
val c = getCursorNotNull(cursor)
c.stack.popFramesTo(c)
}
/** Create a new frame for a Mu function and push it to the top of a stack. */
......@@ -799,5 +834,61 @@ object RichMuCtx {
val str = new String(bytesArray, MuCtx.US_ASCII)
str
}
// legacy support
/** Get the ID of the current function of a frame. Return 0 for native frames. */
def curFunc(stack: MuStackRefValue, frame: Int): Int = {
val cursor = ctx.newCursor(stack)
for (i <- 0 until frame) {
ctx.nextFrame(cursor)
}
val id = ctx.curFunc(cursor)
ctx.closeCursor(cursor)
ctx.deleteValue(cursor)
id
}
/**
* Get the ID of the current function version of a frame. Return 0 for native frames
* or Mu frames of undefined functions
*/
def curFuncVer(stack: MuStackRefValue, frame: Int): Int = {
val cursor = ctx.newCursor(stack)
for (i <- 0 until frame) {
ctx.nextFrame(cursor)
}
val id = ctx.curFuncVer(cursor)
ctx.closeCursor(cursor)
ctx.deleteValue(cursor)
id
}
/**
* Get the ID of the current instruction of a frame. Return 0 for native frames, Mu frames for undefined
* functions, or if the frame is just created by newStack or pushFrame.
*/
def curInst(stack: MuStackRefValue, frame: Int): Int = {
val cursor = ctx.newCursor(stack)
for (i <- 0 until frame) {
ctx.nextFrame(cursor)
}
val id = ctx.curInst(cursor)
ctx.closeCursor(cursor)
ctx.deleteValue(cursor)
id
}
/** Dump keep-alive variables of the current instruction. */
def dumpKeepalives(stack: MuStackRefValue, frame: Int): Seq[MuValue] = {
val cursor = ctx.newCursor(stack)
for (i <- 0 until frame) {
ctx.nextFrame(cursor)
}
val kas = ctx.dumpKeepalives(cursor)
ctx.closeCursor(cursor)
ctx.deleteValue(cursor)
kas
}
}
}
\ No newline at end of file
......@@ -33,8 +33,8 @@ class FutexManager {
val loc = objRef + offset
val autoWakeup = maybeTimeout.map { timeout =>
val now = System.currentTimeMillis()
timeout + now * 1000000L
val now = System.nanoTime()
timeout + now
}
val wr = WaitRecord(objRef, offset, loc, thread, autoWakeup)
......@@ -110,7 +110,7 @@ class FutexManager {
/** Wake up all threads with their timeout expired. */
def futexWakeTimeout(): Unit = {
val now = System.currentTimeMillis() * 1000000L
val now = System.nanoTime()
for (wr <- timeoutSet.takeWhile(_.autoWakeup.get <= now)) {
wakeThread(wr, -3)
......@@ -118,7 +118,7 @@ class FutexManager {
}
}
/** Return the time the next thread wakes up (in the unit of currentTimeMillis * 1000000L) */
/** Return the time the next thread wakes up (in the unit of nanoTime) */
def nextWakeup(): Option[Long] = {
if (!timeoutSet.isEmpty) {
Some(timeoutSet.firstKey.autoWakeup.get)
......
......@@ -275,7 +275,7 @@ trait InstructionExecutor extends InterpreterActions with CommInstExecutor {
case i @ InstThrow(excVal) => {
val exc = excVal.asRef
curStack.popFrame()
curStack.popMuFrameForThrow()
catchException(exc)
}
......
......@@ -24,7 +24,7 @@ trait HasID {
/**
* Keep HasID objects and allow looking them up by their IDs.
*
*
* @param kind A name that indicates what kind of object it holds. For debugging.
*/
class IDObjectKeeper[T <: HasID](val kind: String) {
......@@ -43,10 +43,10 @@ class IDObjectKeeper[T <: HasID](val kind: String) {
throw new UvmRuntimeException("%s of ID %s already exists.".format(kind, obj.id))
}
}
/** Iterate through all objects. */
def values: Iterable[T] = registry.values
/** Remove an object from the registry. */
def remove(obj: T): Unit = {
val old = registry.remove(obj.id)
......@@ -54,7 +54,7 @@ class IDObjectKeeper[T <: HasID](val kind: String) {
throw new UvmRuntimeException("The %s removed is not the same object as the argument. ID: %d".format(kind, obj.id))
}
}
/** Create an ID for a new object of this type. */
def getID() = idFactory.getID()
}
......@@ -72,6 +72,7 @@ class ThreadStackManager(implicit microVM: MicroVM, nativeCallHelper: NativeCall
val stackRegistry = new IDObjectKeeper[InterpreterStack]("stack")
val threadRegistry = new IDObjectKeeper[InterpreterThread]("thread")
val frameCursorRegistry = new IDObjectKeeper[FrameCursor]("framecursor")
def iterateAllLiveStacks: Iterable[InterpreterStack] = stackRegistry.values.filter(_.state != FrameState.Dead)
def iterateAllLiveThreads: Iterable[InterpreterThread] = threadRegistry.values.filter(_.isRunning)
......@@ -110,6 +111,45 @@ class ThreadStackManager(implicit microVM: MicroVM, nativeCallHelper: NativeCall
thr
}
//// Frame cursors related operations
private def createAndAddFrameCursor(id: Int, stack: InterpreterStack, frame: InterpreterFrame): FrameCursor = {
val fc = new FrameCursor(id, stack, frame)
frameCursorRegistry.put(fc)
stack.frameCursors.add(fc)
fc
}
/**
* Create a new frame cursor for a stack.
*/
def newFrameCursor(stack: InterpreterStack): FrameCursor = {
val id = frameCursorRegistry.getID()
val frame = stack.top
createAndAddFrameCursor(id, stack, frame)
}
/**
* Copy a frame cursor.
*/
def copyCursor(cursor: FrameCursor): FrameCursor = {
val id = frameCursorRegistry.getID()
val stack = cursor.stack
val frame = cursor.frame
createAndAddFrameCursor(id, stack, frame)
}
/**
* Copy a frame cursor.
*/
def closeCursor(cursor: FrameCursor): Unit = {
cursor.stack.frameCursors.remove(cursor)
frameCursorRegistry.remove(cursor)
}
//// Execution
/**
* Execute one instruction in each currently executable thread.
*/
......@@ -138,7 +178,7 @@ class ThreadStackManager(implicit microVM: MicroVM, nativeCallHelper: NativeCall
if (someWaiting) {
futexManager.nextWakeup match {
case Some(nextWakeup) => {
val now = System.currentTimeMillis() * 1000000L
val now = System.nanoTime()
val sleep = nextWakeup - now
val sleepMillis = sleep / 1000000L
val sleepNanos = sleep % 1000000L
......
......@@ -13,6 +13,7 @@ import uvm.refimpl.nat.NativeCallResult
import uvm.refimpl.nat.NativeCallHelper
import org.slf4j.LoggerFactory
import com.typesafe.scalalogging.Logger
import scala.collection.mutable.HashSet
/** The state of a frame. */
abstract class FrameState
......@@ -38,6 +39,16 @@ class InterpreterStack(val id: Int, val stackMemory: StackMemory, stackBottomFun
def top = _top
private def top_=(f: InterpreterFrame) = _top = f
/** A list of frame cursors on this stack for sanity check. */
var frameCursors = new HashSet[FrameCursor]()
private def ensureNoCursors(action: String): Unit = {
if (!frameCursors.isEmpty) {
throw new UvmRuntimeException("Attempt to %s when there are frame cursors not closed. Stack: %d, Cursors: %s".format(
action, id, frameCursors.map(_.id).mkString(" ")))
}
}
/** The state of the stack (i.e. state of the top frame) */
def state = top.state
......@@ -232,6 +243,9 @@ class InterpreterStack(val id: Int, val stackMemory: StackMemory, stackBottomFun
if (!state.isInstanceOf[FrameState.Ready]) {
throw new UvmRuntimeException("Attempt to bind to a stack not in the ready state. Actual state: %s".format(state))
}
ensureNoCursors("bind to a stack")
top match {
case mf: MuFrame => {
mf.resumeNormally(args)
......@@ -250,6 +264,8 @@ class InterpreterStack(val id: Int, val stackMemory: StackMemory, stackBottomFun
/** Kill the stack */
def kill(): Unit = {
ensureNoCursors("kill a stack")
for (f <- frames) {
f.state = FrameState.Dead
}
......@@ -259,27 +275,49 @@ class InterpreterStack(val id: Int, val stackMemory: StackMemory, stackBottomFun
}
/**
* Return the n-th frame of the current stack.
* Ensure there is no native frame from the top frame until the frame cursor (exclusive), or any frames until the
* cursor happen to be referred by other frame cursors.
*/
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))
}
}
private def ensurePoppableUntil(cursor: FrameCursor): Unit = {
val toFrame = cursor.frame
for ((curFrame, i) <- frames.takeWhile(_ != toFrame).zipWithIndex) {
if (curFrame.isInstanceOf[NativeFrame]) {
throw new UnimplementedOprationException(
"Popping native frames is not supported. Found native frame at depth %d in stack %d".format(i, id))
}
/** Pop a frame. Part of the API. Also used by THROW */
def popFrame(): Unit = {
top match {
case f: NativeFrame => throw new UnimplementedOprationException("Popping native frames is not supported.")
case f: MuFrame => f.prev match {
case None => throw new UvmRuntimeException("Attempting to pop the last frame of a stack.")
case Some(prev) => popMuFrame()
for (c2 <- frameCursors if c2 != cursor) {
if (c2.frame == curFrame) {
throw new UnimplementedOprationException(
"Frame %s at depth %d in stack %d is referred by another frame cursor %d. Current cursor: %d".format(
c2.frame.toString, i, id, c2.id, cursor.id))
}
}
}
}
/** Pop the current Mu frame. Used by THROW. */
def popMuFrameForThrow(): Unit = {
popMuFrame()
}
/** Pop all frames until cursor. Part of the API. */
def popFramesTo(cursor: FrameCursor): Unit = {
if (cursor.stack != this) {
throw new UvmRefImplException(
"Frame cursor %d refers to frame %s in a different stack %d. Current stack: %d".format(
cursor.frame.toString, cursor.stack.id, this.id))
}
ensurePoppableUntil(cursor)
val toFrame = cursor.frame
for (f <- frames.takeWhile(_ != toFrame) if f.isInstanceOf[DefinedMuFrame]) {
stackMemory.rewind(f.asInstanceOf[DefinedMuFrame].savedStackPointer)
}
top = cursor.frame
}
/** Push a Mu frame. Part of the API. */
......@@ -331,7 +369,7 @@ class NativeFrame(val func: Word, prev: Option[InterpreterFrame]) extends Interp
override def curFuncID: Int = 0
override def curFuncVerID: Int = 0
override def curInstID: Int = 0
override def toString(): String = "NativeFrame(func=0x%x)".format(func)
}
......@@ -382,7 +420,7 @@ 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
......@@ -480,7 +518,7 @@ class DefinedMuFrame(val savedStackPointer: Word, val funcVer: FuncVer, val cook
edgeAssignedBoxes.put(lv.asInstanceOf[Parameter], ValueBox.makeBoxForType(ty))
}
}
override def curFuncID: Int = func.id
override def curFuncVerID: Int = funcVer.id
override def curInstID: Int = if (justCreated) 0 else curInst.id
......@@ -563,14 +601,11 @@ class DefinedMuFrame(val savedStackPointer: Word, val funcVer: FuncVer, val cook
/**
* A mutable cursor that iterates through stack frames.
*/
class FrameCursor(val id: Int, val stack: InterpreterStack, val frame: InterpreterFrame) extends HasID {
/** The current frame it refers to. */
var curFrame = frame
class FrameCursor(val id: Int, val stack: InterpreterStack, var frame: InterpreterFrame) extends HasID {
def nextFrame(): Unit = {
curFrame = curFrame.prev.getOrElse {
frame = frame.prev.getOrElse {
throw new UvmRuntimeException("Attempt to go below the stack-bottom frame. Stack id: %d, Frame: %s".format(
stack.id, curFrame.toString))
stack.id, frame.toString))
}
}
}
......@@ -5,6 +5,7 @@ import uvm.refimpl.TrapHandlerResult.Rebind
import uvm.refimpl.HowToResume.PassValues
object FactorialFromRPython extends App {
import uvm.refimpl.RichMuCtx._
val microVM = new MicroVM()
val ctx = microVM.newContext()
......@@ -17,11 +18,12 @@ object FactorialFromRPython extends App {
microVM.setTrapHandler(new TrapHandler {
override def handleTrap(ctx: MuCtx, thread: MuThreadRefValue, stack: MuStackRefValue, watchPointID: Int): TrapHandlerResult = {
val curInst = ctx.curInst(stack, 0)
val fc = ctx.newCursor(stack)
val curInst = ctx.curInst(fc)
val trapName = microVM.nameOf(curInst)
if (trapName == "@main_v1.entry.main_trap") {
val kas = ctx.dumpKeepalives(stack, 0)
val kas = ctx.dumpKeepalives(fc)
val Seq(rv) = kas
val i = ctx.handleToSInt(rv.asInstanceOf[MuIntValue])
......@@ -31,7 +33,9 @@ object FactorialFromRPython extends App {
throw new RuntimeException("Hit the wrong trap: " + trapName)
}
ctx.closeCursor(fc)
Rebind(stack, PassValues(Seq())) // continue
}
})
......
......@@ -34,19 +34,27 @@ class UvmOSRTests extends UvmBundleTesterBase {
val arg0 = ctx.handleFromInt64(3)
testFunc(ctx, func, Seq(arg0)) { (ctx, th, st, wp) =>
nameOf(ctx.curInst(st, 0)) match {
val fc = ctx.newCursor(st)
nameOf(ctx.curInst(fc)) match {
case "@intro_rec_v1.zero.trap_rec" => {
val Seq(n0) = ctx.dumpKeepalives(st, 0)
ctx.handleToUInt(n0.asInstanceOf[MuIntValue]) shouldBe 0
val Seq(n0: MuIntValue) = ctx.dumpKeepalives(fc)
ctx.handleToUInt(n0) shouldBe 0
for (i <- 1 to 3) {
nameOf(ctx.curInst(st, i)) shouldBe "@intro_rec_v1.nz.call"
val Seq(ni, nm1i) = ctx.dumpKeepalives(st, i)
ctx.handleToUInt(ni.asInstanceOf[MuIntValue]) shouldBe i
ctx.handleToUInt(nm1i.asInstanceOf[MuIntValue]) shouldBe (i - 1)
ctx.nextFrame(fc)
nameOf(ctx.curFunc(fc)) shouldBe "@intro_rec"
nameOf(ctx.curFuncVer(fc)) shouldBe "@intro_rec_v1"
nameOf(ctx.curInst(fc)) shouldBe "@intro_rec_v1.nz.call"
val Seq(ni: MuIntValue, nm1i: MuIntValue) = ctx.dumpKeepalives(st, i)
ctx.handleToUInt(ni) shouldBe i
ctx.handleToUInt(nm1i) shouldBe (i - 1)
}
nameOf(ctx.curInst(st, 4)) shouldBe "@intro_test_base_v1.entry.call"
ctx.nextFrame(fc)
nameOf(ctx.curInst(fc)) shouldBe "@intro_test_base_v1.entry.call"
ctx.closeCursor(fc)
Rebind(st, PassValues(Seq(n0)))
}
......@@ -64,10 +72,13 @@ class UvmOSRTests extends UvmBundleTesterBase {
val arg0 = ctx.handleFromInt64(4)
testFunc(ctx, func, Seq(arg0)) { (ctx, th, st, wp) =>
nameOf(ctx.curInst(st, 0)) match {
val fc = ctx.newCursor(st)
nameOf(ctx.curInst(fc)) match {
case "@osr_test_base_v1.entry.trap_base_exit" => {
val Seq(rv) = ctx.dumpKeepalives(st, 0)
ctx.handleToUInt(rv.asInstanceOf[MuIntValue]) shouldBe 6
val Seq(rv: MuIntValue) = ctx.dumpKeepalives(fc)
ctx.closeCursor(fc)
ctx.handleToUInt(rv) shouldBe 6
returnFromTrap(st)
}
......@@ -85,13 +96,15 @@ class UvmOSRTests extends UvmBundleTesterBase {
val arg0 = ctx.handleFromInt64(8)