Commit c6922e2c authored by Kunshan Wang's avatar Kunshan Wang

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)
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 "@sum_v1.opt.trap_opt" => {
val Seq(n, i, s) = ctx.dumpKeepalives(st, 0)
val Seq(n:MuIntValue, i:MuIntValue, s:MuIntValue) = ctx.dumpKeepalives(fc)
ctx.closeCursor(fc)
ctx.handleToUInt(s.asInstanceOf[MuIntValue]) shouldBe 10
ctx.handleToUInt(i.asInstanceOf[MuIntValue]) shouldBe 5
ctx.handleToUInt(n.asInstanceOf[MuIntValue]) shouldBe 8
ctx.handleToUInt(s) shouldBe 10
ctx.handleToUInt(i) shouldBe 5
ctx.handleToUInt(n) shouldBe 8
// Emulate optimising compiling by loading a pre-optimised version.
val r = new FileReader("tests/uvm-refimpl-test/osr-tests-part2.uir")
......@@ -102,7 +115,9 @@ class UvmOSRTests extends UvmBundleTesterBase {
}
// OSR
ctx.popFrame(st)
ctx.nextFrame(fc)
ctx.popFramesTo(fc)
ctx.closeCursor(fc)
val oneShotFunc = ctx.handleFromFunc("@sum_osr_oneshot")
ctx.pushFrame(st, oneShotFunc)
......@@ -111,8 +126,10 @@ class UvmOSRTests extends UvmBundleTesterBase {
Rebind(st, PassValues(Seq(s, i, n)))
}
case "@osr_test_base_v1.entry.trap_base_exit" => {
val Seq(rv) = ctx.dumpKeepalives(st, 0)
ctx.handleToUInt(rv.asInstanceOf[MuIntValue]) shouldBe 28
val Seq(rv: MuIntValue) = ctx.dumpKeepalives(fc)
ctx.closeCursor(fc)
ctx.handleToUInt(rv) shouldBe 28
returnFromTrap(st)
}
......@@ -122,10 +139,13 @@ class UvmOSRTests extends UvmBundleTesterBase {
// The second time when it is called, it should call the second version
// and OSR should be unnecessary.
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 28
val Seq(rv: MuIntValue) = ctx.dumpKeepalives(fc)
ctx.closeCursor(fc)
ctx.handleToUInt(rv) shouldBe 28
returnFromTrap(st)
}
......@@ -158,9 +178,11 @@ class UvmOSRTests extends UvmBundleTesterBase {
val arg0 = ctx.handleFromInt64(8)
testFuncMulti(ctx, Seq(func1, func2), Seq()) { (ctx, th, st, wp) =>
nameOf(ctx.curInst(st, 0)) match {
val fc = ctx.newCursor(st)
nameOf(ctx.curInst(fc)) match {
case "@consecutive_push_main.v1.entry.trap" => {
val Seq(n: MuIntValue) = ctx.dumpKeepalives(st, 0)
val Seq(n: MuIntValue) = ctx.dumpKeepalives(fc)
ctx.closeCursor(fc)
ctx.handleToUInt(n) shouldBe 42
......@@ -184,17 +206,21 @@ class UvmOSRTests extends UvmBundleTesterBase {
var addOneReachCount = 0L
testFuncMulti(ctx, Seq(func1, func3, func3, func3, func2), Seq()) { (ctx, th, st, wp) =>
nameOf(ctx.curInst(st, 0)) match {
val fc = ctx.newCursor(st)
nameOf(ctx.curInst(fc)) match {
case "@add_one.v1.entry.trap" => {
val Seq(n: MuIntValue, n2: MuIntValue) = ctx.dumpKeepalives(st, 0)
val Seq(n: MuIntValue, n2: MuIntValue) = ctx.dumpKeepalives(fc)
ctx.closeCursor(fc)
ctx.handleToSInt(n).toLong shouldBe (42L + addOneReachCount)
ctx.handleToSInt(n2) shouldBe (42L + addOneReachCount + 1L)
addOneReachCount += 1L
returnFromTrap(st)
}
case "@consecutive_push_main.v1.entry.trap" => {
val Seq(n: MuIntValue) = ctx.dumpKeepalives(st, 0)
val Seq(n: MuIntValue) = ctx.dumpKeepalives(fc)
ctx.closeCursor(fc)
ctx.handleToSInt(n).toLong shouldBe 45L
...