]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/wasm/alloc.rs
Update the stdsimd submodule
[rust.git] / src / libstd / sys / wasm / alloc.rs
1 // Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! This is an implementation of a global allocator on the wasm32 platform when
12 //! emscripten is not in use. In that situation there's no actual runtime for us
13 //! to lean on for allocation, so instead we provide our own!
14 //!
15 //! The wasm32 instruction set has two instructions for getting the current
16 //! amount of memory and growing the amount of memory. These instructions are the
17 //! foundation on which we're able to build an allocator, so we do so! Note that
18 //! the instructions are also pretty "global" and this is the "global" allocator
19 //! after all!
20 //!
21 //! The current allocator here is the `dlmalloc` crate which we've got included
22 //! in the rust-lang/rust repository as a submodule. The crate is a port of
23 //! dlmalloc.c from C to Rust and is basically just so we can have "pure Rust"
24 //! for now which is currently technically required (can't link with C yet).
25 //!
26 //! The crate itself provides a global allocator which on wasm has no
27 //! synchronization as there are no threads!
28
29 extern crate dlmalloc;
30
31 use alloc::{GlobalAlloc, Layout, System};
32
33 static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;
34
35 #[stable(feature = "alloc_system_type", since = "1.28.0")]
36 unsafe impl GlobalAlloc for System {
37     #[inline]
38     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
39         let _lock = lock::lock();
40         DLMALLOC.malloc(layout.size(), layout.align())
41     }
42
43     #[inline]
44     unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
45         let _lock = lock::lock();
46         DLMALLOC.calloc(layout.size(), layout.align())
47     }
48
49     #[inline]
50     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
51         let _lock = lock::lock();
52         DLMALLOC.free(ptr, layout.size(), layout.align())
53     }
54
55     #[inline]
56     unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
57         let _lock = lock::lock();
58         DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size)
59     }
60 }
61
62 #[cfg(target_feature = "atomics")]
63 mod lock {
64     use arch::wasm32;
65     use sync::atomic::{AtomicI32, Ordering::SeqCst};
66
67     static LOCKED: AtomicI32 = AtomicI32::new(0);
68
69     pub struct DropLock;
70
71     pub fn lock() -> DropLock {
72         loop {
73             if LOCKED.swap(1, SeqCst) == 0 {
74                 return DropLock
75             }
76             unsafe {
77                 let r = wasm32::i32_atomic_wait(
78                     &LOCKED as *const AtomicI32 as *mut i32,
79                     1,  // expected value
80                     -1, // timeout
81                 );
82                 debug_assert!(r == 0 || r == 1);
83             }
84         }
85     }
86
87     impl Drop for DropLock {
88         fn drop(&mut self) {
89             let r = LOCKED.swap(0, SeqCst);
90             debug_assert_eq!(r, 1);
91             unsafe {
92                 wasm32::atomic_notify(
93                     &LOCKED as *const AtomicI32 as *mut i32,
94                     1, // only one thread
95                 );
96             }
97         }
98     }
99 }
100
101 #[cfg(not(target_feature = "atomics"))]
102 mod lock {
103     #[inline]
104     pub fn lock() {} // no atomics, no threads, that's easy!
105 }