forked from bytecodealliance/lucet
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add
#[lucet_hostcall]
attr macro; deprecate lucet_hostcalls!
The attribute macro is much more flexible syntactically, and in particular allows hostcall implementations to be properly `rustfmt`ed rather than being stuck in the invocation of a macro.
- Loading branch information
Showing
18 changed files
with
609 additions
and
472 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
[package] | ||
name = "lucet-runtime-macros" | ||
version = "0.4.1" | ||
description = "Macros for the Lucet WebAssembly runtime" | ||
homepage = "https://github.com/bytecodealliance/lucet" | ||
repository = "https://github.com/bytecodealliance/lucet" | ||
license = "Apache-2.0 WITH LLVM-exception" | ||
categories = ["wasm"] | ||
authors = ["Lucet team <[email protected]>"] | ||
edition = "2018" | ||
|
||
[lib] | ||
proc-macro = true | ||
|
||
[dependencies] | ||
syn = { version = "1.0", features = ["full"] } | ||
quote = "1.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
extern crate proc_macro; | ||
use proc_macro::TokenStream; | ||
use quote::quote; | ||
use syn::spanned::Spanned; | ||
|
||
/// This attribute generates a Lucet hostcall from a standalone Rust function that takes a `&mut | ||
/// Vmctx` as its first argument. | ||
/// | ||
/// It is important to use this attribute for hostcalls, rather than exporting them | ||
/// directly. Otherwise the behavior of instance termination and timeouts are | ||
/// undefined. Additionally, the attribute makes the resulting function `unsafe extern "C"` | ||
/// regardless of how the function is defined, as this ABI is required for all hostcalls. | ||
/// | ||
/// In most cases, you will want to also provide the `#[no_mangle]` attribute and `pub` visibility | ||
/// in order for the hostcall to be exported from the final executable. | ||
/// | ||
/// ```ignore | ||
/// #[lucet_hostcall] | ||
/// #[no_mangle] | ||
/// pub fn yield_5(vmctx: &mut Vmctx) { | ||
/// vmctx.yield_val(5); | ||
/// } | ||
/// ``` | ||
/// | ||
/// Note that `lucet-runtime` must be a dependency of any crate where this attribute is used, and it | ||
/// may not be renamed (this restriction may be lifted once [this | ||
/// issue](https://github.com/rust-lang/rust/issues/54363) is resolved). | ||
#[proc_macro_attribute] | ||
pub fn lucet_hostcall(_attr: TokenStream, item: TokenStream) -> TokenStream { | ||
// determine whether we need to import from `lucet_runtime_internals`; this is useful if we want | ||
// to define a hostcall for a target (or tests, more concretely) that doesn't depend on | ||
// `lucet-runtime` | ||
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(); | ||
|
||
// use the same attributes and visibility as the impl hostcall | ||
let attrs = hostcall.attrs.clone(); | ||
let vis = hostcall.vis.clone(); | ||
|
||
// remove #[no_mangle] from the attributes of the impl hostcall if it's there | ||
hostcall.attrs = attrs | ||
.iter() | ||
.filter(|attr| !attr.path.is_ident("no_mangle")) | ||
.cloned() | ||
.collect(); | ||
// make the impl hostcall private | ||
hostcall.vis = syn::Visibility::Inherited; | ||
|
||
// modify the type signature of the exported raw hostcall based on the original signature | ||
let mut raw_sig = hostcall.sig.clone(); | ||
|
||
// hostcalls are always unsafe | ||
raw_sig.unsafety = Some(syn::Token![unsafe](raw_sig.span())); | ||
|
||
// hostcalls are always extern "C" | ||
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 } | ||
}; | ||
|
||
// replace the first argument to the raw hostcall with the vmctx pointer | ||
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; | ||
} | ||
|
||
// the args after the first to provide to the hostcall impl | ||
let impl_args = hostcall | ||
.sig | ||
.inputs | ||
.iter() | ||
.skip(1) | ||
.map(|arg| match arg { | ||
syn::FnArg::Receiver(_) => { | ||
// this case is an error, but humor the token stream so it will produce a nicer | ||
// error later | ||
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() | ||
} |
Oops, something went wrong.