1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::spanned::Spanned;
#[proc_macro_attribute]
pub fn lucet_hostcall(_attr: TokenStream, item: TokenStream) -> TokenStream {
let in_internals = std::env::var("CARGO_PKG_NAME").unwrap() == "lucet-runtime-internals";
let mut hostcall = syn::parse_macro_input!(item as syn::ItemFn);
let hostcall_ident = hostcall.sig.ident.clone();
let attrs = hostcall.attrs.clone();
let vis = hostcall.vis.clone();
hostcall
.attrs
.retain(|attr| !attr.path.is_ident("no_mangle"));
hostcall.vis = syn::Visibility::Inherited;
let mut raw_sig = hostcall.sig.clone();
raw_sig.unsafety = Some(syn::Token![unsafe](raw_sig.span()));
raw_sig.abi = Some(syn::parse_quote!(extern "C"));
let vmctx_mod = if in_internals {
quote! { lucet_runtime_internals::vmctx }
} else {
quote! { lucet_runtime::vmctx }
};
if let Some(arg0) = raw_sig.inputs.iter_mut().nth(0) {
let lucet_vmctx: syn::FnArg = syn::parse_quote!(vmctx_raw: *mut #vmctx_mod::lucet_vmctx);
*arg0 = lucet_vmctx;
}
let impl_args = hostcall
.sig
.inputs
.iter()
.skip(1)
.map(|arg| match arg {
syn::FnArg::Receiver(_) => {
let s = syn::Token![self](arg.span());
quote!(#s)
}
syn::FnArg::Typed(syn::PatType { pat, .. }) => quote!(#pat),
})
.collect::<Vec<_>>();
let termination_details = if in_internals {
quote! { lucet_runtime_internals::instance::TerminationDetails }
} else {
quote! { lucet_runtime::TerminationDetails }
};
let raw_hostcall = quote! {
#(#attrs)*
#vis
#raw_sig {
#[inline(always)]
#hostcall
let mut vmctx = #vmctx_mod::Vmctx::from_raw(vmctx_raw);
#vmctx_mod::VmctxInternal::instance_mut(&mut vmctx).uninterruptable(|| {
let res = std::panic::catch_unwind(move || {
#hostcall_ident(&mut #vmctx_mod::Vmctx::from_raw(vmctx_raw), #(#impl_args),*)
});
match res {
Ok(res) => res,
Err(e) => {
match e.downcast::<#termination_details>() {
Ok(details) => {
#vmctx_mod::Vmctx::from_raw(vmctx_raw).terminate_no_unwind(*details)
},
Err(e) => std::panic::resume_unwind(e),
}
}
}
})
}
};
raw_hostcall.into()
}