diff --git a/crates/turbo-tasks-memory/src/cell.rs b/crates/turbo-tasks-memory/src/cell.rs index 11b756f84217c..d775539009f9a 100644 --- a/crates/turbo-tasks-memory/src/cell.rs +++ b/crates/turbo-tasks-memory/src/cell.rs @@ -225,7 +225,7 @@ impl Cell { content: ref mut cell_content, dependent_tasks, } => { - if content != *cell_content { + if content.ptr_eq(cell_content) { if !dependent_tasks.is_empty() { turbo_tasks.schedule_notify_tasks_set(dependent_tasks); dependent_tasks.clear(); diff --git a/crates/turbo-tasks/src/backend.rs b/crates/turbo-tasks/src/backend.rs index 6e8194ed2204a..54ebbf5a6a108 100644 --- a/crates/turbo-tasks/src/backend.rs +++ b/crates/turbo-tasks/src/backend.rs @@ -335,7 +335,7 @@ pub struct TaskExecutionSpec<'a> { // TODO technically CellContent is already indexed by the ValueTypeId, so we // don't need to store it here -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct CellContent(pub Option); impl Display for CellContent { @@ -377,6 +377,14 @@ impl CellContent { pub fn try_cast(self) -> Option> { Some(ReadRef::new_arc(self.0?.downcast().ok()?)) } + + pub fn ptr_eq(&self, other: &Self) -> bool { + match (&self.0, &other.0) { + (Some(this), Some(other)) => this.ptr_eq(other), + (None, None) => true, + (_, _) => false, + } + } } pub type TaskCollectiblesMap = AutoMap, 1>; diff --git a/crates/turbo-tasks/src/manager.rs b/crates/turbo-tasks/src/manager.rs index eef0d22893ee1..1bf2f1f213dc9 100644 --- a/crates/turbo-tasks/src/manager.rs +++ b/crates/turbo-tasks/src/manager.rs @@ -1575,7 +1575,7 @@ impl CurrentCellRef { let tt = turbo_tasks(); let content = tt.read_own_task_cell(self.current_task, self.index).ok(); let update = if let Some(CellContent(Some(content))) = content { - content != shared_ref + content.ptr_eq(&shared_ref) } else { true }; diff --git a/crates/turbo-tasks/src/task/shared_reference.rs b/crates/turbo-tasks/src/task/shared_reference.rs index 747f2477c98ca..ca04638f7c77e 100644 --- a/crates/turbo-tasks/src/task/shared_reference.rs +++ b/crates/turbo-tasks/src/task/shared_reference.rs @@ -1,7 +1,6 @@ use std::{ any::Any, fmt::{Debug, Display}, - hash::Hash, }; use anyhow::Result; @@ -32,22 +31,11 @@ impl SharedReference { Err(data) => Err(Self(self.0, data)), } } -} -impl Hash for SharedReference { - fn hash(&self, state: &mut H) { - Hash::hash(&(&*self.1 as *const (dyn Any + Send + Sync)), state) - } -} -impl PartialEq for SharedReference { - // Must compare with PartialEq rather than std::ptr::addr_eq since the latter - // only compares their addresses. - #[allow(ambiguous_wide_pointer_comparisons)] - fn eq(&self, other: &Self) -> bool { + pub fn ptr_eq(&self, other: &Self) -> bool { triomphe::Arc::ptr_eq(&self.1, &other.1) } } -impl Eq for SharedReference {} impl Debug for SharedReference { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { diff --git a/crates/turbo-tasks/src/trait_ref.rs b/crates/turbo-tasks/src/trait_ref.rs index d5eb54ecd8376..e62d65929eb77 100644 --- a/crates/turbo-tasks/src/trait_ref.rs +++ b/crates/turbo-tasks/src/trait_ref.rs @@ -40,20 +40,6 @@ impl Clone for TraitRef { } } -impl PartialEq for TraitRef { - fn eq(&self, other: &Self) -> bool { - self.shared_reference == other.shared_reference - } -} - -impl Eq for TraitRef {} - -impl std::hash::Hash for TraitRef { - fn hash(&self, state: &mut H) { - self.shared_reference.hash(state) - } -} - impl Serialize for TraitRef { fn serialize(&self, serializer: S) -> Result { self.shared_reference.serialize(serializer) @@ -89,6 +75,10 @@ where _t: PhantomData, } } + + pub fn ptr_eq(&self, other: &Self) -> bool { + self.shared_reference.ptr_eq(&other.shared_reference) + } } impl TraitRef diff --git a/crates/turbo-tasks/src/value.rs b/crates/turbo-tasks/src/value.rs index b3b36db17840f..effd4eae57af3 100644 --- a/crates/turbo-tasks/src/value.rs +++ b/crates/turbo-tasks/src/value.rs @@ -1,4 +1,4 @@ -use std::{fmt::Debug, marker::PhantomData, ops::Deref}; +use std::{fmt::Debug, hash::Hash, marker::PhantomData, ops::Deref}; use serde::{Deserialize, Serialize}; @@ -91,17 +91,17 @@ impl Clone for TransientInstance { } } -impl Eq for TransientInstance {} - impl PartialEq for TransientInstance { fn eq(&self, other: &Self) -> bool { - self.inner == other.inner + self.inner.ptr_eq(&other.inner) } } -impl std::hash::Hash for TransientInstance { +impl Eq for TransientInstance {} + +impl Hash for TransientInstance { fn hash(&self, state: &mut H) { - self.inner.hash(state); + self.inner.1.as_ptr().hash(state); } } diff --git a/crates/turbopack-browser/src/ecmascript/list/version.rs b/crates/turbopack-browser/src/ecmascript/list/version.rs index 7dd142e36609c..78fb06fb9fa2c 100644 --- a/crates/turbopack-browser/src/ecmascript/list/version.rs +++ b/crates/turbopack-browser/src/ecmascript/list/version.rs @@ -1,3 +1,5 @@ +use std::hash::Hash; + use anyhow::Result; use indexmap::IndexMap; use turbo_tasks::{RcStr, TraitRef, TryJoinIterExt, Vc}; @@ -9,7 +11,7 @@ type VersionTraitRef = TraitRef>; /// The version of a [`EcmascriptDevChunkListContent`]. /// /// [`EcmascriptDevChunkListContent`]: super::content::EcmascriptDevChunkListContent -#[turbo_tasks::value(shared)] +#[turbo_tasks::value(shared, eq = "manual")] pub(super) struct EcmascriptDevChunkListVersion { /// A map from chunk path to its version. #[turbo_tasks(trace_ignore)] @@ -19,6 +21,27 @@ pub(super) struct EcmascriptDevChunkListVersion { pub by_merger: IndexMap>, VersionTraitRef>, } +fn eq_index_map( + this: &IndexMap>, + other: &IndexMap>, +) -> bool { + if this.len() != other.len() { + return false; + } + + this.iter() + .all(|(key, value)| other.get(key).map_or(false, |v| value.ptr_eq(v))) +} + +impl PartialEq for EcmascriptDevChunkListVersion { + fn eq(&self, other: &Self) -> bool { + eq_index_map(&self.by_path, &other.by_path) + || eq_index_map(&self.by_merger, &other.by_merger) + } +} + +impl Eq for EcmascriptDevChunkListVersion {} + #[turbo_tasks::value_impl] impl Version for EcmascriptDevChunkListVersion { #[turbo_tasks::function] diff --git a/crates/turbopack-core/src/version.rs b/crates/turbopack-core/src/version.rs index 08fb9f6ec3572..2e88a0d329619 100644 --- a/crates/turbopack-core/src/version.rs +++ b/crates/turbopack-core/src/version.rs @@ -31,7 +31,7 @@ pub trait VersionedContent { let to_ref = to.into_trait_ref().await?; // Fast path: versions are the same. - if from_ref == to_ref { + if from_ref.ptr_eq(&to_ref) { return Ok(Update::None.into()); } @@ -181,15 +181,23 @@ pub enum Update { } /// A total update to a versioned object. -#[derive(PartialEq, Eq, Debug, Clone, TraceRawVcs, ValueDebugFormat, Serialize, Deserialize)] +#[derive(Debug, Clone, TraceRawVcs, ValueDebugFormat, Serialize, Deserialize)] pub struct TotalUpdate { /// The version this update will bring the object to. #[turbo_tasks(trace_ignore)] pub to: TraitRef>, } +impl PartialEq for TotalUpdate { + fn eq(&self, other: &Self) -> bool { + self.to.ptr_eq(&other.to) + } +} + +impl Eq for TotalUpdate {} + /// A partial update to a versioned object. -#[derive(PartialEq, Eq, Debug, Clone, TraceRawVcs, ValueDebugFormat, Serialize, Deserialize)] +#[derive(Debug, Clone, TraceRawVcs, ValueDebugFormat, Serialize, Deserialize)] pub struct PartialUpdate { /// The version this update will bring the object to. #[turbo_tasks(trace_ignore)] @@ -200,6 +208,14 @@ pub struct PartialUpdate { pub instruction: Arc, } +impl PartialEq for PartialUpdate { + fn eq(&self, other: &Self) -> bool { + self.to.ptr_eq(&other.to) && self.instruction == other.instruction + } +} + +impl Eq for PartialUpdate {} + /// [`Version`] implementation that hashes a file at a given path and returns /// the hex encoded hash as a version identifier. #[turbo_tasks::value] @@ -260,7 +276,14 @@ impl VersionState { pub async fn set(self: Vc, new_version: TraitRef>) -> Result<()> { let this = self.await?; - this.version.set(new_version); + this.version.update_conditionally(|version| { + if !version.ptr_eq(&new_version) { + *version = new_version; + true + } else { + false + } + }); Ok(()) } }