[turbotask] Make turbotask function registration const#90797
[turbotask] Make turbotask function registration const#90797
Conversation
Tests Passed |
Merging this PR will not alter performance
Comparing Footnotes
|
Stats from current PR🔴 1 regression
📊 All Metrics📖 Metrics GlossaryDev Server Metrics:
Build Metrics:
Change Thresholds:
⚡ Dev Server
📦 Dev Server (Webpack) (Legacy)📦 Dev Server (Webpack)
⚡ Production Builds
📦 Production Builds (Webpack) (Legacy)📦 Production Builds (Webpack)
📦 Bundle SizesBundle Sizes⚡ TurbopackClient Main Bundles: **401 kB** → **401 kB** ✅ -41 B80 files with content-based hashes (individual files not comparable between builds) Server Middleware
Build DetailsBuild Manifests
📦 WebpackClient Main Bundles
Polyfills
Pages
Server Edge SSR
Middleware
Build DetailsBuild Manifests
Build Cache
🔄 Shared (bundler-independent)Runtimes
📝 Changed Files (9 files)Files with changes:
View diffsapp-page-exp..ntime.dev.jsfailed to diffapp-page-exp..time.prod.jsDiff too large to display app-page-tur..ntime.dev.jsfailed to diffapp-page-tur..time.prod.jsDiff too large to display app-page-tur..ntime.dev.jsfailed to diffapp-page-tur..time.prod.jsDiff too large to display app-page.runtime.dev.jsfailed to diffapp-page.runtime.prod.jsDiff too large to display server.runtime.prod.jsDiff too large to display 📎 Tarball URL |
| #![feature(sync_unsafe_cell)] | ||
| #![feature(async_fn_traits)] | ||
| #![feature(impl_trait_in_assoc_type)] | ||
| #![feature(const_type_name)] |
There was a problem hiding this comment.
reading through the discussion upstream i don't have a lot of hope for this being stabilized any time soon.
This isn't the biggest deal i guess given all the other nightly features we rely on....
i guess if we really needed to drop it we could always code gen a function that computes the type name and pass a reference to that to the struct? would that work?
There was a problem hiding this comment.
I am pretty sure I can get rid of the need for this feature down the line. There's no actual need for it, but it makes this part of the work far easier.
# What
Make turbotask function registration const -- all function registration
blocks are true &'static items, compiled directly into the binary.
Removes a few thousand allocations of type names and boxed impls of
TaskFn.
# Why
We have approx 2k functions, so the cost of Lazy construction +
temporary allocations adds up (even with compiler optimization). This
also unlocks the opportunity for further startup optimizations (in later
PRs).
# How
The `#[turbo_tasks::function]` macro now generates static items
initialized directly with const fn constructors instead of `Lazy::new(||
...)`, using `const { &into_task_fn(f) as &dyn TaskFn }` blocks to
produce `&'static dyn TaskFn` trait objects at compile time from
zero-sized function items.
Global names that previously required runtime format!() + Box::leak()
are now computed at compile time via `const_type_name()` (a const
wrapper around `std::any::type_name`) and a `const_concat!` macro that
concatenates string slices into a fixed-size byte array.
The NativeFunction struct, ArgMeta, and the
into_task_fn/into_task_fn_with_this wrappers are all const
fn-constructible, with input types inferred through a TaskFnInputs trait
that maps wrapper types to their argument tuples (we use a non-allocated
and non-compiled temporary "duplicate" `TaskFn` instance that is only
useful for type inference in a const context).
# Next Steps
I believe we can remove the const `type_name` in favour of the const
`type_id` and instead pull function names only when needed for display
purposes. This will show up in a future PR.
We can also remove non-const registration for things that aren't
functions as well, though I believe this is less important.

What
Make turbotask function registration const -- all function registration blocks are true &'static items, compiled directly into the binary. Removes a few thousand allocations of type names and boxed impls of TaskFn.
Why
We have approx 2k functions, so the cost of Lazy construction + temporary allocations adds up (even with compiler optimization). This also unlocks the opportunity for further startup optimizations (in later PRs).
How
The
#[turbo_tasks::function]macro now generates static items initialized directly with const fn constructors instead ofLazy::new(|| ...), usingconst { &into_task_fn(f) as &dyn TaskFn }blocks to produce&'static dyn TaskFntrait objects at compile time from zero-sized function items.Global names that previously required runtime format!() + Box::leak() are now computed at compile time via
const_type_name()(a const wrapper aroundstd::any::type_name) and aconst_concat!macro that concatenates string slices into a fixed-size byte array.The NativeFunction struct, ArgMeta, and the into_task_fn/into_task_fn_with_this wrappers are all const fn-constructible, with input types inferred through a TaskFnInputs trait that maps wrapper types to their argument tuples (we use a non-allocated and non-compiled temporary "duplicate"
TaskFninstance that is only useful for type inference in a const context).Next Steps
I believe we can remove the const
type_namein favour of the consttype_idand instead pull function names only when needed for display purposes. This will show up in a future PR.We can also remove non-const registration for things that aren't functions as well, though I believe this is less important.