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

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

Trap handler and tests.

In theory, all Mu client API functions are available to C, but not all
are tested.  Now a client in C is known to be able to create stack,
thread, handle traps and introspect stacks.
parent 22a4132f
...@@ -120,6 +120,9 @@ struct MuVM { ...@@ -120,6 +120,9 @@ struct MuVM {
// Set handlers // Set handlers
void (*set_trap_handler )(MuVM *mvm, MuTrapHandler trap_handler, MuCPtr userdata); void (*set_trap_handler )(MuVM *mvm, MuTrapHandler trap_handler, MuCPtr userdata);
// Proprietary API: let the micro VM execute
void (*execute)(MuVM *mvm);
}; };
// A local context. It can only be used by one thread at a time. It holds many // A local context. It can only be used by one thread at a time. It holds many
...@@ -221,7 +224,7 @@ struct MuCtx { ...@@ -221,7 +224,7 @@ struct MuCtx {
// Thread and stack creation and stack destruction // Thread and stack creation and stack destruction
MuStackRefValue (*new_stack )(MuCtx *ctx, MuFuncRefValue func); MuStackRefValue (*new_stack )(MuCtx *ctx, MuFuncRefValue func);
MuThreadRefValue (*new_thread)(MuCtx *ctx, MuStackRefValue stack, MuThreadRefValue (*new_thread)(MuCtx *ctx, MuStackRefValue stack,
MuHowToResume *htr, MuValue *vals, int nvals, MuRefValue exc); MuHowToResume htr, MuValue *vals, int nvals, MuRefValue exc);
void (*kill_stack)(MuCtx *ctx, MuStackRefValue stack); void (*kill_stack)(MuCtx *ctx, MuStackRefValue stack);
// Frame cursor operations // Frame cursor operations
......
...@@ -17,14 +17,14 @@ class TrapManager(implicit microVM: MicroVM) { ...@@ -17,14 +17,14 @@ class TrapManager(implicit microVM: MicroVM) {
object DefaultTrapHandler extends TrapHandler { object DefaultTrapHandler extends TrapHandler {
def handleTrap(ctx: MuCtx, thread: MuThreadRefValue, stack: MuStackRefValue, watchPointID: Int): TrapHandlerResult = { def handleTrap(ctx: MuCtx, thread: MuThreadRefValue, stack: MuStackRefValue, watchPointID: Int): TrapHandlerResult = {
val thrID = thread.vb.asInstanceOf[BoxThread].thread.get.id val thrID = thread.vb.asInstanceOf[BoxThread].thread.get.id
// val curFuncID = ctx. val staID = stack.vb.asInstanceOf[BoxStack].stack.get.id
// val funcVerID = ca.currentFuncVer(stack, 0) val cursor = ctx.newCursor(stack)
// val funcVer = microVM.globalBundle.funcVerNs(funcVerID) val curFuncID = ctx.curFunc(cursor)
// val instID = ca.currentInstruction(stack, 0) val curFuncVerID = ctx.curFuncVer(cursor)
// val inst = microVM.globalBundle.varNs(instID) val curInstID = ctx.curInst(cursor)
// throw new UvmRuntimeException("Unhandled trap. Thread %d, funcver %s, trap inst %s, watch point ID %d".format( ctx.closeCursor(cursor)
// thr.id, funcVer.repr, inst.repr, watchPointID)) throw new UvmRuntimeException("Unhandled trap. thread %d, stack: %d, func: %d, funcver: %d, inst %d, watch point ID %d".format(
??? thrID, staID, curFuncID, curFuncVerID, curInstID, watchPointID))
} }
} }
......
...@@ -22,13 +22,129 @@ import uvm.ssavariables.MemoryOrder ...@@ -22,13 +22,129 @@ import uvm.ssavariables.MemoryOrder
import uvm.ssavariables.AtomicRMWOptr import uvm.ssavariables.AtomicRMWOptr
import uvm.ssavariables.Flag import uvm.ssavariables.Flag
import uvm.ssavariables.Flag import uvm.ssavariables.Flag
import com.kenai.jffi.Invoker
import com.kenai.jffi.CallContext
import com.kenai.jffi.HeapInvocationBuffer
import NativeClientSupport._
object NativeTrapHandler {
val jffiInvoker = Invoker.getInstance
val trapHandlerCallContext = new CallContext(
JType.VOID, // return value
// input params
JType.POINTER, //MuCtx *ctx,
JType.POINTER, //MuThreadRefValue thread,
JType.POINTER, //MuStackRefValue stack,
JType.SINT32, //int wpid,
// output params
JType.POINTER, //MuTrapHandlerResult *result,
JType.POINTER, //MuStackRefValue *new_stack,
JType.POINTER, //MuValue **values,
JType.POINTER, //int *nvalues,
JType.POINTER, //MuValuesFreer *freer,
JType.POINTER, //MuCPtr *freerdata,
JType.POINTER, //MuRefValue *exception,
// user data
JType.POINTER //MuCPtr userdata
);
val freerCallContext = new CallContext(
JType.VOID, // return value
// input params
JType.POINTER, // MuValue *values,
JType.POINTER //MuCPtr freerdata
)
def callFreer(freerFP: MuValuesFreerFP, valuesPtr: MuValueFakArrayPtr, freerData: MuCPtr): Unit = {
val freerFunc = new com.kenai.jffi.Function(freerFP, freerCallContext)
logger.debug("Calling freer: 0x%x with args (0x%x, 0x%x)".format(freerFP, valuesPtr, freerData))
jffiInvoker.invokeLLrL(freerFunc, valuesPtr, freerData)
logger.debug("Returned from freer")
}
}
/** /**
* This object calls a C function to handle the trap. * This object calls a C function to handle the trap.
*/ */
class NativeTrapHandler(val funcAddr: Long, val userdata: Long) extends TrapHandler { class NativeTrapHandler(val funcAddr: MuTrapHandlerFP, val userdata: MuCPtr) extends TrapHandler {
import NativeTrapHandler._
import NativeMuHelpers._
val jffiFunction = new com.kenai.jffi.Function(funcAddr, trapHandlerCallContext)
def handleTrap(ctx: MuCtx, thread: MuThreadRefValue, stack: MuStackRefValue, watchPointID: Int): TrapHandlerResult = { def handleTrap(ctx: MuCtx, thread: MuThreadRefValue, stack: MuStackRefValue, watchPointID: Int): TrapHandlerResult = {
??? logger.debug("Trapped. Prepare to call native trap handler: %d 0x%x".format(funcAddr, funcAddr))
val hib = new HeapInvocationBuffer(jffiFunction)
// input args
val ctxFak = exposeMuCtx(ctx) // It is a fresh context.
hib.putAddress(ctxFak)
val threadFak = exposeMuValue(ctx, thread) // It is a fresh handle, too.
hib.putAddress(threadFak)
val stackFak = exposeMuValue(ctx, stack) // It is a fresh handle, too.
hib.putAddress(stackFak)
hib.putInt(watchPointID)
// output args
val nOutArgs = 7
val outBuf = jnrMemoryManager.allocateDirect((7L * WORD_SIZE_BYTES).toInt, true) // output values are received here.
val outBufAddr = outBuf.address()
for (i <- 0 until nOutArgs) {
val outAddr = outBufAddr + i * WORD_SIZE_BYTES
logger.debug("The %d-th out arg: 0x%x".format(i, outAddr))
hib.putAddress(outAddr)
}
// user data
hib.putAddress(userdata)
// Call
logger.debug("Calling native trap handler: 0x%x".format(funcAddr))
jffiInvoker.invokeLong(jffiFunction, hib)
logger.debug("Returned from native trap handler: 0x%x".format(funcAddr))
// Inspect return value
val result = outBuf.getInt(0L)
val scalaResult: TrapHandlerResult = result match {
case MU_THREAD_EXIT => TrapHandlerResult.ThreadExit()
case MU_REBIND_PASS_VALUES => {
val nsFak = outBuf.getAddress(1 * WORD_SIZE_BYTES)
val newStack = getMuValueNotNull(nsFak).asInstanceOf[MuStackRefValue]
val valuesPtr = outBuf.getAddress(2 * WORD_SIZE_BYTES)
val nValues = outBuf.getInt(3 * WORD_SIZE_BYTES)
val valueFaks = for (i <- 0 until nValues) yield {
theMemory.getAddress(valuesPtr + i * WORD_SIZE_BYTES)
}
val freerFP = outBuf.getAddress(4 * WORD_SIZE_BYTES)
if (freerFP != 0L) {
val freerData = outBuf.getAddress(5 * WORD_SIZE_BYTES)
callFreer(freerFP, valuesPtr, freerData)
}
val values = valueFaks.map(getMuValueNotNull)
TrapHandlerResult.Rebind(newStack, HowToResume.PassValues(values))
}
case MU_REBIND_THROW_EXC => {
val nsFak = outBuf.getAddress(1 * WORD_SIZE_BYTES)
val newStack = getMuValueNotNull(nsFak).asInstanceOf[MuStackRefValue]
val excFak = outBuf.getAddress(6 * WORD_SIZE_BYTES)
val excVal = getMuValueNotNull(excFak).asInstanceOf[MuRefValue]
TrapHandlerResult.Rebind(newStack, HowToResume.ThrowExc(excVal))
}
}
unexposeMuCtx(ctxFak) // Mu will close the context, but not un-expose it.
scalaResult
} }
} }
...@@ -37,7 +153,6 @@ class NativeTrapHandler(val funcAddr: Long, val userdata: Long) extends TrapHand ...@@ -37,7 +153,6 @@ class NativeTrapHandler(val funcAddr: Long, val userdata: Long) extends TrapHand
*/ */
object NativeMuVM { object NativeMuVM {
import NativeMuHelpers._ import NativeMuHelpers._
import NativeClientSupport._
def new_context(microVM: MicroVM): MuCtxFak = { def new_context(microVM: MicroVM): MuCtxFak = {
val ctx = microVM.newContext() val ctx = microVM.newContext()
...@@ -49,6 +164,7 @@ object NativeMuVM { ...@@ -49,6 +164,7 @@ object NativeMuVM {
def set_trap_handler(microVM: MicroVM, trap_handler: MuTrapHandlerFP, userdata: MuCPtr): Unit = { def set_trap_handler(microVM: MicroVM, trap_handler: MuTrapHandlerFP, userdata: MuCPtr): Unit = {
microVM.setTrapHandler(new NativeTrapHandler(trap_handler, userdata)) microVM.setTrapHandler(new NativeTrapHandler(trap_handler, userdata))
} }
def execute(microVM: MicroVM): Unit = microVM.execute()
} }
/** /**
...@@ -59,7 +175,6 @@ object NativeMuVM { ...@@ -59,7 +175,6 @@ object NativeMuVM {
*/ */
object NativeMuCtx { object NativeMuCtx {
import NativeMuHelpers._ import NativeMuHelpers._
import NativeClientSupport._
def id_of(ctx: MuCtx, name: MuName): MuID = ctx.idOf(name) def id_of(ctx: MuCtx, name: MuName): MuID = ctx.idOf(name)
def name_of(ctx: MuCtx, id: MuID): MuName = ctx.nameOf(id) def name_of(ctx: MuCtx, id: MuID): MuName = ctx.nameOf(id)
...@@ -157,7 +272,10 @@ object NativeMuCtx { ...@@ -157,7 +272,10 @@ object NativeMuCtx {
def fence(ctx: MuCtx, ord: MuMemOrd): Unit = ctx.fence(ord) def fence(ctx: MuCtx, ord: MuMemOrd): Unit = ctx.fence(ord)
def new_stack(ctx: MuCtx, func: MuFuncRefValue): MuValueFak = exposeMuValue(ctx, ctx.newStack(func)) def new_stack(ctx: MuCtx, func: MuFuncRefValue): MuValueFak = exposeMuValue(ctx, ctx.newStack(func))
def new_thread(ctx: MuCtx, stack: MuStackRefValue, htr: MuHowToResume, vals: MuValueFakArrayPtr, nvals: Int, exc: MuRefValue): MuValueFak = {
// NOTE: parameter exc must not be a MuValue because this parameter is ignored when htr is MU_REBIND_PASS_VALUE.
// Setting the type to MuValue (or MuRefValue) will force the exposer to eagerly resolve the underlying actual MuValue.
def new_thread(ctx: MuCtx, stack: MuStackRefValue, htr: MuHowToResume, vals: MuValueFakArrayPtr, nvals: Int, exc: MuValueFak): MuValueFak = {
val scalaHtr = htr match { val scalaHtr = htr match {
case MU_REBIND_PASS_VALUES => { case MU_REBIND_PASS_VALUES => {
val values = for (i <- 0L until nvals) yield { val values = for (i <- 0L until nvals) yield {
...@@ -169,7 +287,8 @@ object NativeMuCtx { ...@@ -169,7 +287,8 @@ object NativeMuCtx {
HowToResume.PassValues(values) HowToResume.PassValues(values)
} }
case MU_REBIND_THROW_EXC => { case MU_REBIND_THROW_EXC => {
HowToResume.ThrowExc(exc) val excVal = getMuValueNotNull(exc).asInstanceOf[MuRefValue]
HowToResume.ThrowExc(excVal)
} }
} }
val rv = ctx.newThread(stack, scalaHtr) val rv = ctx.newThread(stack, scalaHtr)
...@@ -211,10 +330,10 @@ object NativeMuCtx { ...@@ -211,10 +330,10 @@ object NativeMuCtx {
def enable_watchpoint(ctx: MuCtx, wpid: Int): Unit = ctx.enableWatchpoint(wpid) def enable_watchpoint(ctx: MuCtx, wpid: Int): Unit = ctx.enableWatchpoint(wpid)
def disable_watchpoint(ctx: MuCtx, wpid: Int): Unit = ctx.disableWatchpoint(wpid) def disable_watchpoint(ctx: MuCtx, wpid: Int): Unit = ctx.disableWatchpoint(wpid)
def pin(ctx: MuCtx, loc: MuValue): MuValueFak = exposeMuValue(ctx, ctx.pin(loc)) def pin(ctx: MuCtx, loc: MuValue): MuValueFak = exposeMuValue(ctx, ctx.pin(loc))
def unpin(ctx: MuCtx, loc: MuValue): Unit = ctx.unpin(loc) def unpin(ctx: MuCtx, loc: MuValue): Unit = ctx.unpin(loc)
def expose(ctx: MuCtx, func: MuFuncRefValue, call_conv: MuCallConv, cookie: MuIntValue): MuValueFak = exposeMuValue(ctx, ctx.expose(func, call_conv, cookie)) def expose(ctx: MuCtx, func: MuFuncRefValue, call_conv: MuCallConv, cookie: MuIntValue): MuValueFak = exposeMuValue(ctx, ctx.expose(func, call_conv, cookie))
def unexpose(ctx: MuCtx, call_conv: MuCallConv, value: MuUFPValue): Unit = ctx.unexpose(call_conv, value) def unexpose(ctx: MuCtx, call_conv: MuCallConv, value: MuUFPValue): Unit = ctx.unexpose(call_conv, value)
} }
...@@ -223,7 +342,6 @@ object NativeMuCtx { ...@@ -223,7 +342,6 @@ object NativeMuCtx {
* These functions are not exposed. * These functions are not exposed.
*/ */
object NativeMuHelpers { object NativeMuHelpers {
import NativeClientSupport._
private val ONE = BigInt(1) private val ONE = BigInt(1)
...@@ -264,7 +382,7 @@ object NativeMuHelpers { ...@@ -264,7 +382,7 @@ object NativeMuHelpers {
val MU_MIN = 0x08 val MU_MIN = 0x08
val MU_UMAX = 0x09 val MU_UMAX = 0x09
val MU_UMIN = 0x0A val MU_UMIN = 0x0A
val MU_DEFAULT = 0x00 val MU_DEFAULT = 0x00
implicit def intToMemOrd(ord: MuMemOrd): MemoryOrder.MemoryOrder = ord match { implicit def intToMemOrd(ord: MuMemOrd): MemoryOrder.MemoryOrder = ord match {
...@@ -290,14 +408,13 @@ object NativeMuHelpers { ...@@ -290,14 +408,13 @@ object NativeMuHelpers {
case MU_UMAX => AtomicRMWOptr.UMAX case MU_UMAX => AtomicRMWOptr.UMAX
case MU_UMIN => AtomicRMWOptr.UMIN case MU_UMIN => AtomicRMWOptr.UMIN
} }
implicit def intToCallConv(cc: MuCallConv): Flag = cc match { implicit def intToCallConv(cc: MuCallConv): Flag = cc match {
case MU_DEFAULT => Flag("#DEFAULT") case MU_DEFAULT => Flag("#DEFAULT")
} }
} }
object ClientAccessibleClassExposer { object ClientAccessibleClassExposer {
import NativeClientSupport._
val MAX_NAME_SIZE = 65536 val MAX_NAME_SIZE = 65536
...@@ -405,8 +522,6 @@ object ClientAccessibleClassExposer { ...@@ -405,8 +522,6 @@ object ClientAccessibleClassExposer {
*/ */
class ClientAccessibleClassExposer[T: ru.TypeTag: ClassTag](obj: T) { class ClientAccessibleClassExposer[T: ru.TypeTag: ClassTag](obj: T) {
import ClientAccessibleClassExposer._ import ClientAccessibleClassExposer._
import NativeSupport._
import NativeClientSupport._
/** /**
* A list of JFFI closure handles, one for each declared method in obj, in the declared order. * A list of JFFI closure handles, one for each declared method in obj, in the declared order.
...@@ -516,6 +631,7 @@ object NativeClientSupport { ...@@ -516,6 +631,7 @@ object NativeClientSupport {
type CharArrayPtr = Word type CharArrayPtr = Word
type MuValueFakPtr = Word type MuValueFakPtr = Word
type MuValueFakArrayPtr = Word type MuValueFakArrayPtr = Word
type MuValuesFreerFP = Word
// Mu API C-level types. // Mu API C-level types.
type MuID = Int type MuID = Int
......
...@@ -27,6 +27,7 @@ class NativeClientSupportTest extends UvmBundleTesterBase { ...@@ -27,6 +27,7 @@ class NativeClientSupportTest extends UvmBundleTesterBase {
def test_with_ctx(mvm: Word, theID: Int, theName: String): CBool def test_with_ctx(mvm: Word, theID: Int, theName: String): CBool
def test_basic_conv(mvm: Word): CBool def test_basic_conv(mvm: Word): CBool
def test_global_vars(mvm: Word, the_plus_one_fp: Word): CBool def test_global_vars(mvm: Word, the_plus_one_fp: Word): CBool
def test_traps(mvm: Word): CBool
} }
val ncs_tests = LibraryLoader.create(classOf[NcsTestsLib]).load(fileName) val ncs_tests = LibraryLoader.create(classOf[NcsTestsLib]).load(fileName)
...@@ -77,4 +78,9 @@ class NativeClientSupportTest extends UvmBundleTesterBase { ...@@ -77,4 +78,9 @@ class NativeClientSupportTest extends UvmBundleTesterBase {
val result = ncs_tests.test_global_vars(microVMFuncTableAddr, thePlusOneFP) val result = ncs_tests.test_global_vars(microVMFuncTableAddr, thePlusOneFP)
assertNativeSuccess(result) assertNativeSuccess(result)
} }
it should "support traps" in {
val result = ncs_tests.test_traps(microVMFuncTableAddr)
assertNativeSuccess(result)
}
} }
\ No newline at end of file
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <stdint.h> #include <stdint.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h>
#include <muapi.h> #include <muapi.h>
...@@ -11,7 +12,13 @@ ...@@ -11,7 +12,13 @@
return false; \ return false; \
} }
#define MU_ASSERT_EQUALS_TRAP(a, b, f) if (!(a == b)) { \
muprintf("%s (%" f ") is not equal to %s (%" f ")\n", #a, a, #b, b); \
exit(1); \
}
#define ID(name) ctx->id_of(ctx, name) #define ID(name) ctx->id_of(ctx, name)
#define NAME(id) ctx->name_of(ctx, id)
#define muprintf(fmt, ...) printf("[C:%d:%s] " fmt, __LINE__, __func__, ## __VA_ARGS__) #define muprintf(fmt, ...) printf("[C:%d:%s] " fmt, __LINE__, __func__, ## __VA_ARGS__)
...@@ -208,3 +215,127 @@ bool test_global_vars(MuVM *mvm, int64_t(*the_plus_one_fp)(int64_t)) { ...@@ -208,3 +215,127 @@ bool test_global_vars(MuVM *mvm, int64_t(*the_plus_one_fp)(int64_t)) {
return true; return true;
} }
struct simple_context {
int magic;
};
void malloc_freer(MuValue *values, MuCPtr freerdata) {
free(values);
}
void nop_freer(MuValue *values, MuCPtr freerdata) {
}
void simple_trap_handler(MuCtx *ctx, MuThreadRefValue thread,
MuStackRefValue stack, int wpid, MuTrapHandlerResult *result,
MuStackRefValue *new_stack, MuValue **values, int *nvalues,
MuValuesFreer *freer, MuCPtr *freerdata, MuRefValue *exception,
MuCPtr userdata) {
muprintf("Hi! I am the native trap handler!\n");
struct simple_context *userctx = (struct simple_context*)userdata;
int magic = userctx->magic;
muprintf("My magic is %d\n", magic);
MU_ASSERT_EQUALS_TRAP(magic, 42, "d");
muprintf("I am going to introspect the stack.\n");
MuFCRefValue *cursor = ctx->new_cursor(ctx, stack);
MuID fid = ctx->cur_func(ctx, cursor);
muprintf("Function: %d: %s\n", fid, NAME(fid));
MuID fvid = ctx->cur_func_ver(ctx, cursor);
muprintf("Version: %d: %s\n", fvid, NAME(fvid));
MuID iid = ctx->cur_inst(ctx, cursor);
muprintf("Instruction: %d: %s\n", iid, NAME(iid));
MuID trap1_id = ID("@trapper.v1.entry.trap1");
MuID trap2_id = ID("@trapper.v1.entry.trap2");
MU_ASSERT_EQUALS_TRAP(fid , ID("@trapper"), "d");
MU_ASSERT_EQUALS_TRAP(fvid, ID("@trapper.v1"), "d");
muprintf("Selecting branch according to the instruction ID: %d\n", iid);
if (iid == trap1_id) {
muprintf("It is %%trap1\n");
MuValue kas[1];
muprintf("Dumping keep-alives...\n");
ctx->dump_keepalives(ctx, cursor, kas);
muprintf("Dumped\n");
ctx->close_cursor(ctx, cursor);
int64_t oldKa = ctx->handle_to_sint64(ctx, kas[0]);
muprintf("The keep-alive variable is %" PRId64 "\n", oldKa);
MU_ASSERT_EQUALS_TRAP(oldKa, 42LL, PRId64);
int64_t newKa = oldKa + 1;
muprintf("Prepare to return\n");
muprintf("Writing result at %p\n", result);
*result = MU_REBIND_PASS_VALUES;
muprintf("Writing new_stack at %p\n", new_stack);
*new_stack = stack;
muprintf("Allocating values array, writing at %p\n", values);
*values = (MuValue*)malloc(8);
muprintf("Setting the only value. Addr: %p\n", &(*values)[0]);
(*values)[0] = ctx->handle_from_sint64(ctx, newKa, 64);
muprintf("Writing nvalues at %p\n", nvalues);
*nvalues = 1;
muprintf("Writing freer at %p\n", freer);
*freer = malloc_freer;
muprintf("Writing freerdata at %p\n", freerdata);
*freerdata = NULL;
muprintf("Bye!\n");
return;
} else if (iid == trap2_id) {
muprintf("It is %%trap2\n");
MuValue kas[1];
ctx->dump_keepalives(ctx, cursor, kas);
ctx->close_cursor(ctx, cursor);
muprintf("Introspect the KAs...\n");
int64_t v1 = ctx->handle_to_sint64(ctx, kas[0]);
muprintf("KA value %%v1 is %" PRId64 "\n", v1);
MU_ASSERT_EQUALS_TRAP(v1, 43LL, PRId64);
muprintf("Prepare to return from trap handler...\n");
*result = MU_REBIND_PASS_VALUES;
*new_stack = stack;
*values = NULL;
*nvalues = 0;
*freer = NULL;
*freerdata = NULL;
muprintf("Bye!\n");
return;
} else {
muprintf("Unknown trap. ID: %d\n", iid);
MuName trapName = NAME(iid);
muprintf("name: %s\n", trapName);
exit(1);
}
return; // Unreachable, but the C compiler may not be smart enough.
}
bool test_traps(MuVM *mvm) {
struct simple_context userctx = { 42 };
mvm->set_trap_handler(mvm, simple_trap_handler, &userctx);
MuCtx *ctx = mvm->new_context(mvm);
MuValue args[1];
args[0] = ctx->handle_from_sint64(ctx, 42LL, 64);
MuFuncRefValue func = ctx->handle_from_func(ctx, ID("@trapper"));
MuStackRefValue stack = ctx->new_stack(ctx, func);
MuThreadRefValue thread = ctx->new_thread(ctx, stack, MU_REBIND_PASS_VALUES,
args, 1, NULL);
mvm->execute(mvm);
ctx->close_context(ctx);
return true;
}
...@@ -9,3 +9,10 @@ ...@@ -9,3 +9,10 @@
} }
.expose @plus_one_native = @plus_one #DEFAULT @I64_0 .expose @plus_one_native = @plus_one #DEFAULT @I64_0
.funcdef @trapper VERSION %v1 <@i_i> {
%entry(<@i64> %n):
%v1 = [%trap1] TRAP <@i64> KEEPALIVE (%n)
[%trap2] TRAP <> KEEPALIVE (%v1)
COMMINST @uvm.thread_exit
}
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