wasm_bindgen/rt/
mod.rs

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