Skip to content

Commit 2138a97

Browse files
committed
Remove the LockMode enum and dispatch
1 parent 61cc00d commit 2138a97

File tree

3 files changed

+70
-95
lines changed

3 files changed

+70
-95
lines changed

compiler/rustc_data_structures/src/sharded.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::fx::{FxHashMap, FxHasher};
22
#[cfg(parallel_compiler)]
33
use crate::sync::{is_dyn_thread_safe, CacheAligned};
4-
use crate::sync::{Assume, Lock, LockGuard};
4+
use crate::sync::{Lock, LockGuard, Mode};
55
#[cfg(parallel_compiler)]
66
use itertools::Either;
77
use std::borrow::Borrow;
@@ -84,7 +84,7 @@ impl<T> Sharded<T> {
8484

8585
// SAFETY: We know `is_dyn_thread_safe` was false when creating the lock thus
8686
// `might_be_dyn_thread_safe` was also false.
87-
unsafe { single.lock_assume(Assume::NoSync) }
87+
unsafe { single.lock_assume(Mode::NoSync) }
8888
}
8989
#[cfg(parallel_compiler)]
9090
Self::Shards(..) => self.lock_shard_by_hash(make_hash(_val)),
@@ -107,7 +107,7 @@ impl<T> Sharded<T> {
107107

108108
// SAFETY: We know `is_dyn_thread_safe` was false when creating the lock thus
109109
// `might_be_dyn_thread_safe` was also false.
110-
unsafe { single.lock_assume(Assume::NoSync) }
110+
unsafe { single.lock_assume(Mode::NoSync) }
111111
}
112112
#[cfg(parallel_compiler)]
113113
Self::Shards(shards) => {
@@ -118,7 +118,7 @@ impl<T> Sharded<T> {
118118
// always inbounds.
119119
// SAFETY (lock_assume_sync): We know `is_dyn_thread_safe` was true when creating
120120
// the lock thus `might_be_dyn_thread_safe` was also true.
121-
unsafe { shards.get_unchecked(_i & (SHARDS - 1)).0.lock_assume(Assume::Sync) }
121+
unsafe { shards.get_unchecked(_i & (SHARDS - 1)).0.lock_assume(Mode::Sync) }
122122
}
123123
}
124124
}

compiler/rustc_data_structures/src/sync.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ use std::ops::{Deref, DerefMut};
4949
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
5050

5151
mod lock;
52-
pub use lock::{Assume, Lock, LockGuard};
52+
pub use lock::{Lock, LockGuard, Mode};
5353

5454
mod worker_local;
5555
pub use worker_local::{Registry, WorkerLocal};

compiler/rustc_data_structures/src/sync/lock.rs

+65-90
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,29 @@
77

88
use std::fmt;
99

10-
#[cfg(not(parallel_compiler))]
11-
pub use disabled::*;
1210
#[cfg(parallel_compiler)]
13-
pub use enabled::*;
11+
pub use maybe_sync::*;
12+
#[cfg(not(parallel_compiler))]
13+
pub use no_sync::*;
1414

