Commit 982ce681 authored by Kunshan Wang's avatar Kunshan Wang

generate parameter getters

parent 14a56aaa
......@@ -272,7 +272,7 @@ struct MuCtx {
MuIntValue (*handle_from_uint32)(MuCtx *ctx, uint32_t num, int len);
MuIntValue (*handle_from_sint64)(MuCtx *ctx, int64_t num, int len);
MuIntValue (*handle_from_uint64)(MuCtx *ctx, uint64_t num, int len);
MuIntValue (*handle_from_uint64s)(MuCtx *ctx, uint64_t *nums, int nnums, int len); /// MUAPIPARSER num:array:nnum
MuIntValue (*handle_from_uint64s)(MuCtx *ctx, uint64_t *nums, int nnums, int len); /// MUAPIPARSER nums:array:nnums
MuFloatValue (*handle_from_float )(MuCtx *ctx, float num);
MuDoubleValue (*handle_from_double)(MuCtx *ctx, double num);
MuUPtrValue (*handle_from_ptr )(MuCtx *ctx, MuID mu_type, MuCPtr ptr);
......
......@@ -70,14 +70,14 @@ def extract_enums(text, typename, pattern):
_top_level_structs = ["MuVM", "MuCtx"]
_enums = [(typename, re.compile(regex)) for typename, regex in [
("MuTrapHandlerResult", r'^MU_(THREAD|REBIND)'),
("MuDestKind", r'^MU_DEST_'),
("MuBinOptr", r'^MU_BINOP_'),
("MuCmpOptr", r'^MU_CMP_'),
("MuConvOptr", r'^MU_CONV_'),
("MuMemOrd", r'^MU_ORD_'),
("MuAtomicRMWOp", r'^MU_ARMW_'),
("MuCallConv", r'^MU_CC_'),
("MuCommInst", r'^MU_CI_'),
("MuDestKind", r'^MU_DEST_'),
("MuBinOptr", r'^MU_BINOP_'),
("MuCmpOptr", r'^MU_CMP_'),
("MuConvOptr", r'^MU_CONV_'),
("MuMemOrd", r'^MU_ORD_'),
("MuAtomicRMWOptr", r'^MU_ARMW_'),
("MuCallConv", r'^MU_CC_'),
("MuCommInst", r'^MU_CI_'),
]]
def extract_typedefs(text):
......
......@@ -42,7 +42,7 @@ _primitive_types = {
"double": ["Double", "DOUBLE", "getDouble", "setDoubleReturn"],
}
_funcptr_types = {"MuCFP", "MuTrapHandler", "MuValueFreer"}
_other_ptr_types = {"MuName", "MuCFP", "MuTrapHandler", "MuValueFreer"}
_self_getters = {
"MuVM*": "getMuVM",
......@@ -58,10 +58,10 @@ def type_is_handle(ty):
return r_handle_ty.match(ty) is not None
def type_is_ptr(ty):
return type_is_explicit_ptr(ty) or type_is_handle(ty) or ty in _funcptr_types
return type_is_explicit_ptr(ty) or type_is_handle(ty) or ty in _other_ptr_types
def type_is_handle_array(ty):
return is_ptr(ty) and r_handle_ty.match(ty[:-1]) is not None
return type_is_ptr(ty) and r_handle_ty.match(ty[:-1]) is not None
def to_jffi_ty(cty):
if cty in _primitive_types:
......@@ -139,6 +139,65 @@ def to_basic_type(typedefs, name):
name = typedefs[name]
return name
_no_conversion = {
"MuID", # It's just Int.
"MuName", # Only two functions. Handle in Scala.
"MuTrapHandler", # It is a function pointer. Handle in Scala.
"MuCPtr", # Intended to be raw pointer. Passed directly.
"MuCFP", # ditto
"char*", # Only used in load_bundle or load_hail. Handle in Scala.
"int*", # Only used in cmpxchg as an output parameter. Handle in Scala.
"MuWPID", # Just Int
"MuCommInst", # Onlu used in new_comminst, and the builder uses opcode directly.
}
_array_converters = {
"uint64_t*" : "readLongArray",
"MuFlag*" : "readFlagArray",
}
_special_converters = {
"MuMemOrd" : "toMemoryOrder",
"MuAtomicRMWOptr" : "toAtomicRMWOptr",
"MuBinOptr" : "toBinOptr",
"MuCmpOptr" : "toCmpOptr",
"MuConvOptr" : "toConvOptr",
"MuCallConv" : "toFlag",
"MuDestKind" : "toDestKind",
}
def param_converter(pn, pt, rn, rt, is_optional, array_sz, is_bool):
if pt == "void":
raise ValueError("Parameter cannot be void. Param name: {}".format(pn))
if pt in _primitive_types or pt in _no_conversion:
return rn # does not need conversion
if array_sz is not None:
if type_is_handle_array(pt):
ac = "readMuValueArray"
elif pt in _array_converters:
ac = _array_converters[pt]
else:
raise ValueError("I don't know how to convert array {}. "
"Param name: {}, array size: {}".format(pt, pn, array_sz))
return "{}({}, {})".format(ac, rn, array_sz)
if type_is_handle(pt):
if is_optional:
return "getMuValueNullable({})".format(rn)
else:
return "getMuValueNotNull({})".format(rn)
if pt in _special_converters:
return "{}({})".format(_special_converters[pt], rn)
if pt == "int" and is_bool:
return "{} != 0".foramt(rn)
raise ValueError("I don't know how to convert {}. Param name: {}".format(
pt, pn))
def generate_method(typedefs, strname, meth) -> Tuple[str, str]:
name = meth['name']
params = meth['params']
......@@ -153,19 +212,67 @@ def generate_method(typedefs, strname, meth) -> Tuple[str, str]:
header = "val {} = exposedMethod({}, Array({})) {{ _jffiBuffer =>".format(
valname, jffi_retty, ", ".join(jffi_paramtys))
pragmas = [tuple(p.split(":")) for p in pragmas]
stmts = []
# pragmas
pragmas = [tuple(p.split(":")) for p in pragmas]
array_szs = [p[2] for p in pragmas if p[1] == 'array']
# get raw parameters
for i in range(len(params)):
param = params[i]
pn = param['name']
pt = param['type']
rt = to_basic_type(typedefs, pt) # raw type
jffi_getter = to_jffi_getter(rt)
rn = "_raw_" + pn # raw name
stmts.append("val {} = _jffiBuffer.{}({})".format(rn,
jffi_getter, i))
self_param_name = params[0]["name"]
self_param_type = params[0]["type"]
stmts.append("val {} = _jffiBuffer.{}(0)".format(self_param_name,
to_jffi_getter(self_param_type)))
self_obj = "_" + self_param_name + "_obj"
# get the self object (MuVM or MuCtx)
stmts.append("val {} = {}({})".format(
self_obj, _self_getters[self_param_type], self_param_name))
self_param_name,
_self_getters[self_param_type],
"_raw_"+self_param_name))
# convert parameters
for i in range(1, len(params)):
param = params[i]
pn = param['name']
if pn in array_szs:
continue # Array sizes don't need to be passed explicitly.
pt = param['type']
rn = "_raw_" + pn
rt = to_basic_type(typedefs, pt)
pps = [p for p in pragmas if p[0] == pn]
is_optional = False
array_sz = None
is_bool = False
for pp in pps:
if pp[1] == 'array':
array_sz = "_raw_" + pp[2]
elif pp[1] == 'optional':
is_optional = True
elif pp[1] == 'bool':
is_bool = True
pc = param_converter(pn, pt, rn, rt, is_optional, array_sz, is_bool)
stmts.append("val {} = {}".format(pn, pc))
# make the call
# return value
footer = "}"
......@@ -198,13 +305,58 @@ def generate_stubs(ast):
return "\n".join(struct_codes)
def generate_enums(ast):
vals = []
for enum in ast['enums']:
for d in enum['defs']:
vals.append("val {} = {}".format(d['name'], d['value']))
return "\n".join(vals)
_enum_types_to_generate_converters = [
("MuDestKind", "DestKind", 'MU_DEST_'),
("MuBinOptr", "BinOptr", 'MU_BINOP_'),
("MuCmpOptr", "CmpOptr", 'MU_CMP_'),
("MuConvOptr", "ConvOptr", 'MU_CONV_'),
("MuMemOrd", "MemoryOrder", 'MU_ORD_'),
("MuAtomicRMWOptr", "AtomicRMWOptr", 'MU_ARMW_'),
]
def generate_enum_converters(ast):
enums = ast['enums']
edict = {}
for e in enums:
edict[e['name']] = e['defs']
lines = []
for cty, sty, prefix in _enum_types_to_generate_converters:
func_name = "to"+sty
lines.append("def {}(cval: {}): {}.Value = cval match {{".format(
func_name, cty, sty))
defs = edict[cty]
for d in defs:
dn = d['name']
dv = d['value']
assert(dn.startswith(prefix))
sn = dn[len(prefix):]
lines.append(" case {} => {}.{}".format(dv, sty, sn))
lines.append("}")
return "\n".join(lines)
def generate_things(ast):
stubs = generate_stubs(ast)
enums = "" # TODO: generate_enums(ast)
enums = generate_enums(ast)
enum_convs = generate_enum_converters(ast)
return "\n".join([stubs])
return "\n".join([stubs, enums, enum_convs])
src_path = "cbinding/muapi.h"
dst_path = "src/main/scala/uvm/refimpl/nat/cStubs.scala"
......
This diff is collapsed.
package uvm.refimpl.nat
import com.kenai.jffi.CallingConvention
import com.kenai.jffi.Closure
import com.kenai.jffi.Closure.Buffer
import com.kenai.jffi.{ Type => JType }
import NativeSupport._
import PlatformConstants._
import uvm.refimpl._
import uvm.ssavariables.{BinOptr, CmpOptr, ConvOptr, MemoryOrder, AtomicRMWOptr}
import uvm.ir.irbuilder.DestKind
import CDefsHelperFunctions._
import uvm.refimpl.MicroVM
import uvm.ssavariables.Flag
class ExposedMethod(jRetTy: JType, jParamTys: Array[JType], invokeFunc: Buffer => Unit) {
val closure = new SimpleClosure(invokeFunc)
val handle = jffiClosureManager.newClosure(closure, jRetTy, jParamTys, CallingConvention.DEFAULT)
def address = handle.getAddress()
}
class SimpleClosure(f: Buffer => Unit) extends Closure {
def invoke(buffer: Buffer): Unit = f(buffer)
}
private object CDefsHelperFunctions {
def exposedMethod(jRetTy: JType, jParamTys: Array[JType])(invokeFunc: Buffer => Unit) = {
new ExposedMethod(jRetTy, jParamTys, invokeFunc)
}
def getMuVM(ptr: Long): MicroVM = NativeClientSupport.getMicroVM(ptr)
def getMuCtx(ptr: Long): MuCtx = NativeClientSupport.getMuCtx(ptr)
def getMuValueNotNull(ptr: Long): MuValue = NativeClientSupport.getMuValueNotNull(ptr)
def getMuValueNullable(ptr: Long): Option[MuValue] = NativeClientSupport.getMuValueNullable(ptr)
def readIntArray(base: Long, len: Long): IndexedSeq[Int] = {
if (base == 0L) {
IndexedSeq[Int]()
} else {
for (i <- 0L until len) yield {
val addr = base + i * 4L
val v = theMemory.getInt(addr)
v
}
}
}
def readLongArray(base: Long, len: Long): IndexedSeq[Long] = {
if (base == 0L) {
IndexedSeq[Long]()
} else {
for (i <- 0L until len) yield {
val addr = base + i * 8L
val v = theMemory.getLong(addr)
v
}
}
}
def readMuValueArray(base: Long, len: Long): IndexedSeq[MuValue] = {
readLongArray(base, len).map(getMuValueNotNull)
}
def readFlagArray(base: Long, len: Long): IndexedSeq[Flag] = {
readIntArray(base, len).map(toFlag)
}
def toFlag(cval: Int): Flag = cval match {
case 0x00 => Flag("#DEFAULT")
case _ => throw new IllegalArgumentException("Unknown calling convention %d (0x%x)".format(cval, cval))
}
}
\ No newline at end of file
......@@ -266,7 +266,7 @@ object NativeMuCtx {
theMemory.putInt(is_succ, if (succ) 1 else 0)
exposeMuValue(ctx, rv)
}
def atomicrmw(ctx: MuCtx, ord: MuMemOrd, op: MuAtomicRMWOp, loc: MuIRefValue, opnd: MuValue): MuValueFak = {
def atomicrmw(ctx: MuCtx, ord: MuMemOrd, op: MuAtomicRMWOptr, loc: MuIRefValue, opnd: MuValue): MuValueFak = {
val rv = ctx.atomicRMW(ord, op, loc, opnd)
exposeMuValue(ctx, rv)
}
......@@ -418,7 +418,7 @@ object NativeMuCtx {
def new_load(ctx: MuCtx, bb: MuBBNode, is_ptr: Int, ord: MuMemOrd, refty: MuTypeNode, loc: MuVarNode): MuValueFak = exposeMuValue(ctx, ctx.newLoad(bb, is_ptr != 0, ord, refty, loc))
def new_store(ctx: MuCtx, bb: MuBBNode, is_ptr: Int, ord: MuMemOrd, refty: MuTypeNode, loc: MuVarNode, newval: MuVarNode): MuValueFak = exposeMuValue(ctx, ctx.newStore(bb, is_ptr != 0, ord, refty, loc, newval))
def new_cmpxchg(ctx: MuCtx, bb: MuBBNode, is_ptr: Int, is_weak: Int, ord_succ: MuMemOrd, ord_fail: MuMemOrd, refty: MuTypeNode, loc: MuVarNode, expected: MuVarNode, desired: MuVarNode): MuValueFak = exposeMuValue(ctx, ctx.newCmpXchg(bb, is_ptr != 0, is_weak != 0, ord_succ, ord_fail, refty, loc, expected, desired))
def new_atomicrmw(ctx: MuCtx, bb: MuBBNode, is_ptr: Int, ord: MuMemOrd, optr: MuAtomicRMWOp, refTy: MuTypeNode, loc: MuVarNode, opnd: MuVarNode): MuValueFak = exposeMuValue(ctx, ctx.newAtomicRMW(bb, is_ptr != 0, ord, optr, refTy, loc, opnd))
def new_atomicrmw(ctx: MuCtx, bb: MuBBNode, is_ptr: Int, ord: MuMemOrd, optr: MuAtomicRMWOptr, refTy: MuTypeNode, loc: MuVarNode, opnd: MuVarNode): MuValueFak = exposeMuValue(ctx, ctx.newAtomicRMW(bb, is_ptr != 0, ord, optr, refTy, loc, opnd))
def new_fence(ctx: MuCtx, bb: MuBBNode, ord: MuMemOrd): MuValueFak = exposeMuValue(ctx, ctx.newFence(bb, ord))
def new_trap(ctx: MuCtx, bb: MuBBNode, rettys: MuValueFakArrayPtr, nrettys: Int): MuValueFak = exposeMuValue(ctx, ctx.newTrap(bb, readFromValueFakArray(rettys, nrettys)))
def new_watchpoint(ctx: MuCtx, bb: MuBBNode, wpid: MuWPID, rettys: MuValueFakArrayPtr, nrettys: Int): MuValueFak = exposeMuValue(ctx, ctx.newWatchPoint(bb, wpid, readFromValueFakArray(rettys, nrettys)))
......@@ -492,7 +492,7 @@ object NativeMuHelpers {
case MU_SEQ_CST => MemoryOrder.SEQ_CST
}
implicit def intToMemAtomicRMWOp(op: MuAtomicRMWOp): AtomicRMWOptr.AtomicRMWOptr = op match {
implicit def intToMemAtomicRMWOp(op: MuAtomicRMWOptr): AtomicRMWOptr.AtomicRMWOptr = op match {
case MU_XCHG => AtomicRMWOptr.XCHG
case MU_ADD => AtomicRMWOptr.ADD
case MU_SUB => AtomicRMWOptr.SUB
......@@ -980,7 +980,7 @@ object NativeClientSupport {
type MuCPtr = Word
type MuCFP = Word
type MuMemOrd = Int
type MuAtomicRMWOp = Int
type MuAtomicRMWOptr = Int
type MuHowToResume = Int
type MuHowToResumePtr = IntPtr
type MuCallConv = Int
......@@ -1021,6 +1021,16 @@ object NativeClientSupport {
muVal
}
/** Get the MuValue instance form a C MuValue (a pointer). */
def getMuValueNullable(fak: MuValueFak): Option[MuValue] = {
val muVal = muValues.get(jnrMemoryManager.newPointer(fak))
if (muVal == null) {
None
} else {
Some(muVal)
}
}
/**
* Map function table addresses to Pointer so they can be closed. JFFI uses the TrantientNativeMemory (wrapped
* in the Pointer object) to keep the allocated native memory alive.
......
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