Files
Luke SandbergandGitHub dc856d6c33 [turbopack] Optimize TaskInput implementations (#94202)
# What

Replace the `derive` macros for TaskInput with a proc macro
`[turbo_tasks::task_input]` (and analogous support inside of the
`turbo_tasks::value` macro.

Introduce a hand written `CloneResolved` future type for TaskInput
implementations that are always resolved.

# Why

This allows us to take advantage of the `NonLocalValue` marker trait. If
a type is `NonLocalValue` then `TaskInput` can have trivial
`is_resolved` and `resolve_input` implementations. This applies to the
vast majority of TaskInputs but the current `derive` implementation
always produces a recursive `async` `resolve_input` implementation but
it is rarely needed and rustc/llvm do a bad job of optimizing it.

## Code-size impact

`next-swc.darwin-arm64.node` — release profile, `pnpm swc-build-native
--release`, macOS aarch64.

| Metric | canary | this branch | Δ bytes | Δ % |
| --- | ---: | ---: | ---: | ---: |
| Raw `.node` | 124,494,592 | 124,217,280 | −277,312 | −0.22% |
| Stripped (`strip -x`) | 84,294,000 | 84,013,136 | −280,864 | −0.33% |
| Stripped + gzip -9 | 29,123,538 | 28,898,920 | −224,618 | −0.77% |

## Performance

A similar measurement of performance was neutral

| Metric | canary | temporary | Δ | % |
|---|---|---|---|---|
| wall time (s) | 42.659 ± 1.851 | 42.501 ± 2.028 | −0.158 | −0.4% |
| user time (s) | 294.322 ± 1.834 | 293.207 ± 2.070 | −1.115 | −0.4% |
| sys time (s) | 74.158 ± 4.197 | 73.543 ± 5.725 | −0.615 | −0.8% |
| MaxRSS (MB) | 13650.1 ± 66.0 | 13610.1 ± 57.5 | −40.0 | −0.3% |

All deltas are smaller than one standard deviation — statistically
indistinguishable from noise on this benchmark, as expected for a small
optimization.
2026-06-03 23:26:17 +00:00

39 lines
1.3 KiB
Rust

//! Tests for the `#[turbo_tasks::task_input(contains_unresolved_vcs)]` macro are in `turbo_tasks`
//! itself. However, we keep one test here as an integration test between the derive
//! macro and the `#[turbo_tasks::function]` macro.
#![allow(clippy::needless_return)] // tokio macro-generated code doesn't respect this
use anyhow::Result;
use bincode::{Decode, Encode};
use turbo_tasks::{Completion, ReadRef, Vc, trace::TraceRawVcs};
use turbo_tasks_testing::{Registration, register, run_once};
static REGISTRATION: Registration = register!();
#[turbo_tasks::task_input]
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encode, Decode, TraceRawVcs)]
struct OneUnnamedField(u32);
#[turbo_tasks::function]
fn one_unnamed_field(input: OneUnnamedField) -> Vc<Completion> {
assert_eq!(input.0, 42);
Completion::immutable()
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn tests() {
run_once(&REGISTRATION, || async {
#[turbo_tasks::function(operation, root)]
async fn equality_operation() -> Result<Vc<bool>> {
Ok(Vc::cell(ReadRef::ptr_eq(
&one_unnamed_field(OneUnnamedField(42)).await?,
&Completion::immutable().await?,
)))
}
equality_operation().read_strongly_consistent().await?;
anyhow::Ok(())
})
.await
.unwrap()
}