Skip to content

Commit abfd3d6

Browse files
committed
fix our verify features in turbo-tasks backend
1 parent 9662feb commit abfd3d6

File tree

9 files changed

+125
-25
lines changed

9 files changed

+125
-25
lines changed

turbopack/crates/turbo-tasks-backend/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ bench = false
1313
workspace = true
1414

1515
[features]
16-
default = []
16+
default = ["verify_aggregation_graph", "verify_immutable", "verify_determinism"]
1717
print_cache_item_size = ["dep:lzzzz"]
1818
no_fast_stale = []
1919
verify_serialization = []
2020
verify_aggregation_graph = []
2121
verify_immutable = []
22-
verify_determinism = []
22+
verify_determinism = ["turbo-tasks/verify_determinism"]
2323
trace_aggregation_update_queue = []
2424
trace_aggregation_update = ["trace_aggregation_update_queue"]
2525
trace_leaf_distance_update = []

turbopack/crates/turbo-tasks-backend/src/backend/mod.rs

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1937,6 +1937,7 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
19371937
task_id: TaskId,
19381938
result: Result<RawVc, TurboTasksExecutionError>,
19391939
cell_counters: &AutoMap<ValueTypeId, u32, BuildHasherDefault<FxHasher>, 8>,
1940+
#[cfg(feature = "verify_determinism")] stateful: bool,
19401941
has_invalidator: bool,
19411942
turbo_tasks: &dyn TurboTasksBackendApi<TurboTasksBackend<B>>,
19421943
) -> bool {
@@ -1994,6 +1995,8 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
19941995
task_id,
19951996
result,
19961997
cell_counters,
1998+
#[cfg(feature = "verify_determinism")]
1999+
stateful,
19972000
has_invalidator,
19982001
)
19992002
else {
@@ -2068,6 +2071,7 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
20682071
task_id: TaskId,
20692072
result: Result<RawVc, TurboTasksExecutionError>,
20702073
cell_counters: &AutoMap<ValueTypeId, u32, BuildHasherDefault<FxHasher>, 8>,
2074+
#[cfg(feature = "verify_determinism")] stateful: bool,
20712075
has_invalidator: bool,
20722076
) -> Option<TaskExecutionCompletePrepareResult> {
20732077
let mut task = ctx.task(task_id, TaskDataCategory::All);
@@ -2132,6 +2136,12 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
21322136
// take the children from the task to process them
21332137
let mut new_children = take(new_children);
21342138

2139+
// handle stateful (only tracked when verify_determinism is enabled)
2140+
#[cfg(feature = "verify_determinism")]
2141+
if stateful {
2142+
task.set_stateful(true);
2143+
}
2144+
21352145
// handle has_invalidator
21362146
if has_invalidator {
21372147
task.set_invalidator(true);
@@ -2575,7 +2585,8 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
25752585
};
25762586

25772587
// Update the dirty state
2578-
if old_dirtyness != new_dirtyness {
2588+
let dirty_changed = old_dirtyness != new_dirtyness;
2589+
if dirty_changed {
25792590
if let Some(value) = new_dirtyness {
25802591
task.set_dirty(value);
25812592
} else if old_dirtyness.is_some() {
@@ -3139,7 +3150,7 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
31393150
"Task {} {} doesn't report to any root but is reachable from one (uppers: \
31403151
{:?})",
31413152
task_id,
3142-
ctx.get_task_description(task_id),
3153+
task.get_task_description(),
31433154
uppers
31443155
);
31453156
}
@@ -3150,14 +3161,14 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
31503161
.collect();
31513162
for collectible in aggregated_collectibles {
31523163
collectibles
3153-
.entry(collectible)
3164+
.entry(*collectible)
31543165
.or_insert_with(|| (false, Vec::new()))
31553166
.1
31563167
.push(task_id);
31573168
}
31583169

31593170
let own_collectibles: Vec<_> = task
3160-
.iter_collectibles_entries()
3171+
.iter_collectibles()
31613172
.filter_map(|(&collectible, &value)| (value > 0).then_some(collectible))
31623173
.collect::<Vec<_>>();
31633174
for collectible in own_collectibles {
@@ -3195,22 +3206,25 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
31953206

31963207
if should_be_in_upper {
31973208
for upper_id in uppers {
3198-
let task = ctx.task(upper_id, TaskDataCategory::All);
3199-
let in_upper = task
3209+
let upper = ctx.task(upper_id, TaskDataCategory::All);
3210+
let in_upper = upper
32003211
.get_aggregated_dirty_containers(&task_id)
32013212
.is_some_and(|&dirty| dirty > 0);
32023213
if !in_upper {
3203-
let containers: Vec<_> = task
3204-
.iter_aggregated_dirty_containers_entries()
3214+
let containers: Vec<_> = upper
3215+
.iter_aggregated_dirty_containers()
32053216
.map(|(&k, &v)| (k, v))
32063217
.collect();
3218+
let upper_task_desc = upper.get_task_description();
3219+
drop(upper);
32073220
panic!(
32083221
"Task {} ({}) is dirty, but is not listed in the upper task {} \
32093222
({})\nThese dirty containers are present:\n{:#?}",
32103223
task_id,
3211-
ctx.get_task_description(task_id),
3224+
ctx.task(task_id, TaskDataCategory::Data)
3225+
.get_task_description(),
32123226
upper_id,
3213-
ctx.get_task_description(upper_id),
3227+
upper_task_desc,
32143228
containers,
32153229
);
32163230
}
@@ -3229,7 +3243,10 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
32293243
collectible,
32303244
task_ids
32313245
.iter()
3232-
.map(|t| format!("{t} {}", ctx.get_task_description(*t)))
3246+
.map(|t| format!(
3247+
"{t} {}",
3248+
ctx.task(*t, TaskDataCategory::Data).get_task_description()
3249+
))
32333250
.collect::<Vec<_>>()
32343251
)
32353252
.unwrap();
@@ -3245,8 +3262,8 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
32453262
writeln!(stdout, "{task_id:?} -> {upper_id:?}").unwrap();
32463263
}
32473264
while let Some(task_id) = queue.pop() {
3248-
let desc = ctx.get_task_description(task_id);
32493265
let task = ctx.task(task_id, TaskDataCategory::All);
3266+
let desc = task.get_task_description();
32503267
let aggregated_collectible = task
32513268
.get_aggregated_collectibles(&collectible)
32523269
.copied()
@@ -3436,13 +3453,16 @@ impl<B: BackingStorage> Backend for TurboTasksBackend<B> {
34363453
task_id: TaskId,
34373454
result: Result<RawVc, TurboTasksExecutionError>,
34383455
cell_counters: &AutoMap<ValueTypeId, u32, BuildHasherDefault<FxHasher>, 8>,
3456+
#[cfg(feature = "verify_determinism")] stateful: bool,
34393457
has_invalidator: bool,
34403458
turbo_tasks: &dyn TurboTasksBackendApi<Self>,
34413459
) -> bool {
34423460
self.0.task_execution_completed(
34433461
task_id,
34443462
result,
34453463
cell_counters,
3464+
#[cfg(feature = "verify_determinism")]
3465+
stateful,
34463466
has_invalidator,
34473467
turbo_tasks,
34483468
)

turbopack/crates/turbo-tasks-backend/src/backend/operation/update_cell.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,10 @@ impl UpdateCellOperation {
5555
content: CellContent,
5656
is_serializable_cell_content: bool,
5757
updated_key_hashes: Option<SmallVec<[u64; 2]>>,
58-
#[cfg(feature = "verify_determinism")] verification_mode: VerificationMode,
59-
#[cfg(not(feature = "verify_determinism"))] _verification_mode: VerificationMode,
58+
#[cfg(feature = "verify_determinism")]
59+
verification_mode: turbo_tasks::backend::VerificationMode,
60+
#[cfg(not(feature = "verify_determinism"))]
61+
_verification_mode: turbo_tasks::backend::VerificationMode,
6062
mut ctx: impl ExecuteContext<'_>,
6163
) {
6264
let content = if let CellContent(Some(new_content)) = content {
@@ -80,11 +82,14 @@ impl UpdateCellOperation {
8082

8183
// Check if this assumption holds.
8284
#[cfg(feature = "verify_determinism")]
83-
if !is_stateful
84-
&& matches!(verification_mode, VerificationMode::EqualityCheck)
85+
if !task.stateful()
86+
&& matches!(
87+
verification_mode,
88+
turbo_tasks::backend::VerificationMode::EqualityCheck
89+
)
8590
&& content != task.get_cell_data(is_serializable_cell_content, cell)
8691
{
87-
let task_description = ctx.get_task_description(task_id);
92+
let task_description = task.get_task_description();
8893
let cell_type = turbo_tasks::registry::get_value_type(cell.type_id).global_name;
8994
eprintln!(
9095
"Task {} updated cell #{} (type: {}) while recomputing",

turbopack/crates/turbo-tasks-backend/src/backend/storage_schema.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,12 @@ struct TaskStorageSchema {
181181
#[field(storage = "flag", category = "transient")]
182182
prefetched: bool,
183183

184+
/// Whether this task has allocated a State (has interior mutability).
185+
/// Only set when `verify_determinism`` feature is enabled.
186+
/// Used to skip determinism checks for stateful tasks.
187+
#[field(storage = "flag", category = "transient")]
188+
stateful: bool,
189+
184190
// =========================================================================
185191
// CHILDREN & AGGREGATION (meta)
186192
// =========================================================================

turbopack/crates/turbo-tasks/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ default = []
1313
tokio_tracing = ["tokio/tracing"]
1414
hanging_detection = []
1515
task_id_details = []
16+
verify_determinism = []
1617

1718
# TODO(bgw): This feature is here to unblock turning on local tasks by default. It's only turned on
1819
# in unit tests. This will be removed very soon.

turbopack/crates/turbo-tasks/src/backend.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,7 @@ pub trait Backend: Sync + Send {
493493
task: TaskId,
494494
result: Result<RawVc, TurboTasksExecutionError>,
495495
cell_counters: &AutoMap<ValueTypeId, u32, BuildHasherDefault<FxHasher>, 8>,
496+
#[cfg(feature = "verify_determinism")] stateful: bool,
496497
has_invalidator: bool,
497498
turbo_tasks: &dyn TurboTasksBackendApi<Self>,
498499
) -> bool;

turbopack/crates/turbo-tasks/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ pub use crate::{
116116
CurrentCellRef, ReadCellTracking, ReadConsistency, ReadTracking, TaskPersistence,
117117
TaskPriority, TurboTasks, TurboTasksApi, TurboTasksBackendApi, TurboTasksCallApi, Unused,
118118
UpdateInfo, dynamic_call, emit, get_serialization_invalidator, mark_finished, mark_root,
119-
mark_session_dependent, prevent_gc, run, run_once, run_once_with_reason, trait_call,
120-
turbo_tasks, turbo_tasks_scope, turbo_tasks_weak, with_turbo_tasks,
119+
mark_session_dependent, mark_stateful, prevent_gc, run, run_once, run_once_with_reason,
120+
trait_call, turbo_tasks, turbo_tasks_scope, turbo_tasks_weak, with_turbo_tasks,
121121
},
122122
mapped_read_ref::MappedReadRef,
123123
output::OutputContent,

turbopack/crates/turbo-tasks/src/manager.rs

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,11 @@ struct CurrentTaskState {
518518
execution_id: ExecutionId,
519519
priority: TaskPriority,
520520

521+
/// True if the current task has state in cells (interior mutability).
522+
/// Only tracked when verify_determinism feature is enabled.
523+
#[cfg(feature = "verify_determinism")]
524+
stateful: bool,
525+
521526
/// True if the current task uses an external invalidator
522527
has_invalidator: bool,
523528

@@ -541,6 +546,8 @@ impl CurrentTaskState {
541546
task_id: Some(task_id),
542547
execution_id,
543548
priority,
549+
#[cfg(feature = "verify_determinism")]
550+
stateful: false,
544551
has_invalidator: false,
545552
cell_counters: Some(AutoMap::default()),
546553
local_tasks: Vec::new(),
@@ -553,6 +560,8 @@ impl CurrentTaskState {
553560
task_id: None,
554561
execution_id,
555562
priority,
563+
#[cfg(feature = "verify_determinism")]
564+
stateful: false,
556565
has_invalidator: false,
557566
cell_counters: None,
558567
local_tasks: Vec::new(),
@@ -1142,14 +1151,28 @@ impl<B: Backend + 'static> TurboTasks<B> {
11421151
}
11431152

11441153
fn finish_current_task_state(&self) -> FinishedTaskState {
1154+
#[cfg(feature = "verify_determinism")]
1155+
let (stateful, has_invalidator) = CURRENT_TASK_STATE.with(|cell| {
1156+
let CurrentTaskState {
1157+
stateful,
1158+
has_invalidator,
1159+
..
1160+
} = &mut *cell.write().unwrap();
1161+
(*stateful, *has_invalidator)
1162+
});
1163+
#[cfg(not(feature = "verify_determinism"))]
11451164
let has_invalidator = CURRENT_TASK_STATE.with(|cell| {
11461165
let CurrentTaskState {
11471166
has_invalidator, ..
11481167
} = &mut *cell.write().unwrap();
11491168
*has_invalidator
11501169
});
11511170

1152-
FinishedTaskState { has_invalidator }
1171+
FinishedTaskState {
1172+
#[cfg(feature = "verify_determinism")]
1173+
stateful,
1174+
has_invalidator,
1175+
}
11531176
}
11541177

11551178
pub fn backend(&self) -> &B {
@@ -1208,6 +1231,12 @@ impl<B: Backend> Executor<TurboTasks<B>, ScheduledTask, TaskPriority> for TurboT
12081231
Err(err) => Err(TurboTasksExecutionError::Panic(Arc::new(err))),
12091232
};
12101233

1234+
#[cfg(feature = "verify_determinism")]
1235+
let FinishedTaskState {
1236+
stateful,
1237+
has_invalidator,
1238+
} = this.finish_current_task_state();
1239+
#[cfg(not(feature = "verify_determinism"))]
12111240
let FinishedTaskState { has_invalidator } =
12121241
this.finish_current_task_state();
12131242
let cell_counters = CURRENT_TASK_STATE
@@ -1216,6 +1245,8 @@ impl<B: Backend> Executor<TurboTasks<B>, ScheduledTask, TaskPriority> for TurboT
12161245
task_id,
12171246
result,
12181247
&cell_counters,
1248+
#[cfg(feature = "verify_determinism")]
1249+
stateful,
12191250
has_invalidator,
12201251
&*this,
12211252
)
@@ -1310,6 +1341,11 @@ impl<B: Backend> Executor<TurboTasks<B>, ScheduledTask, TaskPriority> for TurboT
13101341
}
13111342

13121343
struct FinishedTaskState {
1344+
/// True if the task has state in cells (interior mutability).
1345+
/// Only tracked when verify_determinism feature is enabled.
1346+
#[cfg(feature = "verify_determinism")]
1347+
stateful: bool,
1348+
13131349
/// True if the task uses an external invalidator
13141350
has_invalidator: bool,
13151351
}
@@ -1849,10 +1885,22 @@ pub fn mark_finished() {
18491885
}
18501886

18511887
/// Returns a [`SerializationInvalidator`] that can be used to invalidate the
1852-
/// serialization of the current task cells
1888+
/// serialization of the current task cells.
1889+
///
1890+
/// Also marks the current task as stateful when the `verify_determinism` feature is enabled,
1891+
/// since State allocation implies interior mutability.
18531892
pub fn get_serialization_invalidator() -> SerializationInvalidator {
18541893
CURRENT_TASK_STATE.with(|cell| {
1855-
let CurrentTaskState { task_id, .. } = &mut *cell.write().unwrap();
1894+
let CurrentTaskState {
1895+
task_id,
1896+
#[cfg(feature = "verify_determinism")]
1897+
stateful,
1898+
..
1899+
} = &mut *cell.write().unwrap();
1900+
#[cfg(feature = "verify_determinism")]
1901+
{
1902+
*stateful = true;
1903+
}
18561904
let Some(task_id) = *task_id else {
18571905
panic!(
18581906
"get_serialization_invalidator() can only be used in the context of a turbo_tasks \
@@ -1872,6 +1920,24 @@ pub fn mark_invalidator() {
18721920
})
18731921
}
18741922

1923+
/// Marks the current task as stateful. This is used to indicate that the task
1924+
/// has interior mutability (e.g., via State or TransientState), which means
1925+
/// the task may produce different outputs even with the same inputs.
1926+
///
1927+
/// Only has an effect when the `verify_determinism` feature is enabled.
1928+
#[cfg(feature = "verify_determinism")]
1929+
pub fn mark_stateful() {
1930+
CURRENT_TASK_STATE.with(|cell| {
1931+
let CurrentTaskState { stateful, .. } = &mut *cell.write().unwrap();
1932+
*stateful = true;
1933+
})
1934+
}
1935+
1936+
#[cfg(not(feature = "verify_determinism"))]
1937+
pub fn mark_stateful() {
1938+
// No-op when verify_determinism is not enabled
1939+
}
1940+
18751941
pub fn prevent_gc() {
18761942
// TODO implement garbage collection
18771943
}

turbopack/crates/turbo-tasks/src/state.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use tracing::trace_span;
1313
use crate::{
1414
Invalidator, OperationValue, SerializationInvalidator, get_invalidator,
1515
get_serialization_invalidator, manager::with_turbo_tasks, mark_session_dependent,
16-
trace::TraceRawVcs,
16+
mark_stateful, trace::TraceRawVcs,
1717
};
1818

1919
#[derive(Encode, Decode)]
@@ -333,6 +333,7 @@ impl<T> Eq for TransientState<T> {}
333333

334334
impl<T> TransientState<T> {
335335
pub fn new() -> Self {
336+
mark_stateful();
336337
Self {
337338
inner: Mutex::new(StateInner::new(None)),
338339
}

0 commit comments

Comments
 (0)