Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ mod path;
pub use path::name_package_module;
mod async_;
pub use async_::AsyncFilterSet;
pub mod symbol_name;

#[derive(Default, Copy, Clone, PartialEq, Eq, Debug)]
pub enum Direction {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use wit_bindgen_core::abi;
use crate::abi;

fn hexdigit(v: u32) -> char {
if v < 10 {
Expand Down
6 changes: 3 additions & 3 deletions crates/cpp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ use std::{
process::{Command, Stdio},
str::FromStr,
};
use symbol_name::{make_external_component, make_external_symbol};
use wit_bindgen_c::to_c_ident;
use wit_bindgen_core::{
Files, InterfaceGenerator, Source, Types, WorldGenerator,
abi::{self, AbiVariant, Bindgen, Bitcast, LiftLower, WasmSignature, WasmType},
name_package_module, uwrite, uwriteln,
name_package_module,
symbol_name::{make_external_component, make_external_symbol},
uwrite, uwriteln,
wit_parser::{
Alignment, ArchitectureSize, Docs, Function, FunctionKind, Handle, Int, InterfaceId, Param,
Resolve, SizeAlign, Stability, Type, TypeDef, TypeDefKind, TypeId, TypeOwner, WorldId,
Expand All @@ -24,7 +25,6 @@ use wit_bindgen_core::{
use wit_parser::TypeIdVisitor;

// mod wamr;
mod symbol_name;

pub const RESOURCE_IMPORT_BASE_CLASS_NAME: &str = "ResourceImportBase";
pub const RESOURCE_EXPORT_BASE_CLASS_NAME: &str = "ResourceExportBase";
Expand Down
9 changes: 9 additions & 0 deletions crates/guest-rust/macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@ impl Parse for Config {
Opt::MergeStructurallyEqualTypes(enable) => {
opts.merge_structurally_equal_types = Some(Some(enable.value()))
}
Opt::LinkNativeSymbols(enable) => {
opts.link_native_symbols = enable.value();
}
}
}
} else {
Expand Down Expand Up @@ -332,6 +335,7 @@ mod kw {
syn::custom_keyword!(debug);
syn::custom_keyword!(enable_method_chaining);
syn::custom_keyword!(merge_structurally_equal_types);
syn::custom_keyword!(link_native_symbols);
}

#[derive(Clone)]
Expand Down Expand Up @@ -416,6 +420,7 @@ enum Opt {
Debug(syn::LitBool),
EnableMethodChaining(syn::LitBool),
MergeStructurallyEqualTypes(syn::LitBool),
LinkNativeSymbols(syn::LitBool),
}

impl Parse for Opt {
Expand Down Expand Up @@ -623,6 +628,10 @@ impl Parse for Opt {
input.parse::<kw::merge_structurally_equal_types>()?;
input.parse::<Token![:]>()?;
Ok(Opt::MergeStructurallyEqualTypes(input.parse()?))
} else if l.peek(kw::link_native_symbols) {
input.parse::<kw::link_native_symbols>()?;
input.parse::<Token![:]>()?;
Ok(Opt::LinkNativeSymbols(input.parse()?))
} else {
Err(l.error())
}
Expand Down
18 changes: 18 additions & 0 deletions crates/guest-rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,24 @@ extern crate std;
/// // structurally equal, which is useful when import and export the same
/// // interface.
/// merge_structurally_equal_types: true,
///
/// // Make the same generated bindings usable on a native (non-wasm)
/// // target as well as on wasm32.
/// //
/// // Imports normally compile to `unreachable!()` off wasm32. With this
/// // enabled each one instead calls through a function pointer that a host
/// // installs at load time via a generated
/// // `__wit_bindgen_register_*` symbol, and exports additionally get a
/// // native symbol whose name encodes the characters a linker cannot
/// // accept. Both targets still build from one source.
/// //
/// // The registration symbols are prefixed with a hex-encoded
/// // `<package>/<world>` so that two `generate!` invocations in one crate
/// // don't collide. Binding the *same* world twice in one linkage unit
/// // still does; use `type_section_suffix` to tell them apart. See
/// // `wit_bindgen_rust::Opts::link_native_symbols` for the full list of
/// // symbols a host can expect.
/// link_native_symbols: true,
/// });
/// ```
///
Expand Down
2 changes: 1 addition & 1 deletion crates/guest-rust/src/rt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ pub fn maybe_link_cabi_realloc() {
/// `cabi_realloc` module above. It's otherwise never explicitly called.
///
/// For more information about this see `./ci/rebuild-libwit-bindgen-cabi.sh`.
#[cfg(any(target_env = "p1", target_env = ""))]
#[cfg(any(target_env = "p1", target_env = "", not(target_arch = "wasm32")))]
pub unsafe fn cabi_realloc(
old_ptr: *mut u8,
old_len: usize,
Expand Down
1 change: 1 addition & 0 deletions crates/rust/src/bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> {
&rust_name,
params,
results,
self.r#gen.r#gen.native_symbols(),
));
rust_name
}
Expand Down
150 changes: 94 additions & 56 deletions crates/rust/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::fmt::Write as _;
use std::mem;
use wit_bindgen_core::abi::{self, AbiVariant, LiftLower};
use wit_bindgen_core::{
AnonymousTypeGenerator, Source, TypeInfo, dealias, uwrite, uwriteln, wit_parser::*,
AnonymousTypeGenerator, Source, TypeInfo, dealias, symbol_name, uwrite, uwriteln, wit_parser::*,
};

pub struct InterfaceGenerator<'a> {
Expand Down Expand Up @@ -212,13 +212,15 @@ impl<'i> InterfaceGenerator<'i> {
"new",
&[abi::WasmType::Pointer],
&[abi::WasmType::I32],
self.r#gen.native_symbols(),
);
let import_rep = crate::declare_import(
&wasm_import_module,
&format!("[resource-rep]{resource_name}"),
"rep",
&[abi::WasmType::I32],
&[abi::WasmType::Pointer],
self.r#gen.native_symbols(),
);
uwriteln!(
self.src,
Expand Down Expand Up @@ -347,7 +349,6 @@ macro_rules! {macro_name} {{
};
self.generate_raw_cabi_export(func, &ty, "$($path_to_types)*", async_);
}
let export_prefix = self.r#gen.opts.export_prefix.as_deref().unwrap_or("");
for name in resources_to_drop {
let module = match self.identifier {
Identifier::Interface(_, key) => self.resolve.name_world_key(key),
Expand All @@ -356,23 +357,25 @@ macro_rules! {macro_name} {{
}
};
let camel = name.to_upper_camel_case();
uwriteln!(
self.src,
r#"
const _: () = {{
#[doc(hidden)]
#[unsafe(export_name = "{export_prefix}{module}#[dtor]{name}")]
#[allow(non_snake_case)]
unsafe extern "C" fn dtor(rep: *mut u8) {{
unsafe {{
$($path_to_types)*::{camel}::dtor::<
<$ty as $($path_to_types)*::Guest>::{camel}
>(rep)
for (cfg, symbol) in self.core_export_symbols(&format!("{module}#[dtor]{name}")) {
uwriteln!(
self.src,
r#"
const _: () = {{
#[doc(hidden)]
{cfg}#[unsafe(export_name = "{symbol}")]
#[allow(non_snake_case)]
unsafe extern "C" fn dtor(rep: *mut u8) {{
unsafe {{
$($path_to_types)*::{camel}::dtor::<
<$ty as $($path_to_types)*::Guest>::{camel}
>(rep)
}}
}}
}}
}};
"#
);
}};
"#
);
}
}
uwriteln!(self.src, "}};);");
uwriteln!(self.src, "}}");
Expand Down Expand Up @@ -1019,6 +1022,7 @@ fn abi_layout(&mut self) -> ::core::alloc::Layout {{
"call",
&sig.params,
&sig.results,
self.r#gen.native_symbols(),
);
let mut args = String::new();
for i in 0..params_lower.len() {
Expand Down Expand Up @@ -1281,60 +1285,93 @@ unsafe fn call_import(&mut self, _params: Self::ParamsLower, _results: *mut u8)
Identifier::World(_) => None,
Identifier::StreamOrFuturePayload => unreachable!(),
};
let export_prefix = self.r#gen.opts.export_prefix.as_deref().unwrap_or("");
let export_name = func.legacy_core_export_name(wasm_module_export_name.as_deref());
let export_name = if async_ {
format!("[async-lift]{export_name}")
} else {
export_name.to_string()
};
uwrite!(
self.src,
"\
#[unsafe(export_name = \"{export_prefix}{export_name}\")]
unsafe extern \"C\" fn export_{name_snake}\
",
);

let params = self.print_export_sig(func, async_);
self.push_str(" {\n");
uwriteln!(
self.src,
"unsafe {{ {path_to_self}::_export_{name_snake}_cabi::<{ty}>({}) }}",
params.join(", ")
);
self.push_str("}\n");

let export_prefix = self.r#gen.opts.export_prefix.as_deref().unwrap_or("");
if async_ {
for (cfg, symbol) in self.core_export_symbols(&export_name) {
uwrite!(
self.src,
"\
#[unsafe(export_name = \"{export_prefix}[callback]{export_name}\")]
unsafe extern \"C\" fn _callback_{name_snake}(event0: u32, event1: u32, event2: u32) -> u32 {{
unsafe {{
{path_to_self}::__callback_{name_snake}(event0, event1, event2)
}}
}}
"
);
} else if abi::guest_export_needs_post_return(self.resolve, func) {
uwrite!(
self.src,
"\
#[unsafe(export_name = \"{export_prefix}cabi_post_{export_name}\")]
unsafe extern \"C\" fn _post_return_{name_snake}\
"
{cfg}#[unsafe(export_name = \"{symbol}\")]
unsafe extern \"C\" fn export_{name_snake}\
",
);
let params = self.print_post_return_sig(func);
self.src.push_str("{\n");
let params = self.print_export_sig(func, async_);
self.push_str(" {\n");
uwriteln!(
self.src,
"unsafe {{ {path_to_self}::__post_return_{name_snake}::<{ty}>({}) }}",
"unsafe {{ {path_to_self}::_export_{name_snake}_cabi::<{ty}>({}) }}",
params.join(", ")
);
self.src.push_str("}\n");
self.push_str("}\n");
}

if async_ {
for (cfg, symbol) in self.core_export_symbols(&format!("[callback]{export_name}")) {
uwrite!(
self.src,
"\
{cfg}#[unsafe(export_name = \"{symbol}\")]
unsafe extern \"C\" fn _callback_{name_snake}(event0: u32, event1: u32, event2: u32) -> u32 {{
unsafe {{
{path_to_self}::__callback_{name_snake}(event0, event1, event2)
}}
}}
"
);
}
} else if abi::guest_export_needs_post_return(self.resolve, func) {
for (cfg, symbol) in self.core_export_symbols(&format!("cabi_post_{export_name}")) {
uwrite!(
self.src,
"\
{cfg}#[unsafe(export_name = \"{symbol}\")]
unsafe extern \"C\" fn _post_return_{name_snake}\
"
);
let params = self.print_post_return_sig(func);
self.src.push_str("{\n");
uwriteln!(
self.src,
"unsafe {{ {path_to_self}::__post_return_{name_snake}::<{ty}>({}) }}",
params.join(", ")
);
self.src.push_str("}\n");
}
}
}

/// Returns each copy of a core export named `export_name` that needs to be
/// emitted, as `(cfg, symbol)`: the `cfg` attribute to gate the copy with
/// and the symbol to export it as.
///
/// Normally there's just one copy: the canonical ABI name with no `cfg`.
/// With `link_native_symbols` enabled a second, hex-encoded copy is emitted
/// for native targets as well, because native linkers reject the `:`, `/`,
/// `#`, `[` and `]` characters that canonical names contain. Names that
/// survive encoding unchanged (`$root` exports, for instance) are emitted
/// once with no `cfg` rather than twice.
fn core_export_symbols(&self, export_name: &str) -> Vec<(&'static str, String)> {
let prefix = self.r#gen.opts.export_prefix.as_deref().unwrap_or("");
let wasm = format!("{prefix}{export_name}");
if self.r#gen.native_symbols().is_none() {
return vec![("", wasm)];
}
let native = format!(
"{prefix}{}",
symbol_name::make_external_component(export_name)
);
if native == wasm {
return vec![("", wasm)];
}
vec![
("#[cfg(target_arch = \"wasm32\")]\n", wasm),
("#[cfg(not(target_arch = \"wasm32\"))]\n", native),
]
}

fn print_export_sig(&mut self, func: &Function, async_: bool) -> Vec<String> {
Expand Down Expand Up @@ -2952,6 +2989,7 @@ impl<'a> {camel}Borrow<'a>{{
"drop",
&[abi::WasmType::I32],
&[],
self.r#gen.native_symbols(),
);
uwriteln!(
self.src,
Expand Down
Loading
Loading