Commit edde641e authored by Kunshan Wang's avatar Kunshan Wang
Browse files

API-GEN: WIP: Implementing C->Rust conversions...

Now arrays, handles and primitive values can be converted to the
appropriate Rust values.

TODO: Need to forward each function to the concrete api_impl methods,
and convert the return values back to C types. Stubs should be
generated to ease the implementation of high-level methods.
parent ed8e3905
...@@ -6,3 +6,18 @@ mod api_c; ...@@ -6,3 +6,18 @@ mod api_c;
mod api_bridge; mod api_bridge;
mod api_impl; mod api_impl;
/// This is for testing. In the productional setting, replace them with the definitions from
/// `src/ast/src/ir.rs` and `src/ast/src/bundle.rs`
mod deps {
// should import from ast/src/ir.rs
pub type WPID = usize;
pub type MuID = usize;
pub type MuName = String;
pub type CName = MuName;
pub struct APIMuValue {
// stub
}
}
This diff is collapsed.
...@@ -12,7 +12,13 @@ ...@@ -12,7 +12,13 @@
use std::os::raw::*; use std::os::raw::*;
// some hand-written function pointer types // some hand-written function pointer types
pub type CMuCFP = extern fn();
// Don't treat void(*)() as Rust funcptr fn(), because fn() is not nullable.
//
// In this Mu API, the MuCFP type is only used as raw data, representing a C-level function
// pointer, and is treated as so by the micro VM itself. So we keep it as raw pointer here.
pub type CMuCFP = *mut c_void;
pub type CMuValuesFreer = extern fn(*mut CMuValue, CMuCPtr); pub type CMuValuesFreer = extern fn(*mut CMuValue, CMuCPtr);
pub type CMuTrapHandler = extern fn( pub type CMuTrapHandler = extern fn(
// input parameters // input parameters
......
/*!
* This file contains the high-level implementation of the Mu API.
*
* Structs are written in idiomatic Rust code. The internal structures of these structs are
* implementation-specific. Methods are defined using `impl`.
*/
pub struct MuVM {
}
pub struct MuCtx {
}
pub struct MuIRBuilder {
}
...@@ -343,67 +343,67 @@ def to_rust_type(raw_type): ...@@ -343,67 +343,67 @@ def to_rust_type(raw_type):
# footer = "}" # footer = "}"
# #
# return (valname, "\n".join([header] + stmts + [footer])) # return (valname, "\n".join([header] + stmts + [footer]))
#
def generate_stubs_for_struct(typedefs, st) -> str: #def generate_stubs_for_struct(typedefs, st) -> str:
name = st["name"] # name = st["name"]
methods = st["methods"] # methods = st["methods"]
#
results = [] # results = []
ptrs = [] # ptrs = []
#
for meth in methods: # for meth in methods:
ptrname, code = generate_method(typedefs, name, meth) # ptrname, code = generate_method(typedefs, name, meth)
ptrs.append(ptrname) # ptrs.append(ptrname)
results.append(code) # results.append(code)
#
results.append("val stubsOf{} = new Array[Word]({})".format(name, len(ptrs))) # results.append("val stubsOf{} = new Array[Word]({})".format(name, len(ptrs)))
for i,ptr in enumerate(ptrs): # for i,ptr in enumerate(ptrs):
results.append("stubsOf{}({}) = {}.address".format(name, i, ptr)) # results.append("stubsOf{}({}) = {}.address".format(name, i, ptr))
#
return "\n".join(results) # return "\n".join(results)
#
def generate_stubs(ast): #def generate_stubs(ast):
struct_codes = [] # struct_codes = []
#
for st in ast["structs"]: # for st in ast["structs"]:
code = generate_stubs_for_struct(ast["typedefs"], st) # code = generate_stubs_for_struct(ast["typedefs"], st)
struct_codes.append(code) # struct_codes.append(code)
#
return "\n".join(struct_codes) # return "\n".join(struct_codes)
#
_enum_types_to_generate_converters = [ #_enum_types_to_generate_converters = [
("MuBinOptr", "BinOptr", 'MU_BINOP_'), # ("MuBinOptr", "BinOptr", 'MU_BINOP_'),
("MuCmpOptr", "CmpOptr", 'MU_CMP_'), # ("MuCmpOptr", "CmpOptr", 'MU_CMP_'),
("MuConvOptr", "ConvOptr", 'MU_CONV_'), # ("MuConvOptr", "ConvOptr", 'MU_CONV_'),
("MuMemOrd", "MemoryOrder", 'MU_ORD_'), # ("MuMemOrd", "MemoryOrder", 'MU_ORD_'),
("MuAtomicRMWOptr", "AtomicRMWOptr", 'MU_ARMW_'), # ("MuAtomicRMWOptr", "AtomicRMWOptr", 'MU_ARMW_'),
] # ]
#
def generate_enum_converters(ast): #def generate_enum_converters(ast):
enums = ast['enums'] # enums = ast['enums']
edict = {} # edict = {}
#
for e in enums: # for e in enums:
edict[e['name']] = e['defs'] # edict[e['name']] = e['defs']
#
lines = [] # lines = []
#
for cty, sty, prefix in _enum_types_to_generate_converters: # for cty, sty, prefix in _enum_types_to_generate_converters:
func_name = "to"+sty # func_name = "to"+sty
lines.append("def {}(cval: {}): {}.Value = cval match {{".format( # lines.append("def {}(cval: {}): {}.Value = cval match {{".format(
func_name, cty, sty)) # func_name, cty, sty))
#
defs = edict[cty] # defs = edict[cty]
for d in defs: # for d in defs:
dn = d['name'] # dn = d['name']
dv = d['value'] # dv = d['value']
assert(dn.startswith(prefix)) # assert(dn.startswith(prefix))
sn = dn[len(prefix):] # sn = dn[len(prefix):]
lines.append(" case {} => {}.{}".format(dv, sty, sn)) # lines.append(" case {} => {}.{}".format(dv, sty, sn))
#
lines.append("}") # lines.append("}")
#
return "\n".join(lines) # return "\n".join(lines)
__rust_kw_rewrite = { __rust_kw_rewrite = {
"ref": "reff", "ref": "reff",
...@@ -437,6 +437,31 @@ def generate_struct_field(meth) -> str: ...@@ -437,6 +437,31 @@ def generate_struct_field(meth) -> str:
return field_def return field_def
_no_conversion = {
# These are used as raw data.
# Even the implementation layer has to use the raw C types.
"MuCPtr",
"MuCFP",
# These are C functions provided and regisered by the client.
# They should be treated like C functions.
"MuValueFreer",
"MuTrapHandler",
# Watch point ID is considered as primitive.
"MuWPID",
# These are enum types. Passed to the micro VM as is.
"MuBinOpStatus",
"MuBinOptr",
"MuCmpOptr",
"MuConvOptr",
"MuMemOrd",
"MuAtomicRMWOptr",
"MuCallConv",
"MuCommInst",
} | _primitive_types.keys()
def generate_forwarder(st, meth) -> str: def generate_forwarder(st, meth) -> str:
name = meth['name'] name = meth['name']
params = meth['params'] params = meth['params']
...@@ -480,15 +505,20 @@ def generate_forwarder(st, meth) -> str: ...@@ -480,15 +505,20 @@ def generate_forwarder(st, meth) -> str:
array_sz_param = param.get("array_sz_param", None) array_sz_param = param.get("array_sz_param", None)
is_optional = param.get("is_optional", False) is_optional = param.get("is_optional", False)
is_out = param.get("is_out", False)
if array_sz_param != None:
assert cty.endswith("*") if is_out:
assert type_is_explicit_ptr(cty)
converter = rpn # Do not convert out param.
# Keep as ptr so that Rust prog can store into it.
elif array_sz_param != None:
assert type_is_explicit_ptr(cty)
c_base_ty = cty[:-1] c_base_ty = cty[:-1]
sz_cpn = array_sz_param sz_cpn = array_sz_param
sz_rpn = avoid_rust_kws(sz_cpn) sz_rpn = avoid_rust_kws(sz_cpn)
if type_is_ptr(c_base_ty): if type_is_handle(c_base_ty):
converter = "from_ptr_array({}, {})".format( converter = "from_handle_array({}, {})".format(
rpn, sz_rpn) rpn, sz_rpn)
elif type_is_node(c_base_ty): elif type_is_node(c_base_ty):
converter = "from_MuID_array({}, {})".format( converter = "from_MuID_array({}, {})".format(
...@@ -497,10 +527,10 @@ def generate_forwarder(st, meth) -> str: ...@@ -497,10 +527,10 @@ def generate_forwarder(st, meth) -> str:
converter = "from_{}_array({}, {})".format( converter = "from_{}_array({}, {})".format(
c_base_ty, rpn, sz_rpn) c_base_ty, rpn, sz_rpn)
elif is_optional: elif is_optional:
if type_is_ptr(cty): if type_is_handle(cty):
converter = "from_ptr_optional({})".format(rpn) converter = "from_handle_optional({})".format(rpn)
elif type_is_node(cty): elif type_is_node(cty):
converter = "from_node_optional({})".format(rpn) converter = "from_MuID_optional({})".format(rpn)
elif cty in ["MuCString", "MuID"]: elif cty in ["MuCString", "MuID"]:
converter = "from_{}_optional({})".format(cty, rpn) converter = "from_{}_optional({})".format(cty, rpn)
else: else:
...@@ -509,6 +539,12 @@ def generate_forwarder(st, meth) -> str: ...@@ -509,6 +539,12 @@ def generate_forwarder(st, meth) -> str:
if cty.endswith("*"): if cty.endswith("*"):
c_base_ty = cty[:-1] c_base_ty = cty[:-1]
converter = "from_{}_ptr({})".format(c_base_ty, rpn) converter = "from_{}_ptr({})".format(c_base_ty, rpn)
elif type_is_handle(cty):
converter = "from_handle({})".format(rpn)
elif type_is_node(cty):
converter = "from_MuID({})".format(rpn)
elif cty in _no_conversion:
converter = rpn # Do not convert primitive types.
else: else:
converter = "from_{}({})".format(cty, rpn) converter = "from_{}({})".format(cty, rpn)
......
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