Commit 7a574230 authored by Kunshan Wang's avatar Kunshan Wang

Tested tagref64, watchpoint and native interface.

parent eaf3dc1c
......@@ -98,7 +98,7 @@ typedef int MuAtomicRMWOp;
// Calling conventions.
typedef int MuCallConv;
#define MU_DEFUALT 0x00
#define MU_DEFAULT 0x00
// Concrete Mu implementations may define more calling conventions.
// NOTE: MuVM and MuCtx are structures with many function pointers. This
......
......@@ -14,13 +14,13 @@ class NativeClientSupportTest extends UvmBundleTesterBase {
"uvm.refimpl.nat" -> DEBUG)
preloadBundles("tests/uvm-refimpl-test/primitives.uir",
"tests/uvm-refimpl-test/native-client-test.uir")
"tests/uvm-refimpl-test/native-client-test.uir")
val fileName = "./tests/c-snippets/ncs_tests.so"
if (!new java.io.File(fileName).isFile()) {
throw new RuntimeException("Need to compile the ncs_tests.so library. cd into tests/c-snippets and invoke 'make'.")
}
type CBool = Byte
trait NcsTestsLib {
......@@ -33,12 +33,15 @@ class NativeClientSupportTest extends UvmBundleTesterBase {
def test_comp_types(mvm: Word): CBool
def test_memory_ops(mvm: Word): CBool
def test_osr(mvm: Word): CBool
def test_tr64(mvm: Word): CBool
def test_wp(mvm: Word): CBool
def test_native(mvm: Word): CBool
}
val ncs_tests = LibraryLoader.create(classOf[NcsTestsLib]).load(fileName)
val microVMFuncTableAddr = NativeClientSupport.exposeMicroVM(microVM)
def assertNativeSuccess(result: CBool): Unit = {
if (result == 0) {
fail("Failed in the native program.")
......@@ -68,43 +71,59 @@ class NativeClientSupportTest extends UvmBundleTesterBase {
val result = ncs_tests.test_with_ctx(microVMFuncTableAddr, theID, theName)
assertNativeSuccess(result)
}
it should "convert C types to Mu types and back, with the same value" in {
val result = ncs_tests.test_basic_conv(microVMFuncTableAddr)
assertNativeSuccess(result)
}
it should "get values from global variables" in {
val ctx = microVM.newContext()
val hThePlusOneFP = ctx.handleFromExpose(ctx.idOf("@plus_one_native"))
val thePlusOneFP = ctx.handleToFP(hThePlusOneFP)
ctx.closeContext()
val result = ncs_tests.test_global_vars(microVMFuncTableAddr, thePlusOneFP)
assertNativeSuccess(result)
}
it should "support traps" in {
val result = ncs_tests.test_traps(microVMFuncTableAddr)
assertNativeSuccess(result)
}
it should "load bundles and HAIL" in {
val result = ncs_tests.test_load_bundle(microVMFuncTableAddr)
assertNativeSuccess(result)
}
it should "handle composite values" in {
val result = ncs_tests.test_comp_types(microVMFuncTableAddr)
assertNativeSuccess(result)
}
it should "perform memory operations" in {
val result = ncs_tests.test_memory_ops(microVMFuncTableAddr)
assertNativeSuccess(result)
}
it should "perform OSR" in {
val result = ncs_tests.test_osr(microVMFuncTableAddr)
assertNativeSuccess(result)
}
it should "handle tagref64" in {
val result = ncs_tests.test_tr64(microVMFuncTableAddr)
assertNativeSuccess(result)
}
it should "enable and disable watchpoints" in {
val result = ncs_tests.test_wp(microVMFuncTableAddr)
assertNativeSuccess(result)
}
it should "pin and unpin objects, and expose Mu functions." in {
val result = ncs_tests.test_native(microVMFuncTableAddr)
assertNativeSuccess(result)
}
}
\ No newline at end of file
......@@ -679,3 +679,236 @@ bool test_osr(MuVM *mvm) {
return true;
}
bool test_tr64(MuVM *mvm) {
MuCtx *ctx = mvm->new_context(mvm);
MuDoubleValue hf = ctx->handle_from_double(ctx, 3.14);
MuIntValue hi = ctx->handle_from_sint64(ctx, 0x123456789abcdLL, 52);
MuRefValue hr = ctx->new_fixed(ctx, ID("@i32"));
MuIntValue ht = ctx->handle_from_sint8(ctx, 15, 6);
MuTagRef64Value tf = ctx->tr64_from_fp (ctx, hf);
MuTagRef64Value ti = ctx->tr64_from_int(ctx, hi);
MuTagRef64Value tr = ctx->tr64_from_ref(ctx, hr, ht);
int fisf = ctx->tr64_is_fp (ctx, tf);
int fisi = ctx->tr64_is_int(ctx, tf);
int fisr = ctx->tr64_is_ref(ctx, tf);
int iisf = ctx->tr64_is_fp (ctx, ti);
int iisi = ctx->tr64_is_int(ctx, ti);
int iisr = ctx->tr64_is_ref(ctx, ti);
int risf = ctx->tr64_is_fp (ctx, tr);
int risi = ctx->tr64_is_int(ctx, tr);
int risr = ctx->tr64_is_ref(ctx, tr);
MU_ASSERT_EQUALS(fisf, 1, "d");
MU_ASSERT_EQUALS(fisi, 0, "d");
MU_ASSERT_EQUALS(fisr, 0, "d");
MU_ASSERT_EQUALS(iisf, 0, "d");
MU_ASSERT_EQUALS(iisi, 1, "d");
MU_ASSERT_EQUALS(iisr, 0, "d");
MU_ASSERT_EQUALS(risf, 0, "d");
MU_ASSERT_EQUALS(risi, 0, "d");
MU_ASSERT_EQUALS(risr, 1, "d");
MuDoubleValue hfb = ctx->tr64_to_fp (ctx, tf);
MuIntValue hib = ctx->tr64_to_int(ctx, ti);
MuRefValue hrb = ctx->tr64_to_ref(ctx, tr);
MuIntValue htb = ctx->tr64_to_tag(ctx, tr);
double fb = ctx->handle_to_double(ctx, hfb);
int64_t ib = ctx->handle_to_sint64(ctx, hib);
int8_t tb = ctx->handle_to_sint8 (ctx, htb);
MU_ASSERT_EQUALS(fb, 3.14, "lf");
MU_ASSERT_EQUALS(ib, 0x123456789abcdLL, PRIx64);
MU_ASSERT_EQUALS(tb, 15, PRId32); // printf implcitly converts to int.
if (!ctx->ref_eq(ctx, hrb, hr)) {
muprintf("hrb is not equal to hr\n");
return false;
}
ctx->close_context(ctx);
return true;
}
struct wp_trap_data {
int which;
};
void wp_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 wp_trap_data *data = (struct wp_trap_data*)userdata;
int which = data->which;
MuFCRefValue *cursor = ctx->new_cursor(ctx, stack);
MuID iid = ctx->cur_inst(ctx, cursor);
ctx->close_cursor(ctx, cursor);
if (iid == ID("@wptest.v1.entry.wp")) {
MU_ASSERT_EQUALS_TRAP(wpid, 44, "d");
MU_ASSERT_EQUALS_TRAP(which, 1, "d");
muprintf("Prepare to stop thread...\n");
*result = MU_THREAD_EXIT;
muprintf("Omae wa mou shindeiru!\n");
} else if (iid == ID("@wptest.v1.dis.trap")) {
MU_ASSERT_EQUALS_TRAP(which, 0, "d");
muprintf("Prepare to stop thread...\n");
*result = MU_THREAD_EXIT;
muprintf("Omae wa mou shindeiru!\n");
} else {
muprintf("Unknown trap. ID: %d\n", iid);
MuName trapName = NAME(iid);
muprintf("name: %s\n", trapName);
exit(1);
}
}
bool test_wp(MuVM *mvm) {
struct wp_trap_data data = {0};
mvm->set_trap_handler(mvm, wp_trap_handler, &data);
MuCtx *ctx = mvm->new_context(mvm);
MuFuncRefValue func = ctx->handle_from_func(ctx, ID("@wptest"));
{
MuStackRefValue stack = ctx->new_stack(ctx, func);
MuThreadRefValue thread = ctx->new_thread(ctx, stack, MU_REBIND_PASS_VALUES,
NULL, 0, NULL);
mvm->execute(mvm);
}
ctx->enable_watchpoint(ctx, 44);
data.which = 1;
{
MuStackRefValue stack = ctx->new_stack(ctx, func);
MuThreadRefValue thread = ctx->new_thread(ctx, stack, MU_REBIND_PASS_VALUES,
NULL, 0, NULL);
mvm->execute(mvm);
}
ctx->disable_watchpoint(ctx, 44);
data.which = 0;
{
MuStackRefValue stack = ctx->new_stack(ctx, func);
MuThreadRefValue thread = ctx->new_thread(ctx, stack, MU_REBIND_PASS_VALUES,
NULL, 0, NULL);
mvm->execute(mvm);
}
ctx->close_context(ctx);
return true;
}
int (*plus_two)(int n);
int native_callback(int v2) {
muprintf("Mu called back. v2=%d\n", v2);
MU_ASSERT_EQUALS_TRAP(v2, 43, "d");
muprintf("Trying to call plus_two(9)\n");
int result = plus_two(9);
muprintf("plus_two returns %d\n", result);
MU_ASSERT_EQUALS_TRAP(result, 11, "d");
return v2+1;
}
void native_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");
MuFCRefValue *cursor = ctx->new_cursor(ctx, stack);
MuID iid = ctx->cur_inst(ctx, cursor);
MU_ASSERT_EQUALS_TRAP(iid, ID("@native_test.v1.entry.trap"), "d");
MuValue kas[1];
ctx->dump_keepalives(ctx, cursor, kas);
ctx->close_cursor(ctx, cursor);
int32_t rv = ctx->handle_to_sint32(ctx, kas[0]);
MU_ASSERT_EQUALS_TRAP(rv, 44, PRId32);
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");
}
bool test_native(MuVM *mvm) {
mvm->set_trap_handler(mvm, native_trap_handler, NULL);
MuCtx *ctx = mvm->new_context(mvm);
// Expose the @plus_two Mu function
MuFuncRefValue hplus_two = ctx->handle_from_func(ctx, ID("@plus_two"));
MuIntValue hcookie = ctx->handle_from_sint64(ctx, 2LL, 64);
MuUFPValue hplus_two_fp = ctx->expose(ctx, hplus_two, MU_DEFAULT, hcookie);
MuCFP plus_two_fp = ctx->handle_to_fp(ctx, hplus_two_fp);
plus_two = (int(*)(int))plus_two_fp;
// Prepare the native_callback C function for Mu to call
MuIRefValue hg_native_callback = ctx->handle_from_global(ctx, ID("@g_native_callback"));
MuUFPValue hnative_callback_fp = ctx->handle_from_fp(ctx, ID("@native_callback.fp"), (MuCFP)native_callback);
ctx->store(ctx, MU_NOT_ATOMIC, hg_native_callback, hnative_callback_fp);
// Preapare an object for the @native_test function. Pin the object to write
// to it in C assignment expression.
MuRefValue obj = ctx->new_fixed(ctx, ID("@i32"));
MuUPtrValue ptr = ctx->pin(ctx, obj);
int *p = (int*)ctx->handle_to_ptr(ctx, ptr);
*p = 42;
ctx->unpin(ctx, obj);
MuValue args[1] = { obj };
// Prepare to run the test.
MuFuncRefValue func = ctx->handle_from_func(ctx, ID("@native_test"));
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->unexpose(ctx, MU_DEFAULT, hplus_two_fp);
ctx->close_context(ctx);
return true;
}
......@@ -24,3 +24,43 @@
.const @A1 <@a1> = {@I32_2 @I32_3 @I32_4}
.typedef @hyb = hybrid <@i64 @i8>
.funcdef @wptest VERSION %v1 <@v_v> {
%entry():
[%wp] WATCHPOINT 44 <> %dis() %ena()
%dis():
[%trap] TRAP <>
COMMINST @uvm.thread_exit
%ena():
COMMINST @uvm.thread_exit
}
.funcsig @native_callback.sig = (@i32) -> (@i32)
.typedef @native_callback.fp = ufuncptr<@native_callback.sig>
.global @g_native_callback <@native_callback.fp>
.funcsig @native_test.sig = (@refi32) -> ()
.funcdef @native_test VERSION %v1 <@native_test.sig> {
%entry(<@refi32> %r):
%i = GETIREF <@i32> %r
%v = LOAD <@i32> %i
%v2 = ADD <@i32> %v @I32_1
%fp = LOAD <@native_callback.fp> @g_native_callback
%rv = CCALL #DEFAULT <@native_callback.fp @native_callback.sig>
%fp (%v2)
[%trap] TRAP <> KEEPALIVE (%rv)
COMMINST @uvm.thread_exit
}
.funcsig @plus_two.sig = (@i32) -> (@i32)
.funcdef @plus_two VERSION %v1 <@plus_two.sig> {
%entry(<@i32> %n):
%cookie = COMMINST @uvm.native.get_cookie
%cookie32 = TRUNC <@i64 @i32> %cookie
%rv = ADD <@i32> %n %cookie32
RET %rv
}
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