Skip to content

Commit be54f9b

Browse files
authored
Unrolled build for #153471
Rollup merge of #153471 - nnethercote:complete_inner, r=petrochenkov Refactor `ActiveJobGuard` A few small improvements. r? @petrochenkov
2 parents 0c68443 + 18ade84 commit be54f9b

1 file changed

Lines changed: 47 additions & 60 deletions

File tree

compiler/rustc_query_impl/src/execution.rs

Lines changed: 47 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::hash::Hash;
2-
use std::mem;
2+
use std::mem::ManuallyDrop;
33

44
use rustc_data_structures::hash_table::{Entry, HashTable};
55
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -26,17 +26,6 @@ fn equivalent_key<K: Eq, V>(k: K) -> impl Fn(&(K, V)) -> bool {
2626
move |x| x.0 == k
2727
}
2828

29-
/// Obtains the enclosed [`QueryJob`], or panics if this query evaluation
30-
/// was poisoned by a panic.
31-
fn expect_job<'tcx>(status: ActiveKeyStatus<'tcx>) -> QueryJob<'tcx> {
32-
match status {
33-
ActiveKeyStatus::Started(job) => job,
34-
ActiveKeyStatus::Poisoned => {
35-
panic!("job for query failed to start and was poisoned")
36-
}
37-
}
38-
}
39-
4029
pub(crate) fn all_inactive<'tcx, K>(state: &QueryState<'tcx, K>) -> bool {
4130
state.active.lock_shards().all(|shard| shard.is_empty())
4231
}
@@ -104,20 +93,6 @@ where
10493
Some(())
10594
}
10695

107-
/// Guard object representing the responsibility to execute a query job and
108-
/// mark it as completed.
109-
///
110-
/// This will poison the relevant query key if it is dropped without calling
111-
/// [`Self::complete`].
112-
struct ActiveJobGuard<'tcx, K>
113-
where
114-
K: Eq + Hash + Copy,
115-
{
116-
state: &'tcx QueryState<'tcx, K>,
117-
key: K,
118-
key_hash: u64,
119-
}
120-
12196
#[cold]
12297
#[inline(never)]
12398
fn mk_cycle<'tcx, C: QueryCache>(
@@ -148,39 +123,65 @@ fn mk_cycle<'tcx, C: QueryCache>(
148123
}
149124
}
150125

126+
/// Guard object representing the responsibility to execute a query job and
127+
/// mark it as completed.
128+
///
129+
/// This will poison the relevant query key if it is dropped without calling
130+
/// [`Self::complete`].
131+
struct ActiveJobGuard<'tcx, K>
132+
where
133+
K: Eq + Hash + Copy,
134+
{
135+
state: &'tcx QueryState<'tcx, K>,
136+
key: K,
137+
key_hash: u64,
138+
}
139+
151140
impl<'tcx, K> ActiveJobGuard<'tcx, K>
152141
where
153142
K: Eq + Hash + Copy,
154143
{
155144
/// Completes the query by updating the query cache with the `result`,
156145
/// signals the waiter, and forgets the guard so it won't poison the query.
157-
fn complete<C>(self, cache: &C, result: C::Value, dep_node_index: DepNodeIndex)
146+
fn complete<C>(self, cache: &C, value: C::Value, dep_node_index: DepNodeIndex)
158147
where
159148
C: QueryCache<Key = K>,
160149
{
161-
// Forget ourself so our destructor won't poison the query.
162-
// (Extract fields by value first to make sure we don't leak anything.)
163-
let Self { state, key, key_hash }: Self = self;
164-
mem::forget(self);
165-
166150
// Mark as complete before we remove the job from the active state
167151
// so no other thread can re-execute this query.
168-
cache.complete(key, result, dep_node_index);
169-
170-
let job = {
171-
// don't keep the lock during the `unwrap()` of the retrieved value, or we taint the
172-
// underlying shard.
173-
// since unwinding also wants to look at this map, this can also prevent a double
174-
// panic.
175-
let mut shard = state.active.lock_shard_by_hash(key_hash);
176-
match shard.find_entry(key_hash, equivalent_key(key)) {
177-
Err(_) => None,
178-
Ok(occupied) => Some(occupied.remove().0.1),
152+
cache.complete(self.key, value, dep_node_index);
153+
154+
let mut this = ManuallyDrop::new(self);
155+
156+
// Drop everything without poisoning the query.
157+
this.drop_and_maybe_poison(/* poison */ false);
158+
}
159+
160+
fn drop_and_maybe_poison(&mut self, poison: bool) {
161+
let status = {
162+
let mut shard = self.state.active.lock_shard_by_hash(self.key_hash);
163+
match shard.find_entry(self.key_hash, equivalent_key(self.key)) {
164+
Err(_) => {
165+
// Note: we must not panic while holding the lock, because unwinding also looks
166+
// at this map, which can result in a double panic. So drop it first.
167+
drop(shard);
168+
panic!();
169+
}
170+
Ok(occupied) => {
171+
let ((key, status), vacant) = occupied.remove();
172+
if poison {
173+
vacant.insert((key, ActiveKeyStatus::Poisoned));
174+
}
175+
status
176+
}
179177
}
180178
};
181-
let job = expect_job(job.expect("active query job entry"));
182179

183-
job.signal_complete();
180+
// Also signal the completion of the job, so waiters will continue execution.
181+
match status {
182+
ActiveKeyStatus::Started(job) => job.signal_complete(),
183+
ActiveKeyStatus::Poisoned => panic!(),
184+
}
184185
}
185186
}
186187

@@ -192,21 +193,7 @@ where
192193
#[cold]
193194
fn drop(&mut self) {
194195
// Poison the query so jobs waiting on it panic.
195-
let Self { state, key, key_hash } = *self;
196-
let job = {
197-
let mut shard = state.active.lock_shard_by_hash(key_hash);
198-
match shard.find_entry(key_hash, equivalent_key(key)) {
199-
Err(_) => panic!(),
200-
Ok(occupied) => {
201-
let ((key, value), vacant) = occupied.remove();
202-
vacant.insert((key, ActiveKeyStatus::Poisoned));
203-
expect_job(value)
204-
}
205-
}
206-
};
207-
// Also signal the completion of the job, so waiters
208-
// will continue execution.
209-
job.signal_complete();
196+
self.drop_and_maybe_poison(/* poison */ true);
210197
}
211198
}
212199

0 commit comments

Comments
 (0)