Skip to content

Commit 4e77a61

Browse files
authored
Remove critical-section requirement for no_std with atomics (#4322)
1 parent de22141 commit 4e77a61

File tree

5 files changed

+92
-15
lines changed

5 files changed

+92
-15
lines changed

.github/workflows/main.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ jobs:
121121
- run: cargo clippy --no-deps --no-default-features --target wasm32-unknown-unknown -p wasm-bindgen -Zbuild-std=core,alloc -- -D warnings
122122
- run: cargo clippy --no-deps --no-default-features --target wasm32-unknown-unknown -p js-sys -Zbuild-std=core,alloc -- -D warnings
123123
- run: cargo clippy --no-deps --no-default-features --target wasm32-unknown-unknown -p web-sys -Zbuild-std=core,alloc -- -D warnings
124-
- run: cargo clippy --no-deps --no-default-features --target wasm32-unknown-unknown -p wasm-bindgen-futures --features once_cell/critical-section -Zbuild-std=core,alloc -- -D warnings
125-
- run: cargo clippy --no-deps --no-default-features --target wasm32-unknown-unknown -p wasm-bindgen-test --features once_cell/critical-section -Zbuild-std=core,alloc -- -D warnings
124+
- run: cargo clippy --no-deps --no-default-features --target wasm32-unknown-unknown -p wasm-bindgen-futures -Zbuild-std=core,alloc -- -D warnings
125+
- run: cargo clippy --no-deps --no-default-features --target wasm32-unknown-unknown -p wasm-bindgen-test -Zbuild-std=core,alloc -- -D warnings
126126

127127
# Run `cargo clippy` over the project
128128
clippy_project:

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
* Add clear error message to communicate new feature resolver version requirements.
1414
[#4312](https://github.com/rustwasm/wasm-bindgen/pull/4312)
1515

16+
* Remove `once_cell/critical-section` requirement for `no_std` with atomics.
17+
[#4322](https://github.com/rustwasm/wasm-bindgen/pull/4322)
18+
1619
### Fixed
1720

1821
* Fix macro-hygiene for calls to `std::thread_local!`.

crates/backend/src/codegen.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,8 @@ impl TryToTokens for ast::LinkToModule {
201201
#program
202202
#extern_fn
203203

204-
static __VAL: #wasm_bindgen::__rt::once_cell::sync::Lazy<#wasm_bindgen::__rt::alloc::string::String> =
205-
#wasm_bindgen::__rt::once_cell::sync::Lazy::new(|| unsafe {
204+
static __VAL: #wasm_bindgen::__rt::LazyLock<#wasm_bindgen::__rt::alloc::string::String> =
205+
#wasm_bindgen::__rt::LazyLock::new(|| unsafe {
206206
<#wasm_bindgen::__rt::alloc::string::String as #wasm_bindgen::convert::FromWasmAbi>::from_abi(#name().join())
207207
});
208208

crates/test/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ std = ["wasm-bindgen/std", "js-sys/std", "wasm-bindgen-futures/std", "scoped-tls
1616
[dependencies]
1717
gg-alloc = { version = "1.0", optional = true }
1818
js-sys = { path = '../js-sys', version = '=0.3.74', default-features = false }
19-
once_cell = { version = "1.12", default-features = false }
2019
scoped-tls = { version = "1.0", optional = true }
2120
wasm-bindgen = { path = '../..', version = '=0.2.97', default-features = false }
2221
wasm-bindgen-futures = { path = '../futures', version = '=0.4.47', default-features = false }

src/lib.rs

Lines changed: 85 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,6 +1572,8 @@ pub mod __rt {
15721572
use core::convert::Infallible;
15731573
use core::mem;
15741574
use core::ops::{Deref, DerefMut};
1575+
#[cfg(all(target_feature = "atomics", not(feature = "std")))]
1576+
use core::sync::atomic::{AtomicU8, Ordering};
15751577

15761578
pub extern crate alloc;
15771579
pub extern crate core;
@@ -1582,16 +1584,6 @@ pub mod __rt {
15821584
use alloc::boxed::Box;
15831585
use alloc::rc::Rc;
15841586

1585-
pub mod once_cell {
1586-
#[cfg(any(target_feature = "atomics", feature = "std"))]
1587-
pub use once_cell::*;
1588-
1589-
#[cfg(all(not(target_feature = "atomics"), not(feature = "std")))]
1590-
pub mod sync {
1591-
pub use super::super::LazyCell as Lazy;
1592-
}
1593-
}
1594-
15951587
/// Wrapper around [`::once_cell::unsync::Lazy`] adding some compatibility methods with
15961588
/// [`std::thread::LocalKey`] and adding `Send + Sync` when `atomics` is not enabled.
15971589
#[cfg(not(feature = "std"))]
@@ -1633,6 +1625,89 @@ pub mod __rt {
16331625
}
16341626
}
16351627

1628+
#[cfg(feature = "std")]
1629+
pub use once_cell::sync::Lazy as LazyLock;
1630+
1631+
#[cfg(all(not(target_feature = "atomics"), not(feature = "std")))]
1632+
pub use LazyCell as LazyLock;
1633+
1634+
#[cfg(all(target_feature = "atomics", not(feature = "std")))]
1635+
pub struct LazyLock<T, F = fn() -> T> {
1636+
state: AtomicU8,
1637+
data: UnsafeCell<Data<T, F>>,
1638+
}
1639+
1640+
#[cfg(all(target_feature = "atomics", not(feature = "std")))]
1641+
enum Data<T, F> {
1642+
Value(T),
1643+
Init(F),
1644+
}
1645+
1646+
#[cfg(all(target_feature = "atomics", not(feature = "std")))]
1647+
unsafe impl<T, F> Sync for LazyLock<T, F> {}
1648+
1649+
#[cfg(all(target_feature = "atomics", not(feature = "std")))]
1650+
unsafe impl<T, F> Send for LazyLock<T, F> {}
1651+
1652+
#[cfg(all(target_feature = "atomics", not(feature = "std")))]
1653+
impl<T, F> LazyLock<T, F> {
1654+
const STATE_UNINIT: u8 = 0;
1655+
const STATE_INITIALIZING: u8 = 1;
1656+
const STATE_INIT: u8 = 2;
1657+
1658+
pub const fn new(init: F) -> LazyLock<T, F> {
1659+
Self {
1660+
state: AtomicU8::new(Self::STATE_UNINIT),
1661+
data: UnsafeCell::new(Data::Init(init)),
1662+
}
1663+
}
1664+
}
1665+
1666+
#[cfg(all(target_feature = "atomics", not(feature = "std")))]
1667+
impl<T> Deref for LazyLock<T> {
1668+
type Target = T;
1669+
1670+
fn deref(&self) -> &T {
1671+
let mut state = self.state.load(Ordering::Acquire);
1672+
1673+
loop {
1674+
match state {
1675+
Self::STATE_INIT => {
1676+
let Data::Value(value) = (unsafe { &*self.data.get() }) else {
1677+
unreachable!()
1678+
};
1679+
return value;
1680+
}
1681+
Self::STATE_UNINIT => {
1682+
if let Err(new_state) = self.state.compare_exchange_weak(
1683+
Self::STATE_UNINIT,
1684+
Self::STATE_INITIALIZING,
1685+
Ordering::Acquire,
1686+
Ordering::Relaxed,
1687+
) {
1688+
state = new_state;
1689+
continue;
1690+
}
1691+
1692+
let data = unsafe { &mut *self.data.get() };
1693+
let Data::Init(init) = data else {
1694+
unreachable!()
1695+
};
1696+
*data = Data::Value(init());
1697+
self.state.store(Self::STATE_INIT, Ordering::Release);
1698+
state = Self::STATE_INIT;
1699+
}
1700+
Self::STATE_INITIALIZING => {
1701+
// TODO: Block here if possible. This would require
1702+
// detecting if we can in the first place.
1703+
state = self.state.load(Ordering::Acquire);
1704+
}
1705+
_ => unreachable!(),
1706+
}
1707+
}
1708+
}
1709+
}
1710+
16361711
#[inline]
16371712
pub fn assert_not_null<T>(s: *mut T) {
16381713
if s.is_null() {

0 commit comments

Comments
 (0)