Commit 77e72680 authored by Kunshan Wang's avatar Kunshan Wang

Tested dynamic func exposing via IR and API.

parent b4f80372
......@@ -10,6 +10,7 @@ import uvm.ssavariables.AtomicRMWOptr._
import uvm.refimpl.mem._
import uvm.ssavariables.HasKeepAliveClause
import scala.collection.mutable.ArrayBuffer
import uvm.ssavariables.Flag
case class Handle(ty: Type, vb: ValueBox)
......@@ -555,6 +556,23 @@ class ClientAgent(mutator: Mutator)(
}
unpin(objRef)
}
def expose(func: Handle, callConv: Flag, cookie: Handle): Handle = {
val TypeFunc(sig) = func.ty
val f = func.vb.asInstanceOf[BoxFunc].func.getOrElse {
throw new UvmRuntimeException("Attempt to expose NULL Mu function")
}
val c = cookie.vb.asInstanceOf[BoxInt].value.toLong
val addr = microVM.nativeCallHelper.exposeFunc(f,c,true)
newHandle(InternalTypePool.funcPtrOf(sig), BoxPointer(addr))
}
def unexpose(callConv: Flag, addr: Handle): Unit = {
val a = addr.vb.asInstanceOf[BoxPointer].addr
microVM.nativeCallHelper.unexposeFunc(a)
}
// Internal methods for the micro VM
......
......@@ -1131,11 +1131,32 @@ class InterpreterThread(val id: Int, initialStack: InterpreterStack, val mutator
}
case "@uvm.native.expose" => {
???
val Seq(callConv) = flagList
val Seq(sig) = sigList
val Seq(func, cookie) = argList
val f = boxOf(func).asInstanceOf[BoxFunc].func.getOrElse {
throw new UvmRuntimeException(ctx + "Attempt to expose NULL Mu function")
}
val c = boxOf(cookie).asInstanceOf[BoxInt].value.toLong
val addr = microVM.nativeCallHelper.exposeFunc(f, c, true)
boxOf(i).asInstanceOf[BoxPointer].addr = addr
continueNormally()
}
case "@uvm.native.unexpose" => {
???
val Seq(callConv) = flagList
val Seq(addr) = argList
val a = boxOf(addr).asInstanceOf[BoxPointer].addr
microVM.nativeCallHelper.unexposeFunc(a)
continueNormally()
}
case "@uvm.native.get_cookie" => {
......
......@@ -33,14 +33,14 @@ class UvmInterpreterNativeCallbackTests extends UvmBundleTesterBase {
val hCBAddr = ca.toPointer(hCB)
println("Callback address: 0x%x".format(hCBAddr))
hCBAddr should not be 0L
val nativeFuncAddr = libCallbacktest.getSymbolAddress("one_level")
assert(nativeFuncAddr != 0L)
val hFP = ca.putPointer("@one_level.fp", nativeFuncAddr)
val nativeFuncGlobal = ca.putGlobal("@one_level.global")
ca.store(MemoryOrder.SEQ_CST, nativeFuncGlobal, hFP)
ca.store(MemoryOrder.NOT_ATOMIC, nativeFuncGlobal, hFP)
val muFunc = ca.putFunction("@one_level_test")
......@@ -55,7 +55,7 @@ class UvmInterpreterNativeCallbackTests extends UvmBundleTesterBase {
case 0 => 3.0
case 1 => 4.0
})
ca.toInt(cok).toLong shouldBe 42L
callbackCalled += 1
......@@ -81,7 +81,155 @@ class UvmInterpreterNativeCallbackTests extends UvmBundleTesterBase {
}
callbackCalled shouldBe 2
ca.close()
}
"The @uvm.native.expose instruction" should "allow a native function to call it" in {
val ca = microVM.newClientAgent()
val nativeFuncAddr = libCallbacktest.getSymbolAddress("one_level")
assert(nativeFuncAddr != 0L)
val hFP = ca.putPointer("@one_level.fp", nativeFuncAddr)
val nativeFuncGlobal = ca.putGlobal("@one_level.global")
ca.store(MemoryOrder.NOT_ATOMIC, nativeFuncGlobal, hFP)
val muFunc = ca.putFunction("@one_level_test2")
var callbackCalled: Int = 0
testFunc(ca, muFunc, Seq()) { (ca, th, st, wp) =>
ca.nameOf(ca.currentInstruction(st, 0)) match {
case "@square.v1.trap" => {
val Seq(value, cok) = ca.dumpKeepalives(st, 0)
ca.toDouble(value) shouldBe (callbackCalled match {
case 0 => 3.0
case 1 => 4.0
case 2 => 3.0
case 3 => 4.0
})
ca.toInt(cok).toLong shouldBe (callbackCalled match {
case 0 => 84L
case 1 => 84L
case 2 => 126L
case 3 => 126L
})
callbackCalled += 1
TrapRebindPassVoid(st)
}
case "@one_level_test2.v1.pretrap" => {
val Seq(fp, cb1, cb2) = ca.dumpKeepalives(st, 0)
ca.toPointer(fp) shouldEqual nativeFuncAddr
val cb1Ptr = ca.toPointer(cb1)
val cb2Ptr = ca.toPointer(cb2)
cb1Ptr should not equal cb2Ptr
val cb1Rec = microVM.nativeCallHelper.exposedFuncs(cb1Ptr)
val cb2Rec = microVM.nativeCallHelper.exposedFuncs(cb2Ptr)
cb1Rec.muFunc shouldBe microVM.globalBundle.funcNs("@square")
cb2Rec.muFunc shouldBe microVM.globalBundle.funcNs("@square")
cb1Rec.cookie shouldBe 84L
cb2Rec.cookie shouldBe 126L
TrapRebindPassVoid(st)
}
case "@one_level_test2.v1.trap" => {
val Seq(fp, rv1, rv2, cb1, cb2) = ca.dumpKeepalives(st, 0)
ca.toPointer(fp) shouldEqual nativeFuncAddr
ca.toDouble(rv1) shouldEqual 25.0
ca.toDouble(rv2) shouldEqual 25.0
val cb1Ptr = ca.toPointer(cb1)
val cb2Ptr = ca.toPointer(cb2)
microVM.nativeCallHelper.exposedFuncs should not contain cb1Ptr
microVM.nativeCallHelper.exposedFuncs should not contain cb2Ptr
TrapRebindPassVoid(st)
}
}
}
callbackCalled shouldBe 4
ca.close()
}
"The expose and unexpose API calls" should "allow a native function to call it" in {
val ca = microVM.newClientAgent()
val hCBF = ca.putFunction("@square")
val hCok = ca.putInt("@i64", 168L)
val hCB = ca.expose(hCBF, Flag("#DEFAULT"), hCok)
val hCBAddr = ca.toPointer(hCB)
println("Callback address: 0x%x".format(hCBAddr))
hCBAddr should not be 0L
val nativeFuncAddr = libCallbacktest.getSymbolAddress("one_level")
assert(nativeFuncAddr != 0L)
val hFP = ca.putPointer("@one_level.fp", nativeFuncAddr)
val nativeFuncGlobal = ca.putGlobal("@one_level.global")
ca.store(MemoryOrder.NOT_ATOMIC, nativeFuncGlobal, hFP)
val muFunc = ca.putFunction("@one_level_test3")
var callbackCalled: Int = 0
testFunc(ca, muFunc, Seq(hCB)) { (ca, th, st, wp) =>
ca.nameOf(ca.currentInstruction(st, 0)) match {
case "@square.v1.trap" => {
val Seq(value, cok) = ca.dumpKeepalives(st, 0)
ca.toDouble(value) shouldBe (callbackCalled match {
case 0 => 3.0
case 1 => 4.0
})
ca.toInt(cok).toLong shouldBe 168L
callbackCalled += 1
TrapRebindPassVoid(st)
}
case "@one_level_test3.v1.pretrap" => {
val Seq(fp, cb) = ca.dumpKeepalives(st, 0)
ca.toPointer(fp) shouldEqual nativeFuncAddr
ca.toPointer(cb) shouldEqual hCBAddr
TrapRebindPassVoid(st)
}
case "@one_level_test3.v1.trap" => {
val Seq(fp, rv) = ca.dumpKeepalives(st, 0)
ca.toPointer(fp) shouldEqual nativeFuncAddr
ca.toDouble(rv) shouldEqual 25.0
TrapRebindPassVoid(st)
}
}
}
callbackCalled shouldBe 2
ca.unexpose(Flag("#DEFAULT"), hCB)
microVM.nativeCallHelper.exposedFuncs should not contain hCBAddr
ca.close()
}
}
\ No newline at end of file
......@@ -151,6 +151,8 @@
}
.const @I64_42 <@i64> = 42
.const @I64_84 <@i64> = 84
.const @I64_126 <@i64> = 126
.expose @square.exposed = @square #DEFAULT @I64_42
......@@ -165,3 +167,29 @@
%trap = TRAP <@void> KEEPALIVE (%fp %rv)
COMMINST @uvm.thread_exit
}
.funcdef @one_level_test2 VERSION @one_level_test2.v1 <@noparamsnoret> () {
%entry:
%fp = LOAD <@one_level.fp> @one_level.global
%cb1 = COMMINST @uvm.native.expose [#DEFAULT] <[@DoubleToDouble.sig]> (@square @I64_84)
%cb2 = COMMINST @uvm.native.expose [#DEFAULT] <[@DoubleToDouble.sig]> (@square @I64_126)
%pretrap = TRAP <@void> KEEPALIVE (%fp %cb1 %cb2)
%rv1 = CCALL #DEFAULT <@one_level.fp @one_level.sig> %fp (@D_3 %cb1)
%rv2 = CCALL #DEFAULT <@one_level.fp @one_level.sig> %fp (@D_3 %cb2)
COMMINST @uvm.native.unexpose [#DEFAULT] (%cb1)
COMMINST @uvm.native.unexpose [#DEFAULT] (%cb2)
%trap = TRAP <@void> KEEPALIVE (%fp %rv1 %rv2 %cb1 %cb2)
COMMINST @uvm.thread_exit
}
.funcsig @one_level_test3.sig = @void (@DoubleToDouble.fp)
.funcdef @one_level_test3 VERSION @one_level_test3.v1 <@one_level_test3.sig> (%cb) {
%entry:
%fp = LOAD <@one_level.fp> @one_level.global
%pretrap = TRAP <@void> KEEPALIVE (%fp %cb)
%rv = CCALL #DEFAULT <@one_level.fp @one_level.sig> %fp (@D_3 %cb)
%trap = TRAP <@void> KEEPALIVE (%fp %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