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}