From 2ea4a6482b98289b0486bf53ef8834e83541dd29 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 27 Nov 2024 16:52:44 +0100 Subject: [PATCH 1/6] restructure prefix_symbol attribute macro impl --- crates/c_api/macro/lib.rs | 53 +++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/crates/c_api/macro/lib.rs b/crates/c_api/macro/lib.rs index 075e0ca66e..21aafa5551 100644 --- a/crates/c_api/macro/lib.rs +++ b/crates/c_api/macro/lib.rs @@ -159,38 +159,43 @@ pub fn declare_ref(input: proc_macro::TokenStream) -> proc_macro::TokenStream { .into() } +macro_rules! bail { + ($message:literal) => {{ + return ::core::result::Result::Err($message.into()); + }}; +} + #[proc_macro_attribute] pub fn prefix_symbol( - _attributes: proc_macro::TokenStream, + attributes: proc_macro::TokenStream, input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { - let mut stream = TokenStream::from(input.clone()).into_iter(); - - let mut fn_name = None; - - while let Some(token) = stream.next() { - match token { - TokenTree::Ident(ref ident) if *ident == "fn" => { - if let Some(TokenTree::Ident(ident_name)) = stream.next() { - fn_name = Some(ident_name.to_string()); - break; - } - } - _ => continue, + match prefix_symbol_impl(attributes.into(), input.into()) { + Ok(result) => result.into(), + Err(message) => quote! { + ::core::compile_error!(#message) } + .into(), } +} - if fn_name.is_none() { - panic!("expected a valid Rust function definition, but it does not appear in: {input:?}"); +fn prefix_symbol_impl(attributes: TokenStream, input: TokenStream) -> Result { + let mut stream = input.clone().into_iter(); + let fn_token = stream.find(|tt| match tt { + TokenTree::Ident(ref ident) if *ident == "fn" => true, + _ => false, + }); + if fn_token.is_none() { + bail!("can only apply on `fn` items") } - - let prefixed_fn_name = format!("wasmi_{}", fn_name.unwrap()); - - let mut attr: proc_macro::TokenStream = quote! { + let Some(TokenTree::Ident(fn_ident)) = stream.next() else { + bail!("function name must follow `fn` keyword") + }; + let fn_name = fn_ident.to_string(); + let prefixed_fn_name = format!("wasmi_{}", fn_name); + Ok(quote! { #[export_name = #prefixed_fn_name] + #input } - .into(); - attr.extend(input); - - attr + .into()) } From 87a3cd07b2c990aba90454708de1fe47aff95610 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 27 Nov 2024 16:53:11 +0100 Subject: [PATCH 2/6] prefix_symbols: check that attributes is empty --- crates/c_api/macro/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/c_api/macro/lib.rs b/crates/c_api/macro/lib.rs index 21aafa5551..ba3eda901a 100644 --- a/crates/c_api/macro/lib.rs +++ b/crates/c_api/macro/lib.rs @@ -180,6 +180,9 @@ pub fn prefix_symbol( } fn prefix_symbol_impl(attributes: TokenStream, input: TokenStream) -> Result { + if !attributes.is_empty() { + bail!("err(prefix_symbol): attributes must be empty") + } let mut stream = input.clone().into_iter(); let fn_token = stream.find(|tt| match tt { TokenTree::Ident(ref ident) if *ident == "fn" => true, From fcca1d8b035dc762ddbd75112f4ae0ca4463e50d Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 27 Nov 2024 16:56:40 +0100 Subject: [PATCH 3/6] no longer attribute fixed wasmi APIs --- crates/c_api/src/store.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/crates/c_api/src/store.rs b/crates/c_api/src/store.rs index 21293e93d9..0b1f68d3bf 100644 --- a/crates/c_api/src/store.rs +++ b/crates/c_api/src/store.rs @@ -98,7 +98,6 @@ pub struct WasmiStoreData { /// /// Wraps [`>::new`](wasmi::Store::new). #[no_mangle] -#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)] pub extern "C" fn wasmi_store_new( engine: &wasm_engine_t, data: *mut ffi::c_void, @@ -122,7 +121,6 @@ pub extern "C" fn wasmi_store_new( /// /// It is the callers responsibility to provide a valid `self`. #[no_mangle] -#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)] pub extern "C" fn wasmi_store_context( store: &mut wasmi_store_t, ) -> StoreContextMut<'_, WasmiStoreData> { @@ -131,7 +129,6 @@ pub extern "C" fn wasmi_store_context( /// Returns a pointer to the foreign data of the Wasmi store context. #[no_mangle] -#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)] pub extern "C" fn wasmi_context_get_data( store: StoreContext<'_, WasmiStoreData>, ) -> *mut ffi::c_void { @@ -140,7 +137,6 @@ pub extern "C" fn wasmi_context_get_data( /// Sets the foreign data of the Wasmi store context. #[no_mangle] -#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)] pub extern "C" fn wasmi_context_set_data( mut store: StoreContextMut<'_, WasmiStoreData>, data: *mut ffi::c_void, @@ -156,7 +152,6 @@ pub extern "C" fn wasmi_context_set_data( /// /// If [`Store::get_fuel`] errors. #[no_mangle] -#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)] pub extern "C" fn wasmi_context_get_fuel( store: StoreContext<'_, WasmiStoreData>, fuel: &mut u64, @@ -174,7 +169,6 @@ pub extern "C" fn wasmi_context_get_fuel( /// /// If [`Store::set_fuel`] errors. #[no_mangle] -#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)] pub extern "C" fn wasmi_context_set_fuel( mut store: StoreContextMut<'_, WasmiStoreData>, fuel: u64, From 8c4ef690837e84a09cdbedaadc311ba540406cb4 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Wed, 27 Nov 2024 16:57:24 +0100 Subject: [PATCH 4/6] no longer prefix non-Wasm spec functions --- crates/c_api/macro/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/c_api/macro/lib.rs b/crates/c_api/macro/lib.rs index ba3eda901a..98d9051afd 100644 --- a/crates/c_api/macro/lib.rs +++ b/crates/c_api/macro/lib.rs @@ -195,6 +195,10 @@ fn prefix_symbol_impl(attributes: TokenStream, input: TokenStream) -> Result Date: Wed, 27 Nov 2024 17:04:02 +0100 Subject: [PATCH 5/6] clean-up macro implementation --- crates/c_api/macro/lib.rs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/crates/c_api/macro/lib.rs b/crates/c_api/macro/lib.rs index 98d9051afd..ba9b321f08 100644 --- a/crates/c_api/macro/lib.rs +++ b/crates/c_api/macro/lib.rs @@ -161,10 +161,25 @@ pub fn declare_ref(input: proc_macro::TokenStream) -> proc_macro::TokenStream { macro_rules! bail { ($message:literal) => {{ - return ::core::result::Result::Err($message.into()); + return ::core::result::Result::Err(Error($message.into())); }}; } +/// An error with its error message. +struct Error(String); + +impl Error { + /// Converts the [`Error`] into a `compile_error!` token stream. + fn to_compile_error(&self) -> proc_macro::TokenStream { + let message = &self.0; + quote! { ::core::compile_error!(#message) }.into() + } +} + +/// Applied on Rust `fn` items from the Wasm spec. +/// +/// Annotates the given function with `#[export_name = $func_name]` +/// where `$func_name` is the name of the given function. #[proc_macro_attribute] pub fn prefix_symbol( attributes: proc_macro::TokenStream, @@ -172,14 +187,11 @@ pub fn prefix_symbol( ) -> proc_macro::TokenStream { match prefix_symbol_impl(attributes.into(), input.into()) { Ok(result) => result.into(), - Err(message) => quote! { - ::core::compile_error!(#message) - } - .into(), + Err(error) => error.to_compile_error(), } } -fn prefix_symbol_impl(attributes: TokenStream, input: TokenStream) -> Result { +fn prefix_symbol_impl(attributes: TokenStream, input: TokenStream) -> Result { if !attributes.is_empty() { bail!("err(prefix_symbol): attributes must be empty") } @@ -197,7 +209,7 @@ fn prefix_symbol_impl(attributes: TokenStream, input: TokenStream) -> Result Date: Wed, 27 Nov 2024 17:08:11 +0100 Subject: [PATCH 6/6] apply clippy suggestions --- crates/c_api/macro/lib.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/crates/c_api/macro/lib.rs b/crates/c_api/macro/lib.rs index ba9b321f08..d2903748ca 100644 --- a/crates/c_api/macro/lib.rs +++ b/crates/c_api/macro/lib.rs @@ -196,10 +196,7 @@ fn prefix_symbol_impl(attributes: TokenStream, input: TokenStream) -> Result true, - _ => false, - }); + let fn_token = stream.find(|tt| matches!(tt, TokenTree::Ident(ref ident) if *ident == "fn")); if fn_token.is_none() { bail!("can only apply on `fn` items") } @@ -215,6 +212,5 @@ fn prefix_symbol_impl(attributes: TokenStream, input: TokenStream) -> Result