Skip to content

Commit 9690142

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

File tree

3 files changed

+79
-107
lines changed

3 files changed

+79
-107
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

+74-102
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,36 +64,26 @@ 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
68-
// with the lock state.
69-
// SAFETY (unlock): We know that the lock is locked as this type is a proof of that.
70-
unsafe {
71-
self.lock.dispatch(
72-
self.assume,
73-
|cell| {
74-
debug_assert_eq!(cell.get(), true);
75-
cell.set(false);
76-
Some(())
77-
},
78-
|lock| lock.unlock(),
79-
);
80-
};
67+
// SAFETY (union access): We get `self.mode` from the lock operation so it is consistent
68+
// with the `lock.mode` state. This means we access the right union fields.
69+
match self.mode {
70+
Mode::NoSync => {
71+
let cell = unsafe { &self.lock.mode_union.no_sync };
72+
debug_assert_eq!(cell.get(), true);
73+
cell.set(false);
74+
}
75+
// SAFETY (unlock): We know that the lock is locked as this type is a proof of that.
76+
Mode::Sync => unsafe { self.lock.mode_union.sync.unlock() },
77+
}
8178
}
8279
}
8380

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

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-
}
85+
/// A lock implementation that's only used if `Lock.mode` is `Sync`.
86+
sync: ManuallyDrop<RawMutex>,
9787
}
9888

9989
/// The value representing a locked state for the `Cell`.
@@ -102,23 +92,26 @@ mod enabled {
10292
/// A lock which only uses synchronization if `might_be_dyn_thread_safe` is true.
10393
/// It implements `DynSend` and `DynSync` instead of the typical `Send` and `Sync`.
10494
pub struct Lock<T> {
105-
mode: LockMode,
95+
/// Indicates if synchronization is used via `mode_union.sync` if it's `Sync`, or if a
96+
/// not thread safe cell is used via `mode_union.no_sync` if it's `NoSync`.
97+
/// This is set on initialization and never changed.
98+
mode: Mode,
99+
100+
mode_union: ModeUnion,
106101
data: UnsafeCell<T>,
107102
}
108103

109104
impl<T> Lock<T> {
110105
#[inline(always)]
111106
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-
}
107+
let (mode, mode_union) = if unlikely(mode::might_be_dyn_thread_safe()) {
108+
// Create the lock with synchronization enabled using the `RawMutex` type.
109+
(Mode::Sync, ModeUnion { sync: ManuallyDrop::new(RawMutex::INIT) })
110+
} else {
111+
// Create the lock with synchronization disabled.
112+
(Mode::NoSync, ModeUnion { no_sync: ManuallyDrop::new(Cell::new(!LOCKED)) })
113+
};
114+
Lock { mode, mode_union, data: UnsafeCell::new(inner) }
122115
}
123116

124117
#[inline(always)]
@@ -131,79 +124,58 @@ mod enabled {
131124
self.data.get_mut()
132125
}
133126

134-
/// This dispatches on the `LockMode` and gives access to its variants depending on
135-
/// `assume`. If `no_sync` returns `None` this will panic.
127+
#[inline(always)]
128+
pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
129+
let mode = self.mode;
130+
// SAFETY: This is safe since the union fields are used in accordance with `self.mode`.
131+
match mode {
132+
Mode::NoSync => {
133+
let cell = unsafe { &self.mode_union.no_sync };
134+
let was_unlocked = cell.get() != LOCKED;
135+
if was_unlocked {
136+
cell.set(LOCKED);
137+
}
138+
was_unlocked
139+
}
140+
Mode::Sync => unsafe { self.mode_union.sync.try_lock() },
141+
}
142+
.then(|| LockGuard { lock: self, marker: PhantomData, mode })
143+
}
144+
145+
/// This acquires the lock assuming syncronization is in a specific mode.
136146
///
137147
/// Safety
138-
/// This method must only be called if `might_be_dyn_thread_safe` on lock creation matches
139-
/// matches the `assume` argument.
148+
/// This method must only be called with `Mode::Sync` if `might_be_dyn_thread_safe` was
149+
/// true on lock creation.
140150
#[inline(always)]
141151
#[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 {
152+
pub unsafe fn lock_assume(&self, mode: Mode) -> LockGuard<'_, T> {
148153
#[inline(never)]
149154
#[track_caller]
150155
#[cold]
151156
fn lock_held() -> ! {
152157
panic!("lock was already held")
153158
}
154159

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()
160+
// SAFETY: This is safe since the union fields are used in accordance with `mode`
161+
// which also must match `self.mode` due to the safety precondition.
162+
unsafe {
163+
match mode {
164+
Mode::NoSync => {
165+
if unlikely(self.mode_union.no_sync.replace(LOCKED) == LOCKED) {
166+
lock_held()
167+
}
166168
}
169+
Mode::Sync => self.mode_union.sync.lock(),
167170
}
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 }
200171
}
172+
LockGuard { lock: self, marker: PhantomData, mode }
201173
}
202174

203175
#[inline(always)]
204176
#[track_caller]
205177
pub fn lock(&self) -> LockGuard<'_, T> {
206-
unsafe { self.lock_assume(self.mode.to_assume()) }
178+
unsafe { self.lock_assume(self.mode) }
207179
}
208180
}
209181

@@ -213,8 +185,8 @@ mod enabled {
213185
unsafe impl<T: DynSend> DynSync for Lock<T> {}
214186
}
215187

216-
mod disabled {
217-
use super::Assume;
188+
mod no_sync {
189+
use super::Mode;
218190
use std::cell::RefCell;
219191

220192
pub use std::cell::RefMut as LockGuard;
@@ -245,7 +217,7 @@ mod disabled {
245217
#[inline(always)]
246218
#[track_caller]
247219
// This is unsafe to match the API for the `parallel_compiler` case.
248-
pub unsafe fn lock_assume(&self, _assume: Assume) -> LockGuard<'_, T> {
220+
pub unsafe fn lock_assume(&self, _mode: Mode) -> LockGuard<'_, T> {
249221
self.0.borrow_mut()
250222
}
251223

0 commit comments

Comments
 (0)