diff --git a/crates/turbo-tasks/src/backend.rs b/crates/turbo-tasks/src/backend.rs index 07134e6b9be22..f21e2e3b1b11e 100644 --- a/crates/turbo-tasks/src/backend.rs +++ b/crates/turbo-tasks/src/backend.rs @@ -4,6 +4,7 @@ use std::{ fmt, fmt::{Debug, Display, Write}, future::Future, + mem::take, pin::Pin, sync::Arc, time::{Duration, Instant}, @@ -351,7 +352,7 @@ pub trait Backend: Sync + Send { impl PersistentTaskType { pub async fn run_resolve_native( fn_id: FunctionId, - inputs: Vec, + mut inputs: Vec, turbo_tasks: Arc>, ) -> Result { let span = tracing::trace_span!( @@ -359,11 +360,14 @@ impl PersistentTaskType { name = ®istry::get_function(fn_id).name.as_str() ); async move { - let mut resolved_inputs = Vec::with_capacity(inputs.len()); - for input in inputs.into_iter() { - resolved_inputs.push(input.resolve().await?) + for i in 0..inputs.len() { + let input = unsafe { take(inputs.get_unchecked_mut(i)) }; + let input = input.resolve().await?; + unsafe { + *inputs.get_unchecked_mut(i) = input; + } } - Ok(turbo_tasks.native_call(fn_id, resolved_inputs)) + Ok(turbo_tasks.native_call(fn_id, inputs)) } .instrument(span) .await diff --git a/crates/turbo-tasks/src/keyed_cell.rs b/crates/turbo-tasks/src/keyed_cell.rs index 763eb94dda27c..ffacf6220fbb7 100644 --- a/crates/turbo-tasks/src/keyed_cell.rs +++ b/crates/turbo-tasks/src/keyed_cell.rs @@ -12,12 +12,20 @@ struct KeyedCell { cell_ref: CurrentCellRef, } -impl KeyedCell {} - #[turbo_tasks::value_impl] impl KeyedCell { #[turbo_tasks::function] - fn new(_task: TaskId, _key: ConcreteTaskInput, value_type_id: ValueTypeId) -> Vc { + fn new_local(_task: TaskId, _key: ConcreteTaskInput, value_type_id: ValueTypeId) -> Vc { + let cell_ref = find_cell_by_type(value_type_id); + KeyedCell { + cell: cell_ref.into(), + cell_ref, + } + .cell() + } + + #[turbo_tasks::function] + fn new_global(_key: ConcreteTaskInput, value_type_id: ValueTypeId) -> Vc { let cell_ref = find_cell_by_type(value_type_id); KeyedCell { cell: cell_ref.into(), @@ -44,7 +52,7 @@ pub async fn keyed_cell( key: K, content: T, ) -> Result> { - let cell = KeyedCell::new( + let cell = KeyedCell::new_local( current_task("keyed_cell"), key.into_concrete(), T::get_value_type_id(), @@ -53,3 +61,17 @@ pub async fn keyed_cell( cell.cell_ref.compare_and_update_shared(content); Ok(cell.cell.into()) } + +/// Cells a value in a cell with a given key. A key MUST only be used once for +/// the whole application. +/// +/// This allows to create singleton Vcs for values while avoiding to pass the +/// whole value as argument and creating a large task key. +pub async fn global_keyed_cell( + key: K, + content: T, +) -> Result> { + let cell = KeyedCell::new_global(key.into_concrete(), T::get_value_type_id()).await?; + cell.cell_ref.compare_and_update_shared(content); + Ok(cell.cell.into()) +} diff --git a/crates/turbo-tasks/src/lib.rs b/crates/turbo-tasks/src/lib.rs index 2ea1b98dd7d07..c0909205f38c9 100644 --- a/crates/turbo-tasks/src/lib.rs +++ b/crates/turbo-tasks/src/lib.rs @@ -86,7 +86,7 @@ pub use invalidation::{ DynamicEqHash, InvalidationReason, InvalidationReasonKind, InvalidationReasonSet, }; pub use join_iter_ext::{JoinIterExt, TryFlatJoinIterExt, TryJoinIterExt}; -pub use keyed_cell::keyed_cell; +pub use keyed_cell::{global_keyed_cell, keyed_cell}; pub use manager::{ dynamic_call, emit, get_invalidator, mark_finished, mark_stateful, run_once, run_once_with_reason, spawn_blocking, spawn_thread, trait_call, turbo_tasks, CurrentCellRef, diff --git a/crates/turbo-tasks/src/task/concrete_task_input.rs b/crates/turbo-tasks/src/task/concrete_task_input.rs index e44e4f7ffa9c9..fb360e9865a9b 100644 --- a/crates/turbo-tasks/src/task/concrete_task_input.rs +++ b/crates/turbo-tasks/src/task/concrete_task_input.rs @@ -322,7 +322,7 @@ impl<'de> Deserialize<'de> for SharedValue { /// converted back into the argument types. This is handled by the [`TaskInput`] /// trait. #[allow(clippy::derived_hash_with_manual_eq)] -#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +#[derive(Debug, Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Default)] pub enum ConcreteTaskInput { TaskOutput(TaskId), TaskCell(TaskId, CellId), @@ -337,6 +337,7 @@ pub enum ConcreteTaskInput { I32(i32), U32(u32), U64(u64), + #[default] Nothing, SharedValue(SharedValue), TransientSharedValue(TransientSharedValue), diff --git a/crates/turbo-tasks/src/task/function.rs b/crates/turbo-tasks/src/task/function.rs index 422e56f1618b9..b2e2897cea57b 100644 --- a/crates/turbo-tasks/src/task/function.rs +++ b/crates/turbo-tasks/src/task/function.rs @@ -135,6 +135,8 @@ macro_rules! task_fn_impl { )* Ok(Box::new(move || { + let span = macro_helpers::tracing::trace_span!("turbo_tasks::function", name); + let _entered = span.enter(); let task_fn = task_fn.clone(); $( let $arg = $arg.clone(); @@ -142,7 +144,7 @@ macro_rules! task_fn_impl { Box::pin(macro_helpers::tracing::Instrument::instrument(async move { Output::try_into_raw_vc((task_fn)($($arg),*)) - }, macro_helpers::tracing::trace_span!("turbo_tasks::function", name))) + }, span.clone())) })) } } @@ -172,6 +174,8 @@ macro_rules! task_fn_impl { )* Ok(Box::new(move || { + let span = macro_helpers::tracing::trace_span!("turbo_tasks::function", name); + let _entered = span.enter(); let task_fn = task_fn.clone(); $( let $arg = $arg.clone(); @@ -181,7 +185,7 @@ macro_rules! task_fn_impl { let result = Output::try_into_raw_vc((task_fn)($($arg),*).await); macro_helpers::notify_scheduled_tasks(); result - }, macro_helpers::tracing::trace_span!("turbo_tasks::function", name))) + }, span.clone())) })) } } @@ -213,6 +217,8 @@ macro_rules! task_fn_impl { )* Ok(Box::new(move || { + let span = macro_helpers::tracing::trace_span!("turbo_tasks::function", name); + let _entered = span.enter(); let task_fn = task_fn.clone(); let recv = recv.clone(); $( @@ -225,7 +231,7 @@ macro_rules! task_fn_impl { let result = Output::try_into_raw_vc((task_fn)(recv, $($arg),*)); macro_helpers::notify_scheduled_tasks(); result - }, macro_helpers::tracing::trace_span!("turbo_tasks::function", name))) + }, span.clone())) })) } } @@ -271,6 +277,8 @@ macro_rules! task_fn_impl { )* Ok(Box::new(move || { + let span = macro_helpers::tracing::trace_span!("turbo_tasks::function", name); + let _entered = span.enter(); let task_fn = task_fn.clone(); let recv = recv.clone(); $( @@ -283,7 +291,7 @@ macro_rules! task_fn_impl { let result = >::Output::try_into_raw_vc((task_fn)(recv, $($arg),*).await); macro_helpers::notify_scheduled_tasks(); result - }, macro_helpers::tracing::trace_span!("turbo_tasks::function", name))) + }, span.clone())) })) } } diff --git a/crates/turbopack-build/src/chunking_context.rs b/crates/turbopack-build/src/chunking_context.rs index 09de7f2b58343..dceb37cae35b1 100644 --- a/crates/turbopack-build/src/chunking_context.rs +++ b/crates/turbopack-build/src/chunking_context.rs @@ -326,11 +326,16 @@ impl ChunkingContext for BuildChunkingContext { ) .await?; - let assets: Vec>> = chunks + let mut assets: Vec>> = chunks .iter() .map(|chunk| self.generate_chunk(*chunk)) .collect(); + // Resolve assets + for asset in assets.iter_mut() { + *asset = asset.resolve().await?; + } + Ok(Vc::cell(assets)) } diff --git a/crates/turbopack-convert-trace/src/main.rs b/crates/turbopack-convert-trace/src/main.rs index f9ddd2b977735..8669cd0bd4460 100644 --- a/crates/turbopack-convert-trace/src/main.rs +++ b/crates/turbopack-convert-trace/src/main.rs @@ -602,10 +602,10 @@ fn main() { if graph && !items.is_empty() { let parent_name = &*span.name; let mut groups = IndexMap::new(); - let mut self_items = Vec::new(); + let mut self_items = 0; fn add_items_to_groups<'a>( - groups: &mut IndexMap, Vec>, - self_items: &mut Vec, + groups: &mut IndexMap<(Cow<'a, str>, usize), Vec>, + self_items: &mut usize, spans: &mut Vec>, parent_count: &mut u32, parent_name: &str, @@ -615,7 +615,17 @@ fn main() { for item in items { match item { SpanItem::SelfTime { .. } => { - self_items.push(item); + if let Some(((key, _), last)) = groups.last_mut() { + if key == &Cow::Borrowed("SELF_TIME") { + last.push(item); + continue; + } + } + groups.insert( + (Cow::Borrowed("SELF_TIME"), *self_items), + vec![item], + ); + *self_items += 1; } SpanItem::Child(id) => { let key = spans[id].name.clone(); @@ -634,7 +644,7 @@ fn main() { ); add_to_span_counter(); } else { - let group = groups.entry(key).or_default(); + let group = groups.entry((key, 0)).or_default(); if !group.is_empty() { add_to_span_counter(); } @@ -653,12 +663,6 @@ fn main() { items, &mut add_to_span_counter, ); - if !self_items.is_empty() { - groups - .entry(Cow::Borrowed("SELF_TIME")) - .or_default() - .append(&mut self_items); - } let groups = groups.into_values().collect::>(); let mut new_items = Vec::new(); for group in groups { diff --git a/crates/turbopack-core/src/chunk/chunking.rs b/crates/turbopack-core/src/chunk/chunking.rs index ed14c881ac519..25e2063563b9f 100644 --- a/crates/turbopack-core/src/chunk/chunking.rs +++ b/crates/turbopack-core/src/chunk/chunking.rs @@ -10,11 +10,9 @@ use indexmap::IndexMap; use once_cell::sync::Lazy; use regex::Regex; use tracing::Level; -use turbo_tasks::{keyed_cell, ReadRef, TryJoinIterExt, ValueToString, Vc}; +use turbo_tasks::{ReadRef, TryJoinIterExt, ValueToString, Vc}; -use super::{ - AsyncModuleInfo, Chunk, ChunkItem, ChunkItemsWithAsyncModuleInfo, ChunkType, ChunkingContext, -}; +use super::{AsyncModuleInfo, Chunk, ChunkItem, ChunkType, ChunkingContext}; use crate::output::{OutputAsset, OutputAssets}; /// Creates chunks based on heuristics for the passed `chunk_items`. Also @@ -40,7 +38,6 @@ pub async fn make_chunks( } let mut referenced_output_assets = Vc::cell(referenced_output_assets); - let other_referenced_output_assets = Vc::cell(Vec::new()); let mut chunks = Vec::new(); for (ty, chunk_items) in map { @@ -65,7 +62,7 @@ pub async fn make_chunks( chunking_context, chunks: &mut chunks, referenced_output_assets: &mut referenced_output_assets, - empty_referenced_output_assets: other_referenced_output_assets, + empty_referenced_output_assets: OutputAssets::empty().resolve().await?, }; app_vendors_split( @@ -128,16 +125,10 @@ async fn make_chunk( split_context.chunks.push( split_context.ty.chunk( split_context.chunking_context, - keyed_cell( - take(key), - ChunkItemsWithAsyncModuleInfo( - chunk_items - .into_iter() - .map(|(chunk_item, async_info, ..)| (chunk_item, async_info)) - .collect(), - ), - ) - .await?, + chunk_items + .into_iter() + .map(|(chunk_item, async_info, ..)| (chunk_item, async_info)) + .collect(), replace( split_context.referenced_output_assets, split_context.empty_referenced_output_assets, diff --git a/crates/turbopack-core/src/chunk/mod.rs b/crates/turbopack-core/src/chunk/mod.rs index 4facab9a60f2f..4a60cdfc56747 100644 --- a/crates/turbopack-core/src/chunk/mod.rs +++ b/crates/turbopack-core/src/chunk/mod.rs @@ -578,7 +578,7 @@ pub trait ChunkType: ValueToString { fn chunk( &self, chunking_context: Vc>, - chunk_items: Vc, + chunk_items: Vec, referenced_output_assets: Vc, ) -> Vc>; @@ -611,9 +611,6 @@ impl AsyncModuleInfo { pub type ChunkItemWithAsyncModuleInfo = (Vc>, Option>); -#[turbo_tasks::value(transparent)] -pub struct ChunkItemsWithAsyncModuleInfo(Vec); - pub trait ChunkItemExt: Send { /// Returns the module id of this chunk item. fn id(self: Vc) -> Vc; diff --git a/crates/turbopack-core/src/resolve/node.rs b/crates/turbopack-core/src/resolve/node.rs index c36ec18e7ac54..f456767dfc80f 100644 --- a/crates/turbopack-core/src/resolve/node.rs +++ b/crates/turbopack-core/src/resolve/node.rs @@ -35,3 +35,35 @@ pub fn node_cjs_resolve_options(root: Vc) -> Vc } .cell() } + +#[turbo_tasks::function] +pub fn node_esm_resolve_options(root: Vc) -> Vc { + let conditions: ResolutionConditions = [ + ("node".to_string(), ConditionValue::Set), + ("import".to_string(), ConditionValue::Set), + ] + .into(); + ResolveOptions { + extensions: vec![], + modules: vec![ResolveModules::Nested( + root, + vec!["node_modules".to_string()], + )], + into_package: vec![ + ResolveIntoPackage::ExportsField { + conditions: conditions.clone(), + unspecified_conditions: ConditionValue::Unset, + }, + ResolveIntoPackage::MainField("main".to_string()), + ResolveIntoPackage::Default("index.js".to_string()), + ResolveIntoPackage::Default("index.json".to_string()), + ResolveIntoPackage::Default("index.node".to_string()), + ], + in_package: vec![ResolveInPackage::ImportsField { + conditions, + unspecified_conditions: ConditionValue::Unset, + }], + ..Default::default() + } + .cell() +} diff --git a/crates/turbopack-css/src/chunk/mod.rs b/crates/turbopack-css/src/chunk/mod.rs index e690f1927550b..bc2057ac66b36 100644 --- a/crates/turbopack-css/src/chunk/mod.rs +++ b/crates/turbopack-css/src/chunk/mod.rs @@ -11,7 +11,7 @@ use turbo_tasks_fs::{rope::Rope, File, FileSystem}; use turbopack_core::{ asset::{Asset, AssetContent}, chunk::{ - AsyncModuleInfo, Chunk, ChunkItem, ChunkItemsWithAsyncModuleInfo, ChunkType, + AsyncModuleInfo, Chunk, ChunkItem, ChunkItemWithAsyncModuleInfo, ChunkType, ChunkableModule, ChunkingContext, ModuleId, OutputChunk, OutputChunkRuntimeInfo, }, code_builder::{Code, CodeBuilder}, @@ -411,13 +411,30 @@ impl ValueToString for CssChunkType { #[turbo_tasks::value_impl] impl ChunkType for CssChunkType { #[turbo_tasks::function] - fn chunk( + async fn chunk( &self, chunking_context: Vc>, - chunk_items: Vc, + chunk_items: Vec, referenced_output_assets: Vc, - ) -> Vc> { - css_chunk(chunking_context, chunk_items, referenced_output_assets) + ) -> Result>> { + let content = CssChunkContent { + chunk_items: chunk_items + .iter() + .map(|(chunk_item, _async_info)| async move { + let Some(chunk_item) = + Vc::try_resolve_downcast::>(*chunk_item).await? + else { + bail!("Chunk item is not an css chunk item but reporting chunk type css"); + }; + // CSS doesn't need to care about async_info, so we can discard it + Ok(chunk_item) + }) + .try_join() + .await?, + referenced_output_assets, + } + .cell(); + Ok(Vc::upcast(CssChunk::new(chunking_context, content))) } #[turbo_tasks::function] @@ -441,33 +458,6 @@ impl ChunkType for CssChunkType { } } -#[turbo_tasks::function] -async fn css_chunk( - chunking_context: Vc>, - chunk_items: Vc, - referenced_output_assets: Vc, -) -> Result>> { - let content = CssChunkContent { - chunk_items: chunk_items - .await? - .iter() - .map(|(chunk_item, _async_info)| async move { - let Some(chunk_item) = - Vc::try_resolve_downcast::>(*chunk_item).await? - else { - bail!("Chunk item is not an css chunk item but reporting chunk type css"); - }; - // CSS doesn't need to care about async_info, so we can discard it - Ok(chunk_item) - }) - .try_join() - .await?, - referenced_output_assets, - } - .cell(); - Ok(Vc::upcast(CssChunk::new(chunking_context, content))) -} - #[turbo_tasks::value_impl] impl ValueDefault for CssChunkType { #[turbo_tasks::function] diff --git a/crates/turbopack-dev/src/chunking_context.rs b/crates/turbopack-dev/src/chunking_context.rs index 0bc3317741e2b..08d103d85710f 100644 --- a/crates/turbopack-dev/src/chunking_context.rs +++ b/crates/turbopack-dev/src/chunking_context.rs @@ -360,6 +360,11 @@ impl ChunkingContext for DevChunkingContext { Value::new(EcmascriptDevChunkListSource::Dynamic), )); + // Resolve assets + for asset in assets.iter_mut() { + *asset = asset.resolve().await?; + } + Ok(Vc::cell(assets)) } @@ -399,6 +404,11 @@ impl ChunkingContext for DevChunkingContext { assets.push(self.generate_evaluate_chunk(ident, other_assets, evaluatable_assets)); + // Resolve assets + for asset in assets.iter_mut() { + *asset = asset.resolve().await?; + } + Ok(Vc::cell(assets)) } diff --git a/crates/turbopack-ecmascript/src/chunk/chunk_type.rs b/crates/turbopack-ecmascript/src/chunk/chunk_type.rs index 6b1fc9d2e5817..cdebbb66ebe0d 100644 --- a/crates/turbopack-ecmascript/src/chunk/chunk_type.rs +++ b/crates/turbopack-ecmascript/src/chunk/chunk_type.rs @@ -2,8 +2,7 @@ use anyhow::{bail, Result}; use turbo_tasks::{TryJoinIterExt, ValueDefault, ValueToString, Vc}; use turbopack_core::{ chunk::{ - AsyncModuleInfo, Chunk, ChunkItem, ChunkItemsWithAsyncModuleInfo, ChunkType, - ChunkingContext, + AsyncModuleInfo, Chunk, ChunkItem, ChunkItemWithAsyncModuleInfo, ChunkType, ChunkingContext, }, output::OutputAssets, }; @@ -30,7 +29,7 @@ impl ChunkType for EcmascriptChunkType { async fn chunk( &self, chunking_context: Vc>, - chunk_items: Vc, + chunk_items: Vec, referenced_output_assets: Vc, ) -> Result>> { let Some(chunking_context) = @@ -41,7 +40,6 @@ impl ChunkType for EcmascriptChunkType { }; let content = EcmascriptChunkContent { chunk_items: chunk_items - .await? .iter() .map(|(chunk_item, async_info)| async move { let Some(chunk_item) =