Skip to content

Commit a3c9ef7

Browse files
Auto merge of #143881 - orlp:once-state-repr, r=<try>
Use zero for initialized Once state By re-labeling which integer represents which internal state for `Once` we can ensure that the initialized state is the all-zero state. This is beneficial because some CPU architectures (such as Arm) have specialized instructions to specifically branch on non-zero, and checking for the initialized state is by far the most important operation. As an example, take this: ```rust use std::sync::atomic::{AtomicU32, Ordering}; const INIT: u32 = 3; #[inline(never)] #[cold] pub fn slow(state: &AtomicU32) { state.store(INIT, Ordering::Release); } pub fn ensure_init(state: &AtomicU32) { if state.load(Ordering::Acquire) != INIT { slow(state) } } ``` If `INIT` is 3 (as is currently the state for `Once`), we see the following assembly on `aarch64-apple-darwin`: ```asm example::ensure_init::h332061368366e313: ldapr w8, [x0] cmp w8, #3 b.ne LBB1_2 ret LBB1_2: b example::slow::ha042bd6a4f33724e ``` By changing the `INIT` state to zero we get the following: ```asm example::ensure_init::h332061368366e313: ldapr w8, [x0] cbnz w8, LBB1_2 ret LBB1_2: b example::slow::ha042bd6a4f33724e ``` So this PR saves 1 instruction every time a `LazyLock` gets accessed on platforms such as these. try-job: x86_64-msvc-*
2 parents d2baa49 + a2d4139 commit a3c9ef7

File tree

2 files changed

+8
-8
lines changed

2 files changed

+8
-8
lines changed

library/std/src/sys/sync/once/futex.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ use crate::sys::futex::{Futex, Primitive, futex_wait, futex_wake_all};
88
// This means we only need one atomic value with 4 states:
99

1010
/// No initialization has run yet, and no thread is currently using the Once.
11-
const INCOMPLETE: Primitive = 0;
11+
const INCOMPLETE: Primitive = 3;
1212
/// Some thread has previously attempted to initialize the Once, but it panicked,
1313
/// so the Once is now poisoned. There are no other threads currently accessing
1414
/// this Once.
15-
const POISONED: Primitive = 1;
15+
const POISONED: Primitive = 2;
1616
/// Some thread is currently attempting to run initialization. It may succeed,
1717
/// so all future threads need to wait for it to finish.
18-
const RUNNING: Primitive = 2;
18+
const RUNNING: Primitive = 1;
1919
/// Initialization has completed and all future calls should finish immediately.
20-
const COMPLETE: Primitive = 3;
20+
const COMPLETE: Primitive = 0;
2121

2222
// An additional bit indicates whether there are waiting threads:
2323

library/std/src/sys/sync/once/queue.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,10 @@ pub struct OnceState {
7575

7676
// Four states that a Once can be in, encoded into the lower bits of
7777
// `state_and_queue` in the Once structure.
78-
const INCOMPLETE: usize = 0x0;
79-
const POISONED: usize = 0x1;
80-
const RUNNING: usize = 0x2;
81-
const COMPLETE: usize = 0x3;
78+
const INCOMPLETE: usize = 0x3;
79+
const POISONED: usize = 0x2;
80+
const RUNNING: usize = 0x1;
81+
const COMPLETE: usize = 0x0;
8282

8383
// Mask to learn about the state. All other bits are the queue of waiters if
8484
// this is in the RUNNING state.

0 commit comments

Comments
 (0)