WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

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;
mod api_bridge;
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 @@
use std::os::raw::*;
// 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 CMuTrapHandler = extern fn(
// 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):
# footer = "}"
#
# return (valname, "\n".join([header] + stmts + [footer]))
def generate_stubs_for_struct(typedefs, st) -> str:
name = st["name"]
methods = st["methods"]
results = []
ptrs = []
for meth in methods:
ptrname, code = generate_method(typedefs, name, meth)
ptrs.append(ptrname)
results.append(code)
results.append("val stubsOf{} = new Array[Word]({})".format(name, len(ptrs)))
for i,ptr in enumerate(ptrs):
results.append("stubsOf{}({}) = {}.address".format(name, i, ptr))
return "\n".join(results)
def generate_stubs(ast):
struct_codes = []
for st in ast["structs"]:
code = generate_stubs_for_struct(ast["typedefs"], st)
struct_codes.append(code)
return "\n".join(struct_codes)
_enum_types_to_generate_converters = [
("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_stubs_for_struct(typedefs, st) -> str:
# name = st["name"]
# methods = st["methods"]
#
# results = []
# ptrs = []
#
# for meth in methods:
# ptrname, code = generate_method(typedefs, name, meth)
# ptrs.append(ptrname)
# results.append(code)
#
# results.append("val stubsOf{} = new Array[Word]({})".format(name, len(ptrs)))
# for i,ptr in enumerate(ptrs):
# results.append("stubsOf{}({}) = {}.address".format(name, i, ptr))
#
# return "\n".join(results)
#
#def generate_stubs(ast):
# struct_codes = []
#
# for st in ast["structs"]:
# code = generate_stubs_for_struct(ast["typedefs"], st)
# struct_codes.append(code)
#
# return "\n".join(struct_codes)
#
#_enum_types_to_generate_converters = [
# ("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)
__rust_kw_rewrite = {
"ref": "reff",
......@@ -437,6 +437,31 @@ def generate_struct_field(meth) -> str:
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:
name = meth['name']
params = meth['params']
......@@ -480,15 +505,20 @@ def generate_forwarder(st, meth) -> str:
array_sz_param = param.get("array_sz_param", None)
is_optional = param.get("is_optional", False)
if array_sz_param != None:
assert cty.endswith("*")
is_out = param.get("is_out", False)
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]
sz_cpn = array_sz_param
sz_rpn = avoid_rust_kws(sz_cpn)
if type_is_ptr(c_base_ty):
converter = "from_ptr_array({}, {})".format(
if type_is_handle(c_base_ty):
converter = "from_handle_array({}, {})".format(
rpn, sz_rpn)
elif type_is_node(c_base_ty):
converter = "from_MuID_array({}, {})".format(
......@@ -497,10 +527,10 @@ def generate_forwarder(st, meth) -> str:
converter = "from_{}_array({}, {})".format(
c_base_ty, rpn, sz_rpn)
elif is_optional:
if type_is_ptr(cty):
converter = "from_ptr_optional({})".format(rpn)
if type_is_handle(cty):
converter = "from_handle_optional({})".format(rpn)
elif type_is_node(cty):
converter = "from_node_optional({})".format(rpn)
converter = "from_MuID_optional({})".format(rpn)
elif cty in ["MuCString", "MuID"]:
converter = "from_{}_optional({})".format(cty, rpn)
else:
......@@ -509,6 +539,12 @@ def generate_forwarder(st, meth) -> str:
if cty.endswith("*"):
c_base_ty = cty[:-1]
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:
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