1515
#[derive(Clone, Copy, PartialEq)]
16-
pub enum Assume {
16+
pub enum Mode {
1717
NoSync,
1818
Sync,
1919
}
2020

21-
mod enabled {
22-
use super::Assume;
21+
mod maybe_sync {
22+
use super::Mode;
2323
use crate::sync::mode;
2424
#[cfg(parallel_compiler)]
2525
use crate::sync::{DynSend, DynSync};
2626
use parking_lot::lock_api::RawMutex as _;
2727
use parking_lot::RawMutex;
2828
use std::cell::Cell;
2929
use std::cell::UnsafeCell;
30-
use std::hint::unreachable_unchecked;
3130
use std::intrinsics::unlikely;
3231
use std::marker::PhantomData;
32+
use std::mem::ManuallyDrop;
3333
use std::ops::{Deref, DerefMut};
3434

3535
/// A guard holding mutable access to a `Lock` which is in a locked state.
@@ -40,7 +40,7 @@ mod enabled {
4040

4141
/// The syncronization mode of the lock. This is explicitly passed to let LLVM relate it
4242
/// to the original lock operation.
43-
assume: Assume,
43+
mode: Mode,
4444
}
4545

4646
impl<'a, T: 'a> Deref for LockGuard<'a, T> {
@@ -64,12 +64,12 @@ mod enabled {
6464
impl<'a, T: 'a> Drop for LockGuard<'a, T> {
6565
#[inline]
6666
fn drop(&mut self) {
67-
// SAFETY (dispatch): We get `self.assume` from the lock operation so it is consistent
67+
// SAFETY (dispatch): We get `self.mode` from the lock operation so it is consistent
6868
// with the lock state.
6969
// SAFETY (unlock): We know that the lock is locked as this type is a proof of that.
7070
unsafe {
7171
self.lock.dispatch(
72-
self.assume,
72+
self.mode,
7373
|cell| {
7474
debug_assert_eq!(cell.get(), true);
7575
cell.set(false);
@@ -81,19 +81,12 @@ mod enabled {
8181
}
8282
}
8383

84-
enum LockMode {
85-
NoSync(Cell<bool>),
86-
Sync(RawMutex),
87-
}
84+
union ModeUnion {
85+
/// Indicates if the cell is locked. Only used if `Lock.mode` is `NoSync`.
86+
cell: ManuallyDrop<Cell<bool>>,
8887

89-
impl LockMode {
90-
#[inline(always)]
91-
fn to_assume(&self) -> Assume {
92-
match self {
93-
LockMode::NoSync(..) => Assume::NoSync,
94-
LockMode::Sync(..) => Assume::Sync,
95-
}
96-
}
88+
/// A lock implementation that's only used if `Lock.mode` is `Sync`.
89+
lock: ManuallyDrop<RawMutex>,
9790
}
9891

9992
/// The value representing a locked state for the `Cell`.
@@ -102,23 +95,26 @@ mod enabled {
10295
/// A lock which only uses synchronization if `might_be_dyn_thread_safe` is true.
10396
/// It implements `DynSend` and `DynSync` instead of the typical `Send` and `Sync`.
10497
pub struct Lock<T> {
105-
mode: LockMode,
98+
/// Indicates if synchronization is used via `mode_union.lock` if `Sync`, or if a
99+
/// not thread safe cell is used via `mode_union.cell` if it's `NoSync`.
100+
/// This is set on initialization and never changed.
101+
mode: Mode,
102+
103+
mode_union: ModeUnion,
106104
data: UnsafeCell<T>,
107105
}
108106

109107
impl<T> Lock<T> {
110108
#[inline(always)]
111109
pub fn new(inner: T) -> Self {
112-
Lock {
113-
mode: if unlikely(mode::might_be_dyn_thread_safe()) {
114-
// Create the lock with synchronization enabled using the `RawMutex` type.
115-
LockMode::Sync(RawMutex::INIT)
116-
} else {
117-
// Create the lock with synchronization disabled.
118-
LockMode::NoSync(Cell::new(!LOCKED))
119-
},
120-
data: UnsafeCell::new(inner),
121-
}
110+
let (mode, mode_union) = if unlikely(mode::might_be_dyn_thread_safe()) {
111+
// Create the lock with synchronization enabled using the `RawMutex` type.
112+
(Mode::Sync, ModeUnion { lock: ManuallyDrop::new(RawMutex::INIT) })
113+
} else {
114+
// Create the lock with synchronization disabled.
115+
(Mode::NoSync, ModeUnion { cell: ManuallyDrop::new(Cell::new(!LOCKED)) })
116+
};
117+
Lock { mode, mode_union, data: UnsafeCell::new(inner) }
122118
}
123119

124120
#[inline(always)]
@@ -131,79 +127,58 @@ mod enabled {
131127
self.data.get_mut()
132128
}
133129

134-
/// This dispatches on the `LockMode` and gives access to its variants depending on
135-
/// `assume`. If `no_sync` returns `None` this will panic.
130+
#[inline(always)]
131+
pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
132+
let mode = self.mode;
133+
// SAFETY: This is safe since the union fields are used in accordance with `self.mode`.
134+
match mode {
135+
Mode::NoSync => {
136+
let cell = unsafe { &self.mode_union.cell };
137+
let was_unlocked = cell.get() != LOCKED;
138+
if was_unlocked {
139+
cell.set(LOCKED);
140+
}
141+
was_unlocked
142+
}
143+
Mode::Sync => unsafe { self.mode_union.lock.try_lock() },
144+
}
145+
.then(|| LockGuard { lock: self, marker: PhantomData, mode })
146+
}
147+
148+
/// This acquires the lock assuming syncronization is in a specific mode.
136149
///
137150
/// Safety
138-
/// This method must only be called if `might_be_dyn_thread_safe` on lock creation matches
139-
/// matches the `assume` argument.
151+
/// This method must only be called with `Mode::Sync` if `might_be_dyn_thread_safe` was
152+
/// true on lock creation.
140153
#[inline(always)]
141154
#[track_caller]
142-
unsafe fn dispatch<R>(
143-
&self,
144-
assume: Assume,
145-
no_sync: impl FnOnce(&Cell<bool>) -> Option<R>,
146-
sync: impl FnOnce(&RawMutex) -> R,
147-
) -> R {
155+
pub unsafe fn lock_assume(&self, mode: Mode) -> LockGuard<'_, T> {
148156
#[inline(never)]
149157
#[track_caller]
150158
#[cold]
151159
fn lock_held() -> ! {
152160
panic!("lock was already held")
153161
}
154162

155-
match assume {
156-
Assume::NoSync => {
157-
let LockMode::NoSync(cell) = &self.mode else {
158-
unsafe { unreachable_unchecked() }
159-
};
160-
if let Some(v) = no_sync(cell) {
161-
v
162-
} else {
163-
// Call this here instead of in `no_sync` so `track_caller` gets properly
164-
// passed along.
165-
lock_held()
163+
// SAFETY: This is safe since the union fields are used in accordance with `mode`
164+
// which also must match `self.mode` due to the safety precondition.
165+
unsafe {
166+
match mode {
167+
Mode::NoSync => {
168+
if unlikely(self.mode_union.cell.replace(LOCKED) == LOCKED) {
169+
lock_held()
170+
}
166171
}
172+
Mode::Sync => self.mode_union.lock.lock(),
167173
}
168-
Assume::Sync => {
169-
let LockMode::Sync(lock) = &self.mode else {
170-
unsafe { unreachable_unchecked() }
171-
};
172-
sync(lock)
173-
}
174-
}
175-
}
176-
177-
#[inline(always)]
178-
pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
179-
let assume = self.mode.to_assume();
180-
unsafe {
181-
self.dispatch(
182-
assume,
183-
|cell| Some((cell.get() != LOCKED).then(|| cell.set(LOCKED)).is_some()),
184-
RawMutex::try_lock,
185-
)
186-
.then(|| LockGuard { lock: self, marker: PhantomData, assume })
187-
}
188-
}
189-
190-
#[inline(always)]
191-
#[track_caller]
192-
pub unsafe fn lock_assume(&self, assume: Assume) -> LockGuard<'_, T> {
193-
unsafe {
194-
self.dispatch(
195-
assume,
196-
|cell| (cell.replace(LOCKED) != LOCKED).then(|| ()),
197-
RawMutex::lock,
198-
);
199-
LockGuard { lock: self, marker: PhantomData, assume }
200174
}
175+
LockGuard { lock: self, marker: PhantomData, mode }
201176
}
202177

203178
#[inline(always)]
204179
#[track_caller]
205180
pub fn lock(&self) -> LockGuard<'_, T> {
206-
unsafe { self.lock_assume(self.mode.to_assume()) }
181+
unsafe { self.lock_assume(self.mode) }
207182
}
208183
}
209184

@@ -213,8 +188,8 @@ mod enabled {
213188
unsafe impl<T: DynSend> DynSync for Lock<T> {}
214189
}
215190

216-
mod disabled {
217-
use super::Assume;
191+
mod no_sync {
192+
use super::Mode;
218193
use std::cell::RefCell;
219194

220195
pub use std::cell::RefMut as LockGuard;
@@ -245,7 +220,7 @@ mod disabled {
245220
#[inline(always)]
246221
#[track_caller]
247222
// This is unsafe to match the API for the `parallel_compiler` case.
248-
pub unsafe fn lock_assume(&self, _assume: Assume) -> LockGuard<'_, T> {
223+
pub unsafe fn lock_assume(&self, _mode: Mode) -> LockGuard<'_, T> {
249224
self.0.borrow_mut()
250225
}
251226

0 commit comments

Comments
 (0)