Commit ac4beb8f authored by Kunshan Wang's avatar Kunshan Wang

Test recursive Mu-C calls

parent 77e72680
......@@ -35,7 +35,7 @@ class UvmInterpreterNativeCallbackTests extends UvmBundleTesterBase {
hCBAddr should not be 0L
val nativeFuncAddr = libCallbacktest.getSymbolAddress("one_level")
assert(nativeFuncAddr != 0L)
nativeFuncAddr should not be 0L
val hFP = ca.putPointer("@one_level.fp", nativeFuncAddr)
......@@ -90,7 +90,7 @@ class UvmInterpreterNativeCallbackTests extends UvmBundleTesterBase {
val ca = microVM.newClientAgent()
val nativeFuncAddr = libCallbacktest.getSymbolAddress("one_level")
assert(nativeFuncAddr != 0L)
nativeFuncAddr should not be 0L
val hFP = ca.putPointer("@one_level.fp", nativeFuncAddr)
......@@ -178,7 +178,7 @@ class UvmInterpreterNativeCallbackTests extends UvmBundleTesterBase {
hCBAddr should not be 0L
val nativeFuncAddr = libCallbacktest.getSymbolAddress("one_level")
assert(nativeFuncAddr != 0L)
nativeFuncAddr should not be 0L
val hFP = ca.putPointer("@one_level.fp", nativeFuncAddr)
......@@ -232,4 +232,85 @@ class UvmInterpreterNativeCallbackTests extends UvmBundleTesterBase {
ca.close()
}
"The exposing definition" should "allow multi-level nested/recursive Mu-native calls" in {
val ca = microVM.newClientAgent()
val hPongFP = ca.putExpFunc("@pong.exposed")
val pongAddr = ca.toPointer(hPongFP)
println("Exposed Mu func (pong) addr: 0x%x".format(pongAddr))
pongAddr should not be 0L
val pingAddr = libCallbacktest.getSymbolAddress("ping")
println("Native func (ping) addr: 0x%x".format(pingAddr))
pingAddr should not be 0L
val hPingFP = ca.putPointer("@PingPong.fp", pingAddr)
val hPongTest = ca.putFunction("@pong_test")
val initialV = ca.putInt("@i32", 10)
var pongCalled: Int = 0
testFunc(ca, hPongTest, Seq(initialV, hPingFP)) { (ca, th, st, wp) =>
ca.nameOf(ca.currentInstruction(st, 0)) match {
case "@pong.v1.entrytrap" => {
val Seq(v, peer) = ca.dumpKeepalives(st, 0)
val vInt = ca.toInt(v).toInt
val peerAddr = ca.toPointer(peer)
pongCalled += 1
printf("Pong called. v=%d, peer=0x%x\n", vInt, peerAddr)
vInt shouldBe (pongCalled match {
case 1 => 10
case 2 => 8
case 3 => 6
case 4 => 4
case 5 => 2
case 6 => 0
})
ca.toPointer(peer) shouldEqual pingAddr
TrapRebindPassVoid(st)
}
case "@pong.v1.resptrap" => {
val Seq(v, resp) = ca.dumpKeepalives(st, 0)
val vInt = ca.toInt(v).toInt
val respInt = ca.toInt(resp).toInt
respInt shouldBe (vInt match {
case 10 => 362880
case 8 => 5040
case 6 => 120
case 4 => 6
case 2 => 1
})
TrapRebindPassVoid(st)
}
case "@pong_test.v1.entrytrap" => {
val Seq(v, peer) = ca.dumpKeepalives(st, 0)
ca.toInt(v).toInt shouldEqual 10
ca.toPointer(peer) shouldEqual pingAddr
TrapRebindPassVoid(st)
}
case "@pong_test.v1.exittrap" => {
val Seq(rv) = ca.dumpKeepalives(st, 0)
ca.toInt(rv).toInt shouldEqual 3628800
TrapRebindPassVoid(st)
}
}
}
pongCalled shouldBe 6
ca.close()
}
}
\ No newline at end of file
......@@ -12,3 +12,19 @@ double one_level(double v1, DoubleToDouble cb) {
v3 = cb(v1+1.0);
return v2 + v3;
}
//typedef int (*PingPong)(int v, PingPong cb); // ERROR
typedef void (*AnyFunc)(); // workaround
typedef int (*PingPong)(int v, AnyFunc cb); // workaround
int ping(int v, PingPong cb) {
printf("[C:ping] v=%d, cb=%p\n", v, cb);
if (v == 0) {
return 1;
} else {
PingPong cbPingPong = (PingPong)cb;
AnyFunc selfAnyFunc = (AnyFunc)ping;
return v * cbPingPong(v-1, selfAnyFunc);
}
}
......@@ -193,3 +193,33 @@
%trap = TRAP <@void> KEEPALIVE (%fp %rv)
COMMINST @uvm.thread_exit
}
.funcsig @PingPong.sig = @i32 (@i32 @PingPong.fp)
.typedef @PingPong.fp = funcptr<@PingPong.sig>
.funcdef @pong VERSION @pong.v1 <@PingPong.sig> (%v %peer) {
%entry:
%entrytrap = TRAP<@void> KEEPALIVE (%v %peer)
%check_zero = EQ <@i32> %v @I32_0
BRANCH2 %check_zero %is_zero %not_zero
%is_zero:
RET <@i32> @I32_1
%not_zero:
%nextv = SUB <@i32> %v @I32_1
%resp = CCALL #DEFAULT <@PingPong.fp @PingPong.sig> %peer (%nextv @pong.exposed)
%resptrap = TRAP<@void> KEEPALIVE (%v %resp)
%rv = MUL <@i32> %resp %v
RET <@i32> %rv
}
.expose @pong.exposed = @pong #DEFAULT @I64_0
.funcdef @pong_test VERSION @pong_test.v1 <@PingPong.sig> (%v %peer) {
%entry:
%entrytrap = TRAP<@void> KEEPALIVE (%v %peer)
%rv = CALL <@PingPong.sig> @pong (%v %peer)
%exittrap = TRAP<@void> KEEPALIVE (%rv)
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