wasm_bindgen/rt/
mod.rs

1use crate::JsValue;
2use core::borrow::{Borrow, BorrowMut};
3use core::cell::{Cell, UnsafeCell};
4use core::convert::Infallible;
5use core::mem;
6use core::ops::{Deref, DerefMut};
7#[cfg(target_feature = "atomics")]
8use core::sync::atomic::{AtomicU8, Ordering};
9
10use alloc::alloc::{alloc, dealloc, realloc, Layout};
11use alloc::boxed::Box;
12use alloc::rc::Rc;
13use once_cell::unsync::Lazy;
14
15pub extern crate alloc;
16pub extern crate core;
17#[cfg(feature = "std")]
18pub extern crate std;
19
20pub mod marker;
21
22pub use wasm_bindgen_macro::BindgenedStruct;
23
24/// Wrapper around [`Lazy`] adding `Send + Sync` when `atomics` is not enabled.
25pub struct LazyCell<T, F = fn() -> T>(Wrapper<Lazy<T, F>>);
26
27struct Wrapper<T>(T);
28
29unsafe impl<T> Sync for Wrapper<T> {}
30
31unsafe impl<T> Send for Wrapper<T> {}
32
33impl<T, F> LazyCell<T, F> {
34    pub const fn new(init: F) -> LazyCell<T, F> {
35        Self(Wrapper(Lazy::new(init)))
36    }
37}
38
39impl<T, F: FnOnce() -> T> LazyCell<T, F> {
40    pub(crate) fn try_with<R>(
41        &self,
42        f: impl FnOnce(&T) -> R,
43    ) -> Result<R, core::convert::Infallible> {
44        Ok(f(&self.0 .0))
45    }
46
47    pub fn force(this: &Self) -> &T {
48        &this.0 .0
49    }
50}
51
52impl<T> Deref for LazyCell<T> {
53    type Target = T;
54
55    fn deref(&self) -> &T {
56        ::once_cell::unsync::Lazy::force(&self.0 .0)
57    }
58}
59
60#[cfg(not(target_feature = "atomics"))]
61pub use LazyCell as LazyLock;
62
63#[cfg(target_feature = "atomics")]
64pub struct LazyLock<T, F = fn() -> T> {
65    state: AtomicU8,
66    data: Wrapper<UnsafeCell<Data<T, F>>>,
67}
68
69#[cfg(target_feature = "atomics")]
70enum Data<T, F> {
71    Value(T),
72    Init(F),
73}
74
75#[cfg(target_feature = "atomics")]
76impl<T, F> LazyLock<T, F> {
77    const STATE_UNINIT: u8 = 0;
78    const STATE_INITIALIZING: u8 = 1;
79    const STATE_INIT: u8 = 2;
80
81    pub const fn new(init: F) -> LazyLock<T, F> {
82        Self {
83            state: AtomicU8::new(Self::STATE_UNINIT),
84            data: Wrapper(UnsafeCell::new(Data::Init(init))),
85        }
86    }
87}
88
89#[cfg(target_feature = "atomics")]
90impl<T> Deref for LazyLock<T> {
91    type Target = T;
92
93    fn deref(&self) -> &T {
94        let mut state = self.state.load(Ordering::Acquire);
95
96        loop {
97            match state {
98                Self::STATE_INIT => {
99                    let Data::Value(value) = (unsafe { &*self.data.0.get() }) else {
100                        unreachable!()
101                    };
102                    return value;
103                }
104                Self::STATE_UNINIT => {
105                    if let Err(new_state) = self.state.compare_exchange_weak(
106                        Self::STATE_UNINIT,
107                        Self::STATE_INITIALIZING,
108                        Ordering::Acquire,
109                        Ordering::Relaxed,
110                    ) {
111                        state = new_state;
112                        continue;
113                    }
114
115                    let data = unsafe { &mut *self.data.0.get() };
116                    let Data::Init(init) = data else {
117                        unreachable!()
118                    };
119                    *data = Data::Value(init());
120                    self.state.store(Self::STATE_INIT, Ordering::Release);
121                    state = Self::STATE_INIT;
122                }
123                Self::STATE_INITIALIZING => {
124                    // TODO: Block here if possible. This would require
125                    // detecting if we can in the first place.
126                    state = self.state.load(Ordering::Acquire);
127                }
128                _ => unreachable!(),
129            }
130        }
131    }
132}
133
134#[macro_export]
135#[doc(hidden)]
136#[cfg(not(target_feature = "atomics"))]
137macro_rules! __wbindgen_thread_local {
138    ($wasm_bindgen:tt, $actual_ty:ty) => {{
139        static _VAL: $wasm_bindgen::__rt::LazyCell<$actual_ty> =
140            $wasm_bindgen::__rt::LazyCell::new(init);
141        $wasm_bindgen::JsThreadLocal { __inner: &_VAL }
142    }};
143}
144
145#[macro_export]
146#[doc(hidden)]
147#[cfg(target_feature = "atomics")]
148#[allow_internal_unstable(thread_local)]
149macro_rules! __wbindgen_thread_local {
150    ($wasm_bindgen:tt, $actual_ty:ty) => {{
151        #[thread_local]
152        static _VAL: $wasm_bindgen::__rt::LazyCell<$actual_ty> =
153            $wasm_bindgen::__rt::LazyCell::new(init);
154        $wasm_bindgen::JsThreadLocal {
155            __inner: || unsafe { $wasm_bindgen::__rt::LazyCell::force(&_VAL) as *const $actual_ty },
156        }
157    }};
158}
159
160#[macro_export]
161#[doc(hidden)]
162#[cfg(not(wasm_bindgen_unstable_test_coverage))]
163macro_rules! __wbindgen_coverage {
164    ($item:item) => {
165        $item
166    };
167}
168
169#[macro_export]
170#[doc(hidden)]
171#[cfg(wasm_bindgen_unstable_test_coverage)]
172#[allow_internal_unstable(coverage_attribute)]
173macro_rules! __wbindgen_coverage {
174    ($item:item) => {
175        #[coverage(off)]
176        $item
177    };
178}
179
180#[inline]
181pub fn assert_not_null<T>(s: *mut T) {
182    if s.is_null() {
183        throw_null();
184    }
185}
186
187#[cold]
188#[inline(never)]
189fn throw_null() -> ! {
190    super::throw_str("null pointer passed to rust");
191}
192
193/// A vendored version of `RefCell` from the standard library.
194///
195/// Now why, you may ask, would we do that? Surely `RefCell` in libstd is
196/// quite good. And you're right, it is indeed quite good! Functionally
197/// nothing more is needed from `RefCell` in the standard library but for
198/// now this crate is also sort of optimizing for compiled code size.
199///
200/// One major factor to larger binaries in Rust is when a panic happens.
201/// Panicking in the standard library involves a fair bit of machinery
202/// (formatting, panic hooks, synchronization, etc). It's all worthwhile if
203/// you need it but for something like `WasmRefCell` here we don't actually
204/// need all that!
205///
206/// This is just a wrapper around all Rust objects passed to JS intended to
207/// guard accidental reentrancy, so this vendored version is intended solely
208/// to not panic in libstd. Instead when it "panics" it calls our `throw`
209/// function in this crate which raises an error in JS.
210pub struct WasmRefCell<T: ?Sized> {
211    borrow: Cell<usize>,
212    value: UnsafeCell<T>,
213}
214
215impl<T: ?Sized> WasmRefCell<T> {
216    pub fn new(value: T) -> WasmRefCell<T>
217    where
218        T: Sized,
219    {
220        WasmRefCell {
221            value: UnsafeCell::new(value),
222            borrow: Cell::new(0),
223        }
224    }
225
226    pub fn get_mut(&mut self) -> &mut T {
227        unsafe { &mut *self.value.get() }
228    }
229
230    pub fn borrow(&self) -> Ref<T> {
231        unsafe {
232            if self.borrow.get() == usize::MAX {
233                borrow_fail();
234            }
235            self.borrow.set(self.borrow.get() + 1);
236            Ref {
237                value: &*self.value.get(),
238                borrow: &self.borrow,
239            }
240        }
241    }
242
243    pub fn borrow_mut(&self) -> RefMut<T> {
244        unsafe {
245            if self.borrow.get() != 0 {
246                borrow_fail();
247            }
248            self.borrow.set(usize::MAX);
249            RefMut {
250                value: &mut *self.value.get(),
251                borrow: &self.borrow,
252            }
253        }
254    }
255
256    pub fn into_inner(self) -> T
257    where
258        T: Sized,
259    {
260        self.value.into_inner()
261    }
262}
263
264pub struct Ref<'b, T: ?Sized + 'b> {
265    value: &'b T,
266    borrow: &'b Cell<usize>,
267}
268
269impl<T: ?Sized> Deref for Ref<'_, T> {
270    type Target = T;
271
272    #[inline]
273    fn deref(&self) -> &T {
274        self.value
275    }
276}
277
278impl<T: ?Sized> Borrow<T> for Ref<'_, T> {
279    #[inline]
280    fn borrow(&self) -> &T {
281        self.value
282    }
283}
284
285impl<T: ?Sized> Drop for Ref<'_, T> {
286    fn drop(&mut self) {
287        self.borrow.set(self.borrow.get() - 1);
288    }
289}
290
291pub struct RefMut<'b, T: ?Sized + 'b> {
292    value: &'b mut T,
293    borrow: &'b Cell<usize>,
294}
295
296impl<T: ?Sized> Deref for RefMut<'_, T> {
297    type Target = T;
298
299    #[inline]
300    fn deref(&self) -> &T {
301        self.value
302    }
303}
304
305impl<T: ?Sized> DerefMut for RefMut<'_, T> {
306    #[inline]
307    fn deref_mut(&mut self) -> &mut T {
308        self.value
309    }
310}
311
312impl<T: ?Sized> Borrow<T> for RefMut<'_, T> {
313    #[inline]
314    fn borrow(&self) -> &T {
315        self.value
316    }
317}
318
319impl<T: ?Sized> BorrowMut<T> for RefMut<'_, T> {
320    #[inline]
321    fn borrow_mut(&mut self) -> &mut T {
322        self.value
323    }
324}
325
326impl<T: ?Sized> Drop for RefMut<'_, T> {
327    fn drop(&mut self) {
328        self.borrow.set(0);
329    }
330}
331
332fn borrow_fail() -> ! {
333    super::throw_str(
334        "recursive use of an object detected which would lead to \
335		 unsafe aliasing in rust",
336    );
337}
338
339/// A type that encapsulates an `Rc<WasmRefCell<T>>` as well as a `Ref`
340/// to the contents of that `WasmRefCell`.
341///
342/// The `'static` requirement is an unfortunate consequence of how this
343/// is implemented.
344pub struct RcRef<T: ?Sized + 'static> {
345    // The 'static is a lie.
346    //
347    // We could get away without storing this, since we're in the same module as
348    // `WasmRefCell` and can directly manipulate its `borrow`, but I'm considering
349    // turning it into a wrapper around `std`'s `RefCell` to reduce `unsafe` in
350    // which case that would stop working. This also requires less `unsafe` as is.
351    //
352    // It's important that this goes before `Rc` so that it gets dropped first.
353    ref_: Ref<'static, T>,
354    _rc: Rc<WasmRefCell<T>>,
355}
356
357impl<T: ?Sized> RcRef<T> {
358    pub fn new(rc: Rc<WasmRefCell<T>>) -> Self {
359        let ref_ = unsafe { (*Rc::as_ptr(&rc)).borrow() };
360        Self { _rc: rc, ref_ }
361    }
362}
363
364impl<T: ?Sized> Deref for RcRef<T> {
365    type Target = T;
366
367    #[inline]
368    fn deref(&self) -> &T {
369        &self.ref_
370    }
371}
372
373impl<T: ?Sized> Borrow<T> for RcRef<T> {
374    #[inline]
375    fn borrow(&self) -> &T {
376        &self.ref_
377    }
378}
379
380/// A type that encapsulates an `Rc<WasmRefCell<T>>` as well as a
381/// `RefMut` to the contents of that `WasmRefCell`.
382///
383/// The `'static` requirement is an unfortunate consequence of how this
384/// is implemented.
385pub struct RcRefMut<T: ?Sized + 'static> {
386    ref_: RefMut<'static, T>,
387    _rc: Rc<WasmRefCell<T>>,
388}
389
390impl<T: ?Sized> RcRefMut<T> {
391    pub fn new(rc: Rc<WasmRefCell<T>>) -> Self {
392        let ref_ = unsafe { (*Rc::as_ptr(&rc)).borrow_mut() };
393        Self { _rc: rc, ref_ }
394    }
395}
396
397impl<T: ?Sized> Deref for RcRefMut<T> {
398    type Target = T;
399
400    #[inline]
401    fn deref(&self) -> &T {
402        &self.ref_
403    }
404}
405
406impl<T: ?Sized> DerefMut for RcRefMut<T> {
407    #[inline]
408    fn deref_mut(&mut self) -> &mut T {
409        &mut self.ref_
410    }
411}
412
413impl<T: ?Sized> Borrow<T> for RcRefMut<T> {
414    #[inline]
415    fn borrow(&self) -> &T {
416        &self.ref_
417    }
418}
419
420impl<T: ?Sized> BorrowMut<T> for RcRefMut<T> {
421    #[inline]
422    fn borrow_mut(&mut self) -> &mut T {
423        &mut self.ref_
424    }
425}
426
427#[no_mangle]
428pub extern "C" fn __wbindgen_malloc(size: usize, align: usize) -> *mut u8 {
429    if let Ok(layout) = Layout::from_size_align(size, align) {
430        unsafe {
431            if layout.size() > 0 {
432                let ptr = alloc(layout);
433                if !ptr.is_null() {
434                    return ptr;
435                }
436            } else {
437                return align as *mut u8;
438            }
439        }
440    }
441
442    malloc_failure();
443}
444
445#[no_mangle]
446pub unsafe extern "C" fn __wbindgen_realloc(
447    ptr: *mut u8,
448    old_size: usize,
449    new_size: usize,
450    align: usize,
451) -> *mut u8 {
452    debug_assert!(old_size > 0);
453    debug_assert!(new_size > 0);
454    if let Ok(layout) = Layout::from_size_align(old_size, align) {
455        let ptr = realloc(ptr, layout, new_size);
456        if !ptr.is_null() {
457            return ptr;
458        }
459    }
460    malloc_failure();
461}
462
463#[cold]
464fn malloc_failure() -> ! {
465    cfg_if::cfg_if! {
466        if #[cfg(debug_assertions)] {
467            super::throw_str("invalid malloc request")
468        } else if #[cfg(feature = "std")] {
469            std::process::abort();
470        } else if #[cfg(all(
471            target_arch = "wasm32",
472            any(target_os = "unknown", target_os = "none")
473        ))] {
474            core::arch::wasm32::unreachable();
475        } else {
476            unreachable!()
477        }
478    }
479}
480
481#[no_mangle]
482pub unsafe extern "C" fn __wbindgen_free(ptr: *mut u8, size: usize, align: usize) {
483    // This happens for zero-length slices, and in that case `ptr` is
484    // likely bogus so don't actually send this to the system allocator
485    if size == 0 {
486        return;
487    }
488    let layout = Layout::from_size_align_unchecked(size, align);
489    dealloc(ptr, layout);
490}
491
492/// This is a curious function necessary to get wasm-bindgen working today,
493/// and it's a bit of an unfortunate hack.
494///
495/// The general problem is that somehow we need the above two symbols to
496/// exist in the final output binary (__wbindgen_malloc and
497/// __wbindgen_free). These symbols may be called by JS for various
498/// bindings, so we for sure need to make sure they're exported.
499///
500/// The problem arises, though, when what if no Rust code uses the symbols?
501/// For all intents and purposes it looks to LLVM and the linker like the
502/// above two symbols are dead code, so they're completely discarded!
503///
504/// Specifically what happens is this:
505///
506/// * The above two symbols are generated into some object file inside of
507///   libwasm_bindgen.rlib
508/// * The linker, LLD, will not load this object file unless *some* symbol
509///   is loaded from the object. In this case, if the Rust code never calls
510///   __wbindgen_malloc or __wbindgen_free then the symbols never get linked
511///   in.
512/// * Later when `wasm-bindgen` attempts to use the symbols they don't
513///   exist, causing an error.
514///
515/// This function is a weird hack for this problem. We inject a call to this
516/// function in all generated code. Usage of this function should then
517/// ensure that the above two intrinsics are translated.
518///
519/// Due to how rustc creates object files this function (and anything inside
520/// it) will be placed into the same object file as the two intrinsics
521/// above. That means if this function is called and referenced we'll pull
522/// in the object file and link the intrinsics.
523///
524/// Ideas for how to improve this are most welcome!
525#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
526pub fn link_mem_intrinsics() {
527    crate::link::link_intrinsics();
528}
529
530#[cfg_attr(target_feature = "atomics", thread_local)]
531static GLOBAL_EXNDATA: Wrapper<Cell<[u32; 2]>> = Wrapper(Cell::new([0; 2]));
532
533#[no_mangle]
534pub unsafe extern "C" fn __wbindgen_exn_store(idx: u32) {
535    debug_assert_eq!(GLOBAL_EXNDATA.0.get()[0], 0);
536    GLOBAL_EXNDATA.0.set([1, idx]);
537}
538
539pub fn take_last_exception() -> Result<(), super::JsValue> {
540    let ret = if GLOBAL_EXNDATA.0.get()[0] == 1 {
541        Err(super::JsValue::_new(GLOBAL_EXNDATA.0.get()[1]))
542    } else {
543        Ok(())
544    };
545    GLOBAL_EXNDATA.0.set([0, 0]);
546    ret
547}
548
549/// An internal helper trait for usage in `#[wasm_bindgen]` on `async`
550/// functions to convert the return value of the function to
551/// `Result<JsValue, JsValue>` which is what we'll return to JS (where an
552/// error is a failed future).
553pub trait IntoJsResult {
554    fn into_js_result(self) -> Result<JsValue, JsValue>;
555}
556
557impl IntoJsResult for () {
558    fn into_js_result(self) -> Result<JsValue, JsValue> {
559        Ok(JsValue::undefined())
560    }
561}
562
563impl<T: Into<JsValue>> IntoJsResult for T {
564    fn into_js_result(self) -> Result<JsValue, JsValue> {
565        Ok(self.into())
566    }
567}
568
569impl<T: Into<JsValue>, E: Into<JsValue>> IntoJsResult for Result<T, E> {
570    fn into_js_result(self) -> Result<JsValue, JsValue> {
571        match self {
572            Ok(e) => Ok(e.into()),
573            Err(e) => Err(e.into()),
574        }
575    }
576}
577
578impl<E: Into<JsValue>> IntoJsResult for Result<(), E> {
579    fn into_js_result(self) -> Result<JsValue, JsValue> {
580        match self {
581            Ok(()) => Ok(JsValue::undefined()),
582            Err(e) => Err(e.into()),
583        }
584    }
585}
586
587/// An internal helper trait for usage in `#[wasm_bindgen(start)]`
588/// functions to throw the error (if it is `Err`).
589pub trait Start {
590    fn start(self);
591}
592
593impl Start for () {
594    #[inline]
595    fn start(self) {}
596}
597
598impl<E: Into<JsValue>> Start for Result<(), E> {
599    #[inline]
600    fn start(self) {
601        if let Err(e) = self {
602            crate::throw_val(e.into());
603        }
604    }
605}
606
607/// An internal helper struct for usage in `#[wasm_bindgen(main)]`
608/// functions to throw the error (if it is `Err`).
609pub struct MainWrapper<T>(pub Option<T>);
610
611pub trait Main {
612    fn __wasm_bindgen_main(&mut self);
613}
614
615impl Main for &mut &mut MainWrapper<()> {
616    #[inline]
617    fn __wasm_bindgen_main(&mut self) {}
618}
619
620impl Main for &mut &mut MainWrapper<Infallible> {
621    #[inline]
622    fn __wasm_bindgen_main(&mut self) {}
623}
624
625impl<E: Into<JsValue>> Main for &mut &mut MainWrapper<Result<(), E>> {
626    #[inline]
627    fn __wasm_bindgen_main(&mut self) {
628        if let Err(e) = self.0.take().unwrap() {
629            crate::throw_val(e.into());
630        }
631    }
632}
633
634impl<E: core::fmt::Debug> Main for &mut MainWrapper<Result<(), E>> {
635    #[inline]
636    fn __wasm_bindgen_main(&mut self) {
637        if let Err(e) = self.0.take().unwrap() {
638            crate::throw_str(&alloc::format!("{:?}", e));
639        }
640    }
641}
642
643pub const fn flat_len<T, const SIZE: usize>(slices: [&[T]; SIZE]) -> usize {
644    let mut len = 0;
645    let mut i = 0;
646    while i < slices.len() {
647        len += slices[i].len();
648        i += 1;
649    }
650    len
651}
652
653pub const fn flat_byte_slices<const RESULT_LEN: usize, const SIZE: usize>(
654    slices: [&[u8]; SIZE],
655) -> [u8; RESULT_LEN] {
656    let mut result = [0; RESULT_LEN];
657
658    let mut slice_index = 0;
659    let mut result_offset = 0;
660
661    while slice_index < slices.len() {
662        let mut i = 0;
663        let slice = slices[slice_index];
664        while i < slice.len() {
665            result[result_offset] = slice[i];
666            i += 1;
667            result_offset += 1;
668        }
669        slice_index += 1;
670    }
671
672    result
673}
674
675// NOTE: This method is used to encode u32 into a variable-length-integer during the compile-time .
676// Generally speaking, the length of the encoded variable-length-integer depends on the size of the integer
677// but the maximum capacity can be used here to simplify the amount of code during the compile-time .
678pub const fn encode_u32_to_fixed_len_bytes(value: u32) -> [u8; 5] {
679    let mut result: [u8; 5] = [0; 5];
680    let mut i = 0;
681    while i < 4 {
682        result[i] = ((value >> (7 * i)) | 0x80) as u8;
683        i += 1;
684    }
685    result[4] = (value >> (7 * 4)) as u8;
686    result
687}
688
689/// Trait for element types to implement `Into<JsValue>` for vectors of
690/// themselves, which isn't possible directly thanks to the orphan rule.
691pub trait VectorIntoJsValue: Sized {
692    fn vector_into_jsvalue(vector: Box<[Self]>) -> JsValue;
693}
694
695impl<T: VectorIntoJsValue> From<Box<[T]>> for JsValue {
696    fn from(vector: Box<[T]>) -> Self {
697        T::vector_into_jsvalue(vector)
698    }
699}
700
701pub fn js_value_vector_into_jsvalue<T: Into<JsValue>>(vector: Box<[T]>) -> JsValue {
702    let result = unsafe { JsValue::_new(super::__wbindgen_array_new()) };
703    for value in vector.into_vec() {
704        let js: JsValue = value.into();
705        unsafe { super::__wbindgen_array_push(result.idx, js.idx) }
706        // `__wbindgen_array_push` takes ownership over `js` and has already dropped it,
707        // so don't drop it again.
708        mem::forget(js);
709    }
710    result
711}