GitLab will be upgraded on June 2nd 2020 at 2.00 pm (AEDT) to 3.00 pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to local Gitlab admin team.

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