Skip to content

Avoid unnecessary work and allocations when instantiating type - #65035

Open
Jake Bailey (jakebailey) wants to merge 5 commits into
microsoft:mainfrom
jakebailey:perf/variable-free-instantiation
Open

Jake Bailey (jakebailey) wants to merge 5 commits into
microsoft:mainfrom
jakebailey:perf/variable-free-instantiation

Conversation

@jakebailey

@jakebailey Jake Bailey (jakebailey) commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

Thanks Steven (@teamchong) for finding these!

Many types passed to instantiation cannot contain type variables, and
whether they can is already cached in their object flags. Check that
cached bit inline at the top of instantiateTypeWithAlias so the common
"nothing to do" case doesn't go through an indirect call.

getPermissiveInstantiation and getRestrictiveInstantiation previously
did a map lookup and one or two map inserts for every non-primitive
type, even though instantiating a variable-free type always yields the
type itself. Return such types directly instead. The restrictive
self-entry is only consulted for conditional types, which are never
variable-free, so skipping it is unobservable.

instantiateSymbol unconditionally fetched the symbol's value links,
allocating them for symbols whose types were never resolved just to
find them empty. Only look the links up, and check the cheap
this-only mapper case first.

Co-authored-by: Steven Chong <[email protected]>
instantiateTypeAlias allocated a new TypeAlias on every call, even
though instantiateTypes already returns the original argument slice
when no argument changes. This happens frequently, e.g. for aliases
without type arguments or whose arguments are unaffected by the
mapper, and the result is passed along on most object, union and
indexed access instantiations.

Return the existing alias in that case, extending the copy-on-change
behavior of list instantiation to the alias itself. Aliases are never
mutated after being attached to a type, and are compared by content
rather than identity, so sharing them is safe.

Co-authored-by: Steven Chong <[email protected]>
When instantiating an anonymous, mapped or deferred object type, and
when instantiating a type reference, we computed the new type
arguments into a freshly allocated slice, then used them to look up an
existing instantiation. Most of these lookups hit, at which point the
slice was simply discarded.

Compute the type arguments into a stack buffer instead, look up the
cache with it, and only copy the arguments to the heap when a new
instantiation is actually created. For type references that need no
tuple normalization, the cache key computed for the lookup is reused
when creating the reference.

Co-authored-by: Steven Chong <[email protected]>
@typescript-automation typescript-automation Bot added Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Oct 29, 2026
@jakebailey Jake Bailey (jakebailey) added the Domain: Performance Reports of unusually slow behavior label Oct 29, 2026
@jakebailey

Copy link
Copy Markdown
Member Author

TypeScript Bot (@typescript-bot) perf test this faster

@typescript-automation

typescript-automation Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Starting jobs; this comment will be updated as builds start and complete.

Command Status Results
perf test this faster ✅ Started 👀 Results

@jakebailey
Jake Bailey (jakebailey) marked this pull request as ready for review October 29, 2026 21:34
Copilot AI balanced review requested due to automatic review settings October 29, 2026 21:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unconditional cloning of already-owned type-argument slices introduces redundant allocations and copies on cache misses in both type-reference and anonymous-type instantiation paths.

2 open issues
What changed in this PR

This PR reduces unnecessary work and allocations during type instantiation in the native TypeScript checker.

Changes:

  • Avoids allocating symbol links unnecessarily and reuses unchanged type aliases.
  • Uses temporary argument buffers and checks caches before retaining new instantiations.
  • Adds a shared type-variable-free check to skip unnecessary instantiation work.
File Description
tsc/​internal/​checker/​checker.go Optimizes symbol, type-reference, and object instantiation through early returns, temporary buffers, and cache reuse.

Review effort: Balanced

Comment thread tsc/internal/checker/checker.go Outdated
Comment thread tsc/internal/checker/checker.go Outdated
When more type arguments are instantiated than fit in the stack
buffer, the list is already freshly allocated and owned by the
caller. Cloning it again before creating a new instantiation added a
second allocation and copy on every cache miss, making these cases
more expensive than before the buffer was introduced.

