-
Notifications
You must be signed in to change notification settings - Fork 293
feat(rust) add native link option #1685
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
7c9d55a
a5172b7
820f88e
d07cc75
6f0dc4f
321ac67
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| 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 { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,33 +27,49 @@ macro_rules! rtdebug { | |
|
|
||
| /// Helper macro to deduplicate foreign definitions of wasm functions. | ||
| /// | ||
| /// This automatically imports when on wasm targets and then defines a dummy | ||
| /// panicking shim for native targets to support native compilation but fail at | ||
| /// runtime. | ||
| /// On wasm targets this declares the canonical ABI built-ins as ordinary | ||
| /// linker-resolved imports. On native targets each one instead becomes a shim | ||
| /// that asks the host's import resolver for its implementation on first call | ||
| /// (see `rt::native_imports`), identified by the same module and name, so the | ||
| /// generated code is the same on both targets and only who satisfies the | ||
| /// import differs. | ||
| macro_rules! extern_wasm { | ||
| ( | ||
| $(#[$extern_attr:meta])* | ||
| #[link(wasm_import_module = $module:literal)] | ||
| unsafe extern "C" { | ||
| $( | ||
| $(#[$func_attr:meta])* | ||
| $vis:vis fn $func_name:ident ( $($args:tt)* ) $(-> $ret:ty)?; | ||
| #[link_name = $name:literal] | ||
| $vis:vis fn $func_name:ident ( $($arg:ident : $ty:ty),* $(,)? ) $(-> $ret:ty)?; | ||
| )* | ||
| } | ||
| ) => { | ||
| $( | ||
| #[cfg(not(target_family = "wasm"))] | ||
| #[allow(unused, reason = "dummy shim for non-wasm compilation, never invoked")] | ||
| $vis unsafe fn $func_name($($args)*) $(-> $ret)? { | ||
| unreachable!(); | ||
| #[allow(dead_code, reason = "mirrors the wasm import set even if unused natively")] | ||
| $vis unsafe fn $func_name($($arg: $ty),*) $(-> $ret)? { | ||
| static CACHE: ::core::sync::atomic::AtomicPtr<()> = | ||
| ::core::sync::atomic::AtomicPtr::new(::core::ptr::null_mut()); | ||
| // Named so as not to shadow any parameter. | ||
| let mut __impl = CACHE.load(::core::sync::atomic::Ordering::Acquire); | ||
| if __impl.is_null() { | ||
| __impl = crate::rt::resolve_import( | ||
| crate::rt::native_imports::cstr(concat!($module, "\0")), | ||
| crate::rt::native_imports::cstr(concat!($name, "\0")), | ||
| ); | ||
| CACHE.store(__impl, ::core::sync::atomic::Ordering::Release); | ||
| } | ||
| let __func: unsafe extern "C" fn($($ty),*) $(-> $ret)? = | ||
| unsafe { ::core::mem::transmute(__impl) }; | ||
|
Comment on lines
+50
to
+62
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To reduce the size of the macro expansion here a bit, could this be restructured as: fn foo() {
static CACHE: ... = ...;
let ptr = $crate::rt::resolve_import(module, name, &CACHE);
unsafe { transmute::<A, B>(ptr)(...) }
}basically moving the |
||
| unsafe { __func($($arg),*) } | ||
| } | ||
| )* | ||
|
|
||
| #[cfg(target_family = "wasm")] | ||
| $(#[$extern_attr])* | ||
| #[link(wasm_import_module = $module)] | ||
| unsafe extern "C" { | ||
| $( | ||
| $(#[$func_attr])* | ||
| $vis fn $func_name($($args)*) $(-> $ret)?; | ||
| #[link_name = $name] | ||
| $vis fn $func_name($($arg: $ty),*) $(-> $ret)?; | ||
| )* | ||
| } | ||
| }; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -76,21 +76,42 @@ | |
| use alloc::boxed::Box; | ||
| use core::ffi::c_void; | ||
|
|
||
| extern_wasm! { | ||
| unsafe extern "C" { | ||
| /// Sets the global task pointer to `ptr` provided. Returns the previous | ||
| /// value. | ||
| /// | ||
| /// This function acts as a dual getter and a setter. To get the | ||
| /// current task pointer a dummy `ptr` can be provided (e.g. NULL) and then | ||
| /// it's passed back when you're done working with it. When setting the | ||
| /// current task pointer it's recommended to call this and then call it | ||
| /// again with the previous value when the tasks's work is done. | ||
| /// | ||
| /// For executors they need to ensure that the `ptr` passed in lives for | ||
| /// the entire lifetime of the component model task. | ||
| pub fn wasip3_task_set(ptr: *mut wasip3_task) -> *mut wasip3_task; | ||
| } | ||
| #[cfg(target_family = "wasm")] | ||
| unsafe extern "C" { | ||
| /// Sets the global task pointer to `ptr` provided. Returns the previous | ||
| /// value. | ||
| /// | ||
| /// This function acts as a dual getter and a setter. To get the | ||
| /// current task pointer a dummy `ptr` can be provided (e.g. NULL) and then | ||
| /// it's passed back when you're done working with it. When setting the | ||
| /// current task pointer it's recommended to call this and then call it | ||
| /// again with the previous value when the tasks's work is done. | ||
| /// | ||
| /// For executors they need to ensure that the `ptr` passed in lives for | ||
| /// the entire lifetime of the component model task. | ||
| pub fn wasip3_task_set(ptr: *mut wasip3_task) -> *mut wasip3_task; | ||
| } | ||
|
|
||
| /// Native counterpart of the C-defined `wasip3_task_set` above. Uses | ||
| /// thread local so there is no possible panic on multi thread when polling | ||
| /// two async exports at the same time. | ||
| #[cfg(all(not(target_family = "wasm"), feature = "std"))] | ||
| pub unsafe fn wasip3_task_set(ptr: *mut wasip3_task) -> *mut wasip3_task { | ||
| use core::cell::Cell; | ||
| std::thread_local!( | ||
| static CURRENT: Cell<*mut wasip3_task> = const { Cell::new(core::ptr::null_mut()) } | ||
| ); | ||
| CURRENT.with(|current| current.replace(ptr)) | ||
| } | ||
|
Comment on lines
+94
to
+105
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW the purpose of this symbol on wasm was to specifically have a weak definition to handle cases where imports are using one version of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i believe it can also happen with |
||
|
|
||
| /// Without `std` there are no thread-locals on stable Rust, so this falls | ||
| /// back to one global slot, which requires the host to not poll two async | ||
| /// exports at the same time. | ||
| #[cfg(all(not(target_family = "wasm"), not(feature = "std")))] | ||
| pub unsafe fn wasip3_task_set(ptr: *mut wasip3_task) -> *mut wasip3_task { | ||
| use core::sync::atomic::{AtomicPtr, Ordering}; | ||
| static CURRENT: AtomicPtr<wasip3_task> = AtomicPtr::new(core::ptr::null_mut()); | ||
| CURRENT.swap(ptr, Ordering::AcqRel) | ||
| } | ||
|
Comment on lines
+107
to
115
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm kind of hesitant to do this sort of fallback because sometimes it's appropriate and sometimes not. Would it be possible to somehow hook this up into the resolver for native? |
||
|
|
||
| /// The first version of `wasip3_task` which implies the existence of the | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 = ""))] | ||
|
BjornTheProgrammer marked this conversation as resolved.
|
||
| #[cfg(any(target_env = "p1", target_env = "", not(target_arch = "wasm32")))] | ||
| pub unsafe fn cabi_realloc( | ||
| old_ptr: *mut u8, | ||
| old_len: usize, | ||
|
|
@@ -192,6 +192,12 @@ pub unsafe fn cabi_realloc( | |
| return ptr; | ||
| } | ||
|
|
||
| #[cfg(not(target_arch = "wasm32"))] | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mind switching to |
||
| mod native_imports; | ||
|
|
||
| #[cfg(not(target_arch = "wasm32"))] | ||
| pub use native_imports::{ImportResolver, resolve_import}; | ||
|
|
||
| /// Provide a hook for generated export functions to run static constructors at | ||
| /// most once. | ||
| /// | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit wary to document too much here because this crate is sort of only half the story. Could the section here be generally reworded to say "things compile, but won't work by default. If you want things to work go to this URL over here for more information" where that URL is either one you host or some
*.mdin this repo