wit_bindgen_rt/
lib.rs

1#![no_std]
2
3#[cfg(feature = "async")]
4extern crate std;
5
6extern crate alloc;
7
8use alloc::alloc::Layout;
9use core::ptr::{self, NonNull};
10
11// Re-export `bitflags` so that we can reference it from macros.
12#[cfg(feature = "bitflags")]
13#[doc(hidden)]
14pub use bitflags;
15
16/// For more information about this see `./ci/rebuild-libwit-bindgen-cabi.sh`.
17#[cfg(not(target_env = "p2"))]
18mod wit_bindgen_cabi;
19
20/// This function is called from generated bindings and will be deleted by
21/// the linker. The purpose of this function is to force a reference to the
22/// symbol `cabi_realloc` to make its way through to the final linker
23/// command line. That way `wasm-ld` will pick it up, see it needs to be
24/// exported, and then export it.
25///
26/// For more information about this see `./ci/rebuild-libwit-bindgen-cabi.sh`.
27pub fn maybe_link_cabi_realloc() {
28    #[cfg(all(target_family = "wasm", not(target_env = "p2")))]
29    {
30        extern "C" {
31            fn cabi_realloc(
32                old_ptr: *mut u8,
33                old_len: usize,
34                align: usize,
35                new_len: usize,
36            ) -> *mut u8;
37        }
38        // Force the `cabi_realloc` symbol to be referenced from here. This
39        // is done with a `#[used]` Rust `static` to ensure that this
40        // reference makes it all the way to the linker before it's
41        // considered for garbage collection. When the linker sees it it'll
42        // remove this `static` here (due to it not actually being needed)
43        // but the linker will have at that point seen the `cabi_realloc`
44        // symbol and it should get exported.
45        #[used]
46        static _NAME_DOES_NOT_MATTER: unsafe extern "C" fn(
47            *mut u8,
48            usize,
49            usize,
50            usize,
51        ) -> *mut u8 = cabi_realloc;
52    }
53}
54
55/// NB: this function is called by a generated function in the
56/// `cabi_realloc` module above. It's otherwise never explicitly called.
57///
58/// For more information about this see `./ci/rebuild-libwit-bindgen-cabi.sh`.
59#[cfg(not(target_env = "p2"))]
60pub unsafe fn cabi_realloc(
61    old_ptr: *mut u8,
62    old_len: usize,
63    align: usize,
64    new_len: usize,
65) -> *mut u8 {
66    use self::alloc::alloc::{self, Layout};
67
68    let layout;
69    let ptr = if old_len == 0 {
70        if new_len == 0 {
71            return align as *mut u8;
72        }
73        layout = Layout::from_size_align_unchecked(new_len, align);
74        alloc::alloc(layout)
75    } else {
76        debug_assert_ne!(new_len, 0, "non-zero old_len requires non-zero new_len!");
77        layout = Layout::from_size_align_unchecked(old_len, align);
78        alloc::realloc(old_ptr, layout, new_len)
79    };
80    if ptr.is_null() {
81        // Print a nice message in debug mode, but in release mode don't
82        // pull in so many dependencies related to printing so just emit an
83        // `unreachable` instruction.
84        if cfg!(debug_assertions) {
85            alloc::handle_alloc_error(layout);
86        } else {
87            #[cfg(target_arch = "wasm32")]
88            core::arch::wasm32::unreachable();
89            #[cfg(not(target_arch = "wasm32"))]
90            unreachable!();
91        }
92    }
93    return ptr;
94}
95
96/// Provide a hook for generated export functions to run static constructors at
97/// most once.
98///
99/// wit-bindgen-rust generates a call to this function at the start of all
100/// component export functions. Importantly, it is not called as part of
101/// `cabi_realloc`, which is a *core* export func, but should not execute ctors.
102#[cfg(target_arch = "wasm32")]
103pub fn run_ctors_once() {
104    static mut RUN: bool = false;
105    unsafe {
106        if !RUN {
107            // This function is synthesized by `wasm-ld` to run all static
108            // constructors. wasm-ld will either provide an implementation
109            // of this symbol, or synthesize a wrapper around each
110            // exported function to (unconditionally) run ctors. By using
111            // this function, the linked module is opting into "manually"
112            // running ctors.
113            extern "C" {
114                fn __wasm_call_ctors();
115            }
116            __wasm_call_ctors();
117            RUN = true;
118        }
119    }
120}
121
122/// Support for using the Component Model Async ABI
123#[cfg(feature = "async")]
124pub mod async_support;
125
126/// Cleanup helper used to deallocate blocks of canonical ABI data from
127/// lowerings.
128pub struct Cleanup {
129    ptr: NonNull<u8>,
130    layout: Layout,
131}
132
133// Usage of the returned pointer is always unsafe and must abide by these
134// conventions, but this structure itself has no inherent reason to not be
135// send/sync.
136unsafe impl Send for Cleanup {}
137unsafe impl Sync for Cleanup {}
138
139impl Cleanup {
140    /// Allocates a chunk of memory with `layout` and returns an object to clean
141    /// it up.
142    ///
143    /// Always returns a pointer which is null if `layout` has size zero. The
144    /// optional cleanup returned will be present if `layout` has a non-zero
145    /// size. When dropped `Cleanup` will deallocate the pointer returned.
146    pub fn new(layout: Layout) -> (*mut u8, Option<Cleanup>) {
147        use alloc::alloc;
148
149        if layout.size() == 0 {
150            return (ptr::null_mut(), None);
151        }
152        let ptr = unsafe { alloc::alloc(layout) };
153        let ptr = match NonNull::new(ptr) {
154            Some(ptr) => ptr,
155            None => alloc::handle_alloc_error(layout),
156        };
157        (ptr.as_ptr(), Some(Cleanup { ptr, layout }))
158    }
159
160    /// Discards this cleanup to leak its memory or intentionally transfer
161    /// ownership to some other location.
162    pub fn forget(self) {
163        core::mem::forget(self);
164    }
165}
166
167impl Drop for Cleanup {
168    fn drop(&mut self) {
169        unsafe {
170            for i in 0..self.layout.size() {
171                *self.ptr.add(i).as_ptr() = 0xff;
172            }
173            alloc::alloc::dealloc(self.ptr.as_ptr(), self.layout);
174        }
175    }
176}