Only clone arguments that were written into the buffer, and pass
heap-allocated lists through as-is.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Temporary argument buffers still escape to the heap in both instantiation paths, causing avoidable allocations for unchanged arguments and cache hits, plus extra allocations on small-argument cache misses.

No open issues 🎉

1 previously missed issue

In code that hasn't changed since last review

Medium severity Prevent temporary buffer escape and excess allocations

tsc/​internal/​checker/​checker.go:22991

The conditional clone leaves an escape path from buf to newTypeReferenceInstantiation, so the temporary buffer is heap-allocated even when the arguments are unchanged or the cache hits. The same issue occurs in getObjectTypeInstantiation at line 23073, where small-argument cache misses also allocate the cloned slice in addition to the buffer. Separate temporary storage from retained argument storage so neither buffer can escape, then verify allocation counts for unchanged arguments, cache hits, and cache misses.

2 resolved since last review

Review effort: Balanced

@typescript-automation

Copy link
Copy Markdown
Contributor

Jake Bailey (@jakebailey)
The results of the perf run you requested are in!

Here they are:

tsc

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Compiler-Unions - native
Errors 41 41 ~ ~ ~ p=1.000 n=20
Symbols 88,466 88,466 ~ ~ ~ p=1.000 n=20
Types 79,607 79,607 ~ ~ ~ p=1.000 n=20
Memory Used 104,147k (± 0.03%) 104,120k (± 0.02%) ~ 104,019k 104,215k p=0.465 n=20
Memory Allocs 1,263,790 (± 0.01%) 1,254,200 (± 0.01%) -9,590 (- 0.76%) 1,253,799 1,254,494 p=0.000 n=20
Config Time 0.000s 0.000s ~ ~ ~ p=1.000 n=20
Parse Time 0.022s (± 2.36%) 0.023s (± 2.03%) ~ 0.021s 0.025s p=0.183 n=20
Bind Time 0.008s (± 3.69%) 0.008s (± 6.60%) ~ 0.007s 0.012s p=0.689 n=20
Check Time 0.214s (± 1.17%) 0.214s (± 1.18%) ~ 0.207s 0.229s p=0.920 n=20
Emit Time 0.138s (± 1.23%) 0.137s (± 0.97%) ~ 0.131s 0.146s p=0.651 n=20
Total Time 0.385s (± 0.83%) 0.386s (± 0.77%) ~ 0.377s 0.398s p=0.560 n=20
angular-1 - native
Errors 3 3 ~ ~ ~ p=1.000 n=20
Symbols 586,480 (± 0.01%) 586,548 (± 0.02%) ~ 586,154 586,787 p=0.199 n=20
Types 241,688 (± 0.00%) 241,687 (± 0.00%) ~ 241,683 241,690 p=0.962 n=20
Memory Used 517,909k (± 0.02%) 517,836k (± 0.02%) ~ 517,424k 518,210k p=0.344 n=20
Memory Allocs 7,805,394 (± 0.12%) 7,790,668 (± 0.30%) -14,725 (- 0.19%) 7,762,169 7,939,910 p=0.000 n=20
Config Time 0.009s (± 2.78%) 0.009s (± 2.52%) ~ 0.008s 0.009s p=0.514 n=20
Parse Time 0.129s (± 3.65%) 0.129s (± 2.07%) ~ 0.120s 0.139s p=0.233 n=20
Bind Time 0.050s (±11.10%) 0.045s (± 8.18%) ~ 0.040s 0.070s p=0.164 n=20
Check Time 0s 0s ~ ~ ~ p=1.000 n=20
Emit Time 0.886s (± 1.54%) 0.881s (± 1.23%) ~ 0.863s 0.949s p=0.644 n=20
Total Time 1.085s (± 1.76%) 1.076s (± 1.31%) ~ 1.049s 1.161s p=0.663 n=20
arktype - native
Errors 0 0 ~ ~ ~ p=1.000 n=20
Symbols 685,920 685,920 ~ ~ ~ p=1.000 n=20
Types 939,467 939,467 ~ ~ ~ p=1.000 n=20
Memory Used 497,299k (± 0.01%) 495,464k (± 0.01%) -1,836k (- 0.37%) 495,291k 495,691k p=0.000 n=20
Memory Allocs 12,108,850 (± 0.02%) 11,289,251 (± 0.02%) 🟩-819,599 (- 6.77%) 11,283,876 11,301,116 p=0.000 n=20
Config Time 0.001s 0.001s ~ ~ ~ p=1.000 n=20
Parse Time 0.042s (± 3.37%) 0.042s (± 3.16%) ~ 0.036s 0.046s p=0.602 n=20
Bind Time 0.013s (±10.40%) 0.013s (± 9.26%) ~ 0.011s 0.018s p=0.793 n=20
Check Time 0.965s (± 0.52%) 0.962s (± 0.46%) ~ 0.947s 0.985s p=0.180 n=20
Emit Time 0.000s 0.000s ~ ~ ~ p=1.000 n=20
Total Time 1.050s (± 0.48%) 1.046s (± 0.42%) ~ 1.033s 1.069s p=0.189 n=20
class-transformer - native
Errors 0 0 ~ ~ ~ p=1.000 n=20
Symbols 45,376 45,376 ~ ~ ~ p=1.000 n=20
Types 7,573 7,573 ~ ~ ~ p=1.000 n=20
Memory Used 27,836k (± 0.02%) 27,829k (± 0.02%) -7k (- 0.03%) 27,803k 27,865k p=0.034 n=20
Memory Allocs 248,630 (± 0.05%) 248,025 (± 0.06%) -605 (- 0.24%) 247,474 248,587 p=0.000 n=20
Config Time 0.000s 0.000s ~ ~ ~ p=1.000 n=20
Parse Time 0.012s (± 3.09%) 0.012s (± 2.54%) ~ 0.010s 0.013s p=0.283 n=20
Bind Time 0.004s (±11.18%) 0.004s (±15.06%) ~ 0.002s 0.007s p=0.504 n=20
Check Time 0.008s (± 5.20%) 0.008s (± 4.98%) ~ 0.007s 0.010s p=0.933 n=20
Emit Time 0.009s (± 5.77%) 0.009s (± 7.68%) ~ 0.007s 0.012s p=0.876 n=20
Total Time 0.032s (± 1.87%) 0.033s (± 3.16%) ~ 0.028s 0.040s p=0.851 n=20
effect - native
Errors 12 12 ~ ~ ~ p=1.000 n=20
Symbols 1,235,115 1,235,115 ~ ~ ~ p=1.000 n=20
Types 894,113 894,113 ~ ~ ~ p=1.000 n=20
Memory Used 940,517k (± 0.01%) 939,961k (± 0.02%) -556k (- 0.06%) 939,349k 940,706k p=0.000 n=20
Memory Allocs 12,671,890 (± 0.02%) 12,405,573 (± 0.04%) -266,317 (- 2.10%) 12,396,235 12,441,799 p=0.000 n=20
Config Time 0.002s 0.002s (± 6.84%) ~ 0.002s 0.003s p=0.487 n=20
Parse Time 0.150s (± 1.82%) 0.149s (± 1.78%) ~ 0.139s 0.161s p=0.743 n=20
Bind Time 0.000s 0.000s ~ ~ ~ p=1.000 n=20
Check Time 0.940s (± 0.87%) 0.934s (± 0.80%) ~ 0.906s 0.959s p=0.365 n=20
Emit Time 0.500s (± 2.35%) 0.501s (± 2.03%) ~ 0.466s 0.530s p=0.909 n=20
Total Time 1.685s (± 0.51%) 1.680s (± 0.49%) ~ 1.648s 1.705s p=0.465 n=20
mui-docs - native
Errors 11,405 11,405 ~ ~ ~ p=1.000 n=20
Symbols 3,784,019 3,784,019 ~ ~ ~ p=1.000 n=20
Types 1,355,974 1,355,974 ~ ~ ~ p=1.000 n=20
Memory Used 1,836,371k (± 0.06%) 1,835,665k (± 0.07%) ~ 1,829,905k 1,840,949k p=0.327 n=20
Memory Allocs 26,017,585 (± 0.13%) 25,069,522 (± 0.13%) 🟩-948,063 (- 3.64%) 24,989,366 25,226,487 p=0.000 n=20
Config Time 0.009s (± 1.61%) 0.009s (± 7.60%) ~ 0.008s 0.015s p=0.560 n=20
Parse Time 0.298s (± 2.20%) 0.306s (± 3.17%) ~ 0.281s 0.364s p=0.267 n=20
Bind Time 0.001s (±18.96%) 0.001s (± 9.93%) ~ 0.001s 0.002s p=1.000 n=20
Check Time 3.287s (± 0.73%) 3.285s (± 0.85%) ~ 3.177s 3.377s p=0.952 n=20
Emit Time 0.255s (± 1.53%) 0.264s (± 4.18%) ~ 0.246s 0.329s p=0.297 n=20
Total Time 4.362s (± 0.75%) 4.383s (± 0.62%) ~ 4.300s 4.486s p=0.159 n=20
sentry - native
Errors 2 2 ~ ~ ~ p=1.000 n=20
Symbols 4,793,245 4,793,245 ~ ~ ~ p=1.000 n=20
Types 2,607,045 2,607,045 ~ ~ ~ p=1.000 n=20
Memory Used 2,880,551k (± 0.03%) 2,878,820k (± 0.03%) -1,730k (- 0.06%) 2,875,779k 2,882,003k p=0.008 n=20
Memory Allocs 75,290,662 (± 0.25%) 74,384,367 (± 0.51%) -906,295 (- 1.20%) 73,757,108 76,345,422 p=0.000 n=20
Config Time 0.025s (± 1.48%) 0.025s (± 1.33%) ~ 0.024s 0.026s p=0.652 n=20
Parse Time 0.482s (± 4.98%) 0.483s (± 4.77%) ~ 0.428s 0.605s p=0.888 n=20
Bind Time 0.153s (± 9.13%) 0.177s (±10.47%) ~ 0.137s 0.242s p=0.142 n=20
Check Time 6.817s (± 1.16%) 6.765s (± 1.21%) ~ 6.585s 7.129s p=0.351 n=20
Emit Time 0.000s 0.000s ~ ~ ~ p=1.000 n=20
Total Time 7.523s (± 1.19%) 7.505s (± 1.09%) ~ 7.301s 7.814s p=0.693 n=20
social-app - native
Errors 0 0 ~ ~ ~ p=1.000 n=20
Symbols 1,883,074 1,883,074 ~ ~ ~ p=1.000 n=20
Types 1,158,168 1,158,168 ~ ~ ~ p=1.000 n=20
Memory Used 972,538k (± 0.01%) 971,299k (± 0.02%) -1,239k (- 0.13%) 970,642k 971,962k p=0.000 n=20
Memory Allocs 13,592,734 (± 0.27%) 12,768,191 (± 0.14%) 🟩-824,543 (- 6.07%) 12,712,722 12,862,193 p=0.000 n=20
Config Time 0.008s 0.008s ~ ~ ~ p=1.000 n=20
Parse Time 0.158s (± 2.02%) 0.158s (± 1.44%) ~ 0.150s 0.166s p=0.846 n=20
Bind Time 0.048s (±11.56%) 0.044s (± 8.72%) ~ 0.039s 0.066s p=0.412 n=20
Check Time 1.474s (± 0.59%) 1.474s (± 0.48%) ~ 1.446s 1.511s p=0.973 n=20
Emit Time 0.000s 0.000s ~ ~ ~ p=1.000 n=20
Total Time 1.704s (± 0.57%) 1.700s (± 0.37%) ~ 1.682s 1.735s p=0.763 n=20
strada-build-src - native
Errors 0 0 ~ ~ ~ p=1.000 n=20
Symbols 1,184,972 1,184,972 ~ ~ ~ p=1.000 n=20
Types 438,963 438,963 ~ ~ ~ p=1.000 n=20
Memory Used 1,166,783k (± 0.31%) 1,164,505k (± 0.34%) ~ 1,148,248k 1,185,865k p=0.341 n=20
Memory Allocs 47,638,867 (± 0.09%) 47,187,221 (± 0.11%) -451,646 (- 0.95%) 47,007,245 47,403,284 p=0.000 n=20
Config Time 0.002s (±14.66%) 0.002s (±15.95%) ~ 0.001s 0.003s p=0.962 n=20
Parse Time 0.141s (± 1.86%) 0.142s (± 1.62%) ~ 0.133s 0.153s p=0.489 n=20
Bind Time 0.000s 0.000s ~ ~ ~ p=1.000 n=20
Check Time 0.825s (± 0.90%) 0.827s (± 0.78%) ~ 0.803s 0.851s p=0.753 n=20
Emit Time 0.140s (± 1.51%) 0.142s (± 2.05%) ~ 0.132s 0.161s p=0.150 n=20
Total Time 9.565s (± 0.65%) 9.595s (± 0.81%) ~ 9.344s 9.870s p=0.602 n=20
strada-compiler - native
Errors 0 0 ~ ~ ~ p=1.000 n=20
Symbols 263,511 263,511 ~ ~ ~ p=1.000 n=20
Types 196,116 196,116 ~ ~ ~ p=1.000 n=20
Memory Used 224,595k (± 0.02%) 224,615k (± 0.01%) ~ 224,492k 224,702k p=0.457 n=20
Memory Allocs 2,401,359 (± 0.01%) 2,375,919 (± 0.01%) -25,441 (- 1.06%) 2,375,118 2,376,822 p=0.000 n=20
Config Time 0.000s 0.000s ~ ~ ~ p=1.000 n=20
Parse Time 0.052s (± 3.71%) 0.053s (± 3.36%) ~ 0.046s 0.060s p=0.930 n=20
Bind Time 0.000s 0.000s ~ ~ ~ p=1.000 n=20
Check Time 0.410s (± 1.33%) 0.407s (± 1.16%) ~ 0.392s 0.423s p=0.409 n=20
Emit Time 0.051s (± 6.89%) 0.049s (± 4.77%) ~ 0.042s 0.057s p=0.329 n=20
Total Time 0.544s (± 1.20%) 0.537s (± 0.67%) -0.007s (- 1.33%) 0.519s 0.552s p=0.028 n=20
t3code-server - native
Errors 0 0 ~ ~ ~ p=1.000 n=20
Symbols 4,350,661 4,350,661 ~ ~ ~ p=1.000 n=20
Types 3,040,644 3,040,644 ~ ~ ~ p=1.000 n=20
Memory Used 2,434,117k (± 0.03%) 2,430,858k (± 0.03%) -3,259k (- 0.13%) 2,428,930k 2,434,989k p=0.000 n=20
Memory Allocs 37,388,766 (± 0.08%) 34,730,279 (± 0.05%) 🟩-2,658,488 (- 7.11%) 34,669,029 34,808,764 p=0.000 n=20
Config Time 0.003s 0.003s ~ ~ ~ p=1.000 n=20
Parse Time 0.257s (± 1.71%) 0.262s (± 2.54%) ~ 0.230s 0.289s p=0.223 n=20
Bind Time 0.097s (±11.36%) 0.094s (±11.29%) ~ 0.077s 0.142s p=0.430 n=20
Check Time 7.335s (± 0.39%) 7.352s (± 0.61%) ~ 7.256s 7.677s p=0.703 n=20
Emit Time 0.000s 0.000s ~ ~ ~ p=1.000 n=20
Total Time 7.703s (± 0.39%) 7.722s (± 0.58%) ~ 7.634s 8.051s p=0.713 n=20
tanstack-router - native
Errors 1 1 ~ ~ ~ p=1.000 n=20
Symbols 571,756 571,756 ~ ~ ~ p=1.000 n=20
Types 397,689 397,689 ~ ~ ~ p=1.000 n=20
Memory Used 331,403k (± 0.01%) 331,226k (± 0.01%) -178k (- 0.05%) 331,072k 331,405k p=0.000 n=20
Memory Allocs 4,391,670 (± 0.14%) 4,092,817 (± 0.19%) 🟩-298,853 (- 6.80%) 4,074,592 4,126,394 p=0.000 n=20
Config Time 0.001s 0.001s ~ ~ ~ p=1.000 n=20
Parse Time 0.041s (± 3.63%) 0.040s (± 4.73%) ~ 0.035s 0.049s p=0.084 n=20
Bind Time 0.013s (± 3.91%) 0.015s (±12.33%) ~ 0.012s 0.022s p=0.138 n=20
Check Time 0.587s (± 0.56%) 0.589s (± 0.63%) ~ 0.573s 0.600s p=0.323 n=20
Emit Time 0.000s 0.000s ~ ~ ~ p=1.000 n=20
Total Time 0.663s (± 0.54%) 0.663s (± 0.77%) ~ 0.641s 0.684s p=0.773 n=20
ts-pre-modules - native
Errors 87 87 ~ ~ ~ p=1.000 n=20
Symbols 231,616 231,616 ~ ~ ~ p=1.000 n=20
Types 181,195 181,195 ~ ~ ~ p=1.000 n=20
Memory Used 193,527k (± 0.01%) 193,515k (± 0.02%) ~ 193,383k 193,647k p=0.560 n=20
Memory Allocs 1,318,215 (± 0.02%) 1,291,890 (± 0.01%) -26,325 (- 2.00%) 1,291,298 1,292,926 p=0.000 n=20
Config Time 0.000s 0.000s ~ ~ ~ p=1.000 n=20
Parse Time 0.043s (± 3.13%) 0.042s (± 2.67%) ~ 0.037s 0.046s p=0.239 n=20
Bind Time 0.022s (± 5.20%) 0.022s (± 5.52%) ~ 0.016s 0.026s p=0.720 n=20
Check Time 0.295s (± 1.20%) 0.297s (± 1.13%) ~ 0.287s 0.308s p=0.198 n=20
Emit Time 0.000s 0.000s ~ ~ ~ p=1.000 n=20
Total Time 0.366s (± 0.90%) 0.367s (± 0.89%) ~ 0.355s 0.379s p=0.507 n=20
vscode - native
Errors 11 11 ~ ~ ~ p=1.000 n=20
Symbols 7,495,436 7,495,436 ~ ~ ~ p=1.000 n=20
Types 4,398,006 4,398,006 ~ ~ ~ p=1.000 n=20
Memory Used 5,194,576k (± 0.02%) 5,188,625k (± 0.01%) -5,951k (- 0.11%) 5,186,032k 5,191,708k p=0.000 n=20
Memory Allocs 56,816,888 (± 0.03%) 56,427,455 (± 0.02%) -389,432 (- 0.69%) 56,410,273 56,479,229 p=0.000 n=20
Config Time 0.034s (± 1.28%) 0.034s (± 1.24%) ~ 0.033s 0.036s p=0.432 n=20
Parse Time 0.914s (± 1.87%) 0.917s (± 1.18%) ~ 0.852s 0.956s p=0.380 n=20
Bind Time 0.342s (± 8.77%) 0.334s (± 6.96%) ~ 0.304s 0.531s p=0.433 n=20
Check Time 8.029s (± 0.95%) 8.069s (± 0.97%) ~ 7.783s 8.365s p=0.512 n=20
Emit Time 2.892s (± 5.06%) 2.793s (± 4.03%) ~ 2.641s 3.763s p=0.410 n=20
Total Time 12.269s (± 1.16%) 12.206s (± 1.17%) ~ 11.758s 13.098s p=0.525 n=20
webpack - native
Errors 616 616 ~ ~ ~ p=1.000 n=20
Symbols 917,188 917,188 ~ ~ ~ p=1.000 n=20
Types 636,859 636,859 ~ ~ ~ p=1.000 n=20
Memory Used 693,532k (± 0.02%) 693,036k (± 0.01%) -496k (- 0.07%) 692,757k 693,348k p=0.000 n=20
Memory Allocs 6,500,898 (± 0.04%) 6,409,719 (± 0.05%) -91,178 (- 1.40%) 6,399,001 6,423,214 p=0.000 n=20
Config Time 0.004s 0.004s ~ ~ ~ p=1.000 n=20
Parse Time 0.140s (± 3.27%) 0.147s (± 3.89%) 🔻+0.008s (+ 5.36%) 0.126s 0.182s p=0.048 n=20
Bind Time 0.048s (±18.76%) 0.049s (±11.20%) ~ 0.039s 0.075s p=0.420 n=20
Check Time 1.165s (± 1.04%) 1.185s (± 3.08%) ~ 1.139s 1.508s p=0.387 n=20
Emit Time 0.000s 0.000s ~ ~ ~ p=1.000 n=20
Total Time 1.380s (± 1.01%) 1.410s (± 2.60%) ~ 1.350s 1.719s p=0.101 n=20
xstate-main - native
Errors 0 0 ~ ~ ~ p=1.000 n=20
Symbols 640,490 640,490 ~ ~ ~ p=1.000 n=20
Types 387,984 387,984 ~ ~ ~ p=1.000 n=20
Memory Used 350,902k (± 0.02%) 350,777k (± 0.02%) -125k (- 0.04%) 350,491k 351,190k p=0.009 n=20
Memory Allocs 3,991,533 (± 0.08%) 3,782,135 (± 0.07%) 🟩-209,398 (- 5.25%) 3,772,720 3,794,335 p=0.000 n=20
Config Time 0.001s 0.001s ~ ~ ~ p=1.000 n=20
Parse Time 0.061s (± 2.07%) 0.060s (± 2.94%) ~ 0.055s 0.067s p=0.633 n=20
Bind Time 0.022s (± 8.15%) 0.024s (± 9.36%) ~ 0.019s 0.033s p=0.223 n=20
Check Time 0.455s (± 0.75%) 0.453s (± 0.70%) ~ 0.443s 0.468s p=0.702 n=20
Emit Time 0.000s 0.000s ~ ~ ~ p=1.000 n=20
Total Time 0.545s (± 0.71%) 0.544s (± 0.82%) ~ 0.527s 0.559s p=0.909 n=20
System info unknown
Hosts
  • native
Scenarios
  • Compiler-Unions - native
  • angular-1 - native
  • arktype - native
  • class-transformer - native
  • effect - native
  • mui-docs - native
  • sentry - native
  • social-app - native
  • strada-build-src - native
  • strada-compiler - native
  • t3code-server - native
  • tanstack-router - native
  • ts-pre-modules - native
  • vscode - native
  • webpack - native
  • xstate-main - native
Benchmark Name Iterations
Current pr 20
Baseline baseline 20

Developer Information:

Download Benchmarks

@jakebailey

Jake Bailey (jakebailey) commented Oct 29, 2026 •

Copy link
Copy Markdown
Member Author

This helps a little, but, not really that much? Certainly alloc count though.

Escape analysis does not consider control flow. Because the variable
that could point into the stack buffer was also handed to code that
retains it, the buffer was moved to the heap on every call, including
the unchanged and cache-hit paths that were meant to be allocation
free.

Keep retained arguments in a separate variable that is only assigned
from a fresh allocation or a copy, so the buffer never flows into
retained storage and can stay on the stack.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

There are no active review issues blocking the type-instantiation optimizations.

No open issues 🎉

Review effort: Balanced

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Author: Team Domain: Performance Reports of unusually slow behavior For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants