[pull] main from react:main - #643

Merged
pull[bot] merged 4 commits into
code:mainfrom
react:main
Aug 24, 2026
Merged

[pull] main from react:main#643
pull[bot] merged 4 commits into
code:mainfrom
react:main

Conversation

@pull

@pullpullBot commented Aug 24, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

andrewimmand others added 4 commits August 24, 2026 13:38
…7225)
## Summary
By replicating the `IndexSet` behavior with a simple inline array, this
is able to avoid any heap allocation / memory thrash for
`AbstractValue`. It also reduces the size of AbstractValue from 72 bytes
+ all of the heap allocations, to only 18 bytes.
## How did you test this change?
Ran all of the fixtures to confirm byte output is identical.
Effects on memory and compile time:
| Benchmark | Peak allocation | Allocation count | Wall time |
|------------------|-----------------------------|------------------|-----------|
| legacy/image.tsx | 58.21 -> 33.40 MiB (-42.6%) | -51.1% | -39.5% |
| next-client | 58.21 -> 33.40 (-42.6%) | -40.5% | -25.1% |
| devtools | 26.39 -> 16.29 (-38.3%) | -26.7% | -14.8% |
| fixtures | 17.35 → 9.41 (-45.8%) | -9.9% | -9.0% |
## Summary
In the mutation / aliasing inference, the state is used twice, and both
get cloned. Only one clone is necessary, the second can be safely moved.
This has minimal impact on peak memory usage, but it does reduce wall
time by *10%* on real Next.js benchmark apps.
## How did you test this change?
Ran against benchmark apps to confirm identical byte output.
Ran against the 1800+ Rust Compiler test fixtures.
tl;dr this reduces peak memory allocation by 5-15%, and reduces codegen
time by 30-70% depending on payload. On heavy components with deep ASTs
the impact is more exaggerated.
## Summary
Codegen of temp vars records the expressions they replaced, so that they
can be unwound. In the TS version this uses a `Map` and stores pointers
to AST nodes - relatively cheap. For borrow-checking reasons, the Rust
version clones the AST. This results in recurring deep clones, making
codegen accidentally quadratic and using significant amounts of memory.
This introduces a convenience data structure for emitting temp vars in
an unwindable manner, without heavy AST allocation.
It also avoids a separate AST deep clone when propagating null values.
## How did you test this change?
All fixtures pass with byte-identical outputs.
Ran this against real codebases and pathological benchmark cases,
confirming byte-identical output as well.
#37357)
This follows #37315, which added the render lifetime controller to bound
the abort listener that `attachAbortSignal` attaches to a caller's
signal. `RequestInstance` constructed one for every request, so a render
that is given no signal allocated a controller, aborted it on
completion, and nothing ever observed either.
The controller is now created in `attachAbortSignal`, and the three
places that end the lifetime go through `endRenderLifetime`, which does
nothing when there is no controller. Callers that pass a signal are
unaffected. Callers that do not no longer allocate one, and `signal` is
optional in every browser, edge and static entry point, while
`renderToPipeableStream` and `resumeToPipeableStream` accept no signal
at all.
They also no longer reach `AbortController` at all, which matters more
than the allocation. Fizz had no runtime dependency on it before #37315,
and an unconditional one reaches environments that provide the API
through a polyfill. An incomplete polyfill can then fail a render that
never asked for abort support.
The new test asserts that no controller is constructed when no signal is
passed. It fails with the eager construction restored, since nothing
else in the suite would notice a regression to it.
@pullpullBot locked and limited conversation to collaborators Aug 24, 2026
@pull
pullBot merged commit 3d05080 into code:mainAug 24, 2026
17 checks passed
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@andrewimm@unstubbable
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

[pull] main from react:main - #643

Merged
pull[bot] merged 4 commits into
code:mainfrom
react:main
Aug 24, 2026
Merged

[pull] main from react:main#643
pull[bot] merged 4 commits into
code:mainfrom
react:main

Conversation

@pull

@pullpullBot commented Aug 24, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

andrewimmand others added 4 commits August 24, 2026 13:38
…7225)
## Summary
By replicating the `IndexSet` behavior with a simple inline array, this
is able to avoid any heap allocation / memory thrash for
`AbstractValue`. It also reduces the size of AbstractValue from 72 bytes
+ all of the heap allocations, to only 18 bytes.
## How did you test this change?
Ran all of the fixtures to confirm byte output is identical.
Effects on memory and compile time:
| Benchmark | Peak allocation | Allocation count | Wall time |
|------------------|-----------------------------|------------------|-----------|
| legacy/image.tsx | 58.21 -> 33.40 MiB (-42.6%) | -51.1% | -39.5% |
| next-client | 58.21 -> 33.40 (-42.6%) | -40.5% | -25.1% |
| devtools | 26.39 -> 16.29 (-38.3%) | -26.7% | -14.8% |
| fixtures | 17.35 → 9.41 (-45.8%) | -9.9% | -9.0% |
## Summary
In the mutation / aliasing inference, the state is used twice, and both
get cloned. Only one clone is necessary, the second can be safely moved.
This has minimal impact on peak memory usage, but it does reduce wall
time by *10%* on real Next.js benchmark apps.
## How did you test this change?
Ran against benchmark apps to confirm identical byte output.
Ran against the 1800+ Rust Compiler test fixtures.
tl;dr this reduces peak memory allocation by 5-15%, and reduces codegen
time by 30-70% depending on payload. On heavy components with deep ASTs
the impact is more exaggerated.
## Summary
Codegen of temp vars records the expressions they replaced, so that they
can be unwound. In the TS version this uses a `Map` and stores pointers
to AST nodes - relatively cheap. For borrow-checking reasons, the Rust
version clones the AST. This results in recurring deep clones, making
codegen accidentally quadratic and using significant amounts of memory.
This introduces a convenience data structure for emitting temp vars in
an unwindable manner, without heavy AST allocation.
It also avoids a separate AST deep clone when propagating null values.
## How did you test this change?
All fixtures pass with byte-identical outputs.
Ran this against real codebases and pathological benchmark cases,
confirming byte-identical output as well.
#37357)
This follows #37315, which added the render lifetime controller to bound
the abort listener that `attachAbortSignal` attaches to a caller's
signal. `RequestInstance` constructed one for every request, so a render
that is given no signal allocated a controller, aborted it on
completion, and nothing ever observed either.
The controller is now created in `attachAbortSignal`, and the three
places that end the lifetime go through `endRenderLifetime`, which does
nothing when there is no controller. Callers that pass a signal are
unaffected. Callers that do not no longer allocate one, and `signal` is
optional in every browser, edge and static entry point, while
`renderToPipeableStream` and `resumeToPipeableStream` accept no signal
at all.
They also no longer reach `AbortController` at all, which matters more
than the allocation. Fizz had no runtime dependency on it before #37315,
and an unconditional one reaches environments that provide the API
through a polyfill. An incomplete polyfill can then fail a render that
never asked for abort support.
The new test asserts that no controller is constructed when no signal is
passed. It fails with the eager construction restored, since nothing
else in the suite would notice a regression to it.
@pullpullBot locked and limited conversation to collaborators Aug 24, 2026
@pull
pullBot merged commit 3d05080 into code:mainAug 24, 2026
17 checks passed
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@andrewimm@unstubbable
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[pull] main from react:main - #643

Merged
pull[bot] merged 4 commits into
code:mainfrom
react:main
Aug 24, 2026
Merged

[pull] main from react:main#643
pull[bot] merged 4 commits into
code:mainfrom
react:main

Conversation

@pull

@pullpullBot commented Aug 24, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

andrewimmand others added 4 commits August 24, 2026 13:38
…7225)
## Summary
By replicating the `IndexSet` behavior with a simple inline array, this
is able to avoid any heap allocation / memory thrash for
`AbstractValue`. It also reduces the size of AbstractValue from 72 bytes
+ all of the heap allocations, to only 18 bytes.
## How did you test this change?
Ran all of the fixtures to confirm byte output is identical.
Effects on memory and compile time:
| Benchmark | Peak allocation | Allocation count | Wall time |
|------------------|-----------------------------|------------------|-----------|
| legacy/image.tsx | 58.21 -> 33.40 MiB (-42.6%) | -51.1% | -39.5% |
| next-client | 58.21 -> 33.40 (-42.6%) | -40.5% | -25.1% |
| devtools | 26.39 -> 16.29 (-38.3%) | -26.7% | -14.8% |
| fixtures | 17.35 → 9.41 (-45.8%) | -9.9% | -9.0% |
## Summary
In the mutation / aliasing inference, the state is used twice, and both
get cloned. Only one clone is necessary, the second can be safely moved.
This has minimal impact on peak memory usage, but it does reduce wall
time by *10%* on real Next.js benchmark apps.
## How did you test this change?
Ran against benchmark apps to confirm identical byte output.
Ran against the 1800+ Rust Compiler test fixtures.
tl;dr this reduces peak memory allocation by 5-15%, and reduces codegen
time by 30-70% depending on payload. On heavy components with deep ASTs
the impact is more exaggerated.
## Summary
Codegen of temp vars records the expressions they replaced, so that they
can be unwound. In the TS version this uses a `Map` and stores pointers
to AST nodes - relatively cheap. For borrow-checking reasons, the Rust
version clones the AST. This results in recurring deep clones, making
codegen accidentally quadratic and using significant amounts of memory.
This introduces a convenience data structure for emitting temp vars in
an unwindable manner, without heavy AST allocation.
It also avoids a separate AST deep clone when propagating null values.
## How did you test this change?
All fixtures pass with byte-identical outputs.
Ran this against real codebases and pathological benchmark cases,
confirming byte-identical output as well.
#37357)
This follows #37315, which added the render lifetime controller to bound
the abort listener that `attachAbortSignal` attaches to a caller's
signal. `RequestInstance` constructed one for every request, so a render
that is given no signal allocated a controller, aborted it on
completion, and nothing ever observed either.
The controller is now created in `attachAbortSignal`, and the three
places that end the lifetime go through `endRenderLifetime`, which does
nothing when there is no controller. Callers that pass a signal are
unaffected. Callers that do not no longer allocate one, and `signal` is
optional in every browser, edge and static entry point, while
`renderToPipeableStream` and `resumeToPipeableStream` accept no signal
at all.
They also no longer reach `AbortController` at all, which matters more
than the allocation. Fizz had no runtime dependency on it before #37315,
and an unconditional one reaches environments that provide the API
through a polyfill. An incomplete polyfill can then fail a render that
never asked for abort support.
The new test asserts that no controller is constructed when no signal is
passed. It fails with the eager construction restored, since nothing
else in the suite would notice a regression to it.
@pullpullBot locked and limited conversation to collaborators Aug 24, 2026
@pull
pullBot merged commit 3d05080 into code:mainAug 24, 2026
17 checks passed
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@andrewimm@unstubbable
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[pull] main from react:main - #643

Merged
pull[bot] merged 4 commits into
code:mainfrom
react:main
Aug 24, 2026
Merged

[pull] main from react:main#643
pull[bot] merged 4 commits into
code:mainfrom
react:main

Conversation

@pull

@pullpullBot commented Aug 24, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

andrewimmand others added 4 commits August 24, 2026 13:38
…7225)
## Summary
By replicating the `IndexSet` behavior with a simple inline array, this
is able to avoid any heap allocation / memory thrash for
`AbstractValue`. It also reduces the size of AbstractValue from 72 bytes
+ all of the heap allocations, to only 18 bytes.
## How did you test this change?
Ran all of the fixtures to confirm byte output is identical.
Effects on memory and compile time:
| Benchmark | Peak allocation | Allocation count | Wall time |
|------------------|-----------------------------|------------------|-----------|
| legacy/image.tsx | 58.21 -> 33.40 MiB (-42.6%) | -51.1% | -39.5% |
| next-client | 58.21 -> 33.40 (-42.6%) | -40.5% | -25.1% |
| devtools | 26.39 -> 16.29 (-38.3%) | -26.7% | -14.8% |
| fixtures | 17.35 → 9.41 (-45.8%) | -9.9% | -9.0% |
## Summary
In the mutation / aliasing inference, the state is used twice, and both
get cloned. Only one clone is necessary, the second can be safely moved.
This has minimal impact on peak memory usage, but it does reduce wall
time by *10%* on real Next.js benchmark apps.
## How did you test this change?
Ran against benchmark apps to confirm identical byte output.
Ran against the 1800+ Rust Compiler test fixtures.
tl;dr this reduces peak memory allocation by 5-15%, and reduces codegen
time by 30-70% depending on payload. On heavy components with deep ASTs
the impact is more exaggerated.
## Summary
Codegen of temp vars records the expressions they replaced, so that they
can be unwound. In the TS version this uses a `Map` and stores pointers
to AST nodes - relatively cheap. For borrow-checking reasons, the Rust
version clones the AST. This results in recurring deep clones, making
codegen accidentally quadratic and using significant amounts of memory.
This introduces a convenience data structure for emitting temp vars in
an unwindable manner, without heavy AST allocation.
It also avoids a separate AST deep clone when propagating null values.
## How did you test this change?
All fixtures pass with byte-identical outputs.
Ran this against real codebases and pathological benchmark cases,
confirming byte-identical output as well.
#37357)
This follows #37315, which added the render lifetime controller to bound
the abort listener that `attachAbortSignal` attaches to a caller's
signal. `RequestInstance` constructed one for every request, so a render
that is given no signal allocated a controller, aborted it on
completion, and nothing ever observed either.
The controller is now created in `attachAbortSignal`, and the three
places that end the lifetime go through `endRenderLifetime`, which does
nothing when there is no controller. Callers that pass a signal are
unaffected. Callers that do not no longer allocate one, and `signal` is
optional in every browser, edge and static entry point, while
`renderToPipeableStream` and `resumeToPipeableStream` accept no signal
at all.
They also no longer reach `AbortController` at all, which matters more
than the allocation. Fizz had no runtime dependency on it before #37315,
and an unconditional one reaches environments that provide the API
through a polyfill. An incomplete polyfill can then fail a render that
never asked for abort support.
The new test asserts that no controller is constructed when no signal is
passed. It fails with the eager construction restored, since nothing
else in the suite would notice a regression to it.
@pullpullBot locked and limited conversation to collaborators Aug 24, 2026
@pull
pullBot merged commit 3d05080 into code:mainAug 24, 2026
17 checks passed
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@andrewimm@unstubbable
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

[pull] main from react:main - #643

Merged
pull[bot] merged 4 commits into
code:mainfrom
react:main
Aug 24, 2026
Merged

[pull] main from react:main#643
pull[bot] merged 4 commits into
code:mainfrom
react:main

Conversation

@pull

@pullpullBot commented Aug 24, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

andrewimmand others added 4 commits August 24, 2026 13:38
…7225)
## Summary
By replicating the `IndexSet` behavior with a simple inline array, this
is able to avoid any heap allocation / memory thrash for
`AbstractValue`. It also reduces the size of AbstractValue from 72 bytes
+ all of the heap allocations, to only 18 bytes.
## How did you test this change?
Ran all of the fixtures to confirm byte output is identical.
Effects on memory and compile time:
| Benchmark | Peak allocation | Allocation count | Wall time |
|------------------|-----------------------------|------------------|-----------|
| legacy/image.tsx | 58.21 -> 33.40 MiB (-42.6%) | -51.1% | -39.5% |
| next-client | 58.21 -> 33.40 (-42.6%) | -40.5% | -25.1% |
| devtools | 26.39 -> 16.29 (-38.3%) | -26.7% | -14.8% |
| fixtures | 17.35 → 9.41 (-45.8%) | -9.9% | -9.0% |
## Summary
In the mutation / aliasing inference, the state is used twice, and both
get cloned. Only one clone is necessary, the second can be safely moved.
This has minimal impact on peak memory usage, but it does reduce wall
time by *10%* on real Next.js benchmark apps.
## How did you test this change?
Ran against benchmark apps to confirm identical byte output.
Ran against the 1800+ Rust Compiler test fixtures.
tl;dr this reduces peak memory allocation by 5-15%, and reduces codegen
time by 30-70% depending on payload. On heavy components with deep ASTs
the impact is more exaggerated.
## Summary
Codegen of temp vars records the expressions they replaced, so that they
can be unwound. In the TS version this uses a `Map` and stores pointers
to AST nodes - relatively cheap. For borrow-checking reasons, the Rust
version clones the AST. This results in recurring deep clones, making
codegen accidentally quadratic and using significant amounts of memory.
This introduces a convenience data structure for emitting temp vars in
an unwindable manner, without heavy AST allocation.
It also avoids a separate AST deep clone when propagating null values.
## How did you test this change?
All fixtures pass with byte-identical outputs.
Ran this against real codebases and pathological benchmark cases,
confirming byte-identical output as well.
#37357)
This follows #37315, which added the render lifetime controller to bound
the abort listener that `attachAbortSignal` attaches to a caller's
signal. `RequestInstance` constructed one for every request, so a render
that is given no signal allocated a controller, aborted it on
completion, and nothing ever observed either.
The controller is now created in `attachAbortSignal`, and the three
places that end the lifetime go through `endRenderLifetime`, which does
nothing when there is no controller. Callers that pass a signal are
unaffected. Callers that do not no longer allocate one, and `signal` is
optional in every browser, edge and static entry point, while
`renderToPipeableStream` and `resumeToPipeableStream` accept no signal
at all.
They also no longer reach `AbortController` at all, which matters more
than the allocation. Fizz had no runtime dependency on it before #37315,
and an unconditional one reaches environments that provide the API
through a polyfill. An incomplete polyfill can then fail a render that
never asked for abort support.
The new test asserts that no controller is constructed when no signal is
passed. It fails with the eager construction restored, since nothing
else in the suite would notice a regression to it.
@pullpullBot locked and limited conversation to collaborators Aug 24, 2026
@pull
pullBot merged commit 3d05080 into code:mainAug 24, 2026
17 checks passed
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@andrewimm@unstubbable
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[pull] main from react:main - #643

Merged
pull[bot] merged 4 commits into
code:mainfrom
react:main
Aug 24, 2026
Merged

[pull] main from react:main#643
pull[bot] merged 4 commits into
code:mainfrom
react:main

Conversation

@pull

@pullpullBot commented Aug 24, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

andrewimmand others added 4 commits August 24, 2026 13:38
…7225)
## Summary
By replicating the `IndexSet` behavior with a simple inline array, this
is able to avoid any heap allocation / memory thrash for
`AbstractValue`. It also reduces the size of AbstractValue from 72 bytes
+ all of the heap allocations, to only 18 bytes.
## How did you test this change?
Ran all of the fixtures to confirm byte output is identical.
Effects on memory and compile time:
| Benchmark | Peak allocation | Allocation count | Wall time |
|------------------|-----------------------------|------------------|-----------|
| legacy/image.tsx | 58.21 -> 33.40 MiB (-42.6%) | -51.1% | -39.5% |
| next-client | 58.21 -> 33.40 (-42.6%) | -40.5% | -25.1% |
| devtools | 26.39 -> 16.29 (-38.3%) | -26.7% | -14.8% |
| fixtures | 17.35 → 9.41 (-45.8%) | -9.9% | -9.0% |
## Summary
In the mutation / aliasing inference, the state is used twice, and both
get cloned. Only one clone is necessary, the second can be safely moved.
This has minimal impact on peak memory usage, but it does reduce wall
time by *10%* on real Next.js benchmark apps.
## How did you test this change?
Ran against benchmark apps to confirm identical byte output.
Ran against the 1800+ Rust Compiler test fixtures.
tl;dr this reduces peak memory allocation by 5-15%, and reduces codegen
time by 30-70% depending on payload. On heavy components with deep ASTs
the impact is more exaggerated.
## Summary
Codegen of temp vars records the expressions they replaced, so that they
can be unwound. In the TS version this uses a `Map` and stores pointers
to AST nodes - relatively cheap. For borrow-checking reasons, the Rust
version clones the AST. This results in recurring deep clones, making
codegen accidentally quadratic and using significant amounts of memory.
This introduces a convenience data structure for emitting temp vars in
an unwindable manner, without heavy AST allocation.
It also avoids a separate AST deep clone when propagating null values.
## How did you test this change?
All fixtures pass with byte-identical outputs.
Ran this against real codebases and pathological benchmark cases,
confirming byte-identical output as well.
#37357)
This follows #37315, which added the render lifetime controller to bound
the abort listener that `attachAbortSignal` attaches to a caller's
signal. `RequestInstance` constructed one for every request, so a render
that is given no signal allocated a controller, aborted it on
completion, and nothing ever observed either.
The controller is now created in `attachAbortSignal`, and the three
places that end the lifetime go through `endRenderLifetime`, which does
nothing when there is no controller. Callers that pass a signal are
unaffected. Callers that do not no longer allocate one, and `signal` is
optional in every browser, edge and static entry point, while
`renderToPipeableStream` and `resumeToPipeableStream` accept no signal
at all.
They also no longer reach `AbortController` at all, which matters more
than the allocation. Fizz had no runtime dependency on it before #37315,
and an unconditional one reaches environments that provide the API
through a polyfill. An incomplete polyfill can then fail a render that
never asked for abort support.
The new test asserts that no controller is constructed when no signal is
passed. It fails with the eager construction restored, since nothing
else in the suite would notice a regression to it.
@pullpullBot locked and limited conversation to collaborators Aug 24, 2026
@pull
pullBot merged commit 3d05080 into code:mainAug 24, 2026
17 checks passed
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@andrewimm@unstubbable
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[pull] main from react:main - #643

Merged
pull[bot] merged 4 commits into
code:mainfrom
react:main
Aug 24, 2026
Merged

[pull] main from react:main#643
pull[bot] merged 4 commits into
code:mainfrom
react:main

Conversation

@pull

@pullpullBot commented Aug 24, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

andrewimmand others added 4 commits August 24, 2026 13:38
…7225)
## Summary
By replicating the `IndexSet` behavior with a simple inline array, this
is able to avoid any heap allocation / memory thrash for
`AbstractValue`. It also reduces the size of AbstractValue from 72 bytes
+ all of the heap allocations, to only 18 bytes.
## How did you test this change?
Ran all of the fixtures to confirm byte output is identical.
Effects on memory and compile time:
| Benchmark | Peak allocation | Allocation count | Wall time |
|------------------|-----------------------------|------------------|-----------|
| legacy/image.tsx | 58.21 -> 33.40 MiB (-42.6%) | -51.1% | -39.5% |
| next-client | 58.21 -> 33.40 (-42.6%) | -40.5% | -25.1% |
| devtools | 26.39 -> 16.29 (-38.3%) | -26.7% | -14.8% |
| fixtures | 17.35 → 9.41 (-45.8%) | -9.9% | -9.0% |
## Summary
In the mutation / aliasing inference, the state is used twice, and both
get cloned. Only one clone is necessary, the second can be safely moved.
This has minimal impact on peak memory usage, but it does reduce wall
time by *10%* on real Next.js benchmark apps.
## How did you test this change?
Ran against benchmark apps to confirm identical byte output.
Ran against the 1800+ Rust Compiler test fixtures.
tl;dr this reduces peak memory allocation by 5-15%, and reduces codegen
time by 30-70% depending on payload. On heavy components with deep ASTs
the impact is more exaggerated.
## Summary
Codegen of temp vars records the expressions they replaced, so that they
can be unwound. In the TS version this uses a `Map` and stores pointers
to AST nodes - relatively cheap. For borrow-checking reasons, the Rust
version clones the AST. This results in recurring deep clones, making
codegen accidentally quadratic and using significant amounts of memory.
This introduces a convenience data structure for emitting temp vars in
an unwindable manner, without heavy AST allocation.
It also avoids a separate AST deep clone when propagating null values.
## How did you test this change?
All fixtures pass with byte-identical outputs.
Ran this against real codebases and pathological benchmark cases,
confirming byte-identical output as well.
#37357)
This follows #37315, which added the render lifetime controller to bound
the abort listener that `attachAbortSignal` attaches to a caller's
signal. `RequestInstance` constructed one for every request, so a render
that is given no signal allocated a controller, aborted it on
completion, and nothing ever observed either.
The controller is now created in `attachAbortSignal`, and the three
places that end the lifetime go through `endRenderLifetime`, which does
nothing when there is no controller. Callers that pass a signal are
unaffected. Callers that do not no longer allocate one, and `signal` is
optional in every browser, edge and static entry point, while
`renderToPipeableStream` and `resumeToPipeableStream` accept no signal
at all.
They also no longer reach `AbortController` at all, which matters more
than the allocation. Fizz had no runtime dependency on it before #37315,
and an unconditional one reaches environments that provide the API
through a polyfill. An incomplete polyfill can then fail a render that
never asked for abort support.
The new test asserts that no controller is constructed when no signal is
passed. It fails with the eager construction restored, since nothing
else in the suite would notice a regression to it.
@pullpullBot locked and limited conversation to collaborators Aug 24, 2026
@pull
pullBot merged commit 3d05080 into code:mainAug 24, 2026
17 checks passed
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@andrewimm@unstubbable
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

[pull] main from react:main - #643

Merged
pull[bot] merged 4 commits into
code:mainfrom
react:main
Aug 24, 2026
Merged

[pull] main from react:main#643
pull[bot] merged 4 commits into
code:mainfrom
react:main

Conversation

@pull

@pullpullBot commented Aug 24, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

andrewimmand others added 4 commits August 24, 2026 13:38
…7225)
## Summary
By replicating the `IndexSet` behavior with a simple inline array, this
is able to avoid any heap allocation / memory thrash for
`AbstractValue`. It also reduces the size of AbstractValue from 72 bytes
+ all of the heap allocations, to only 18 bytes.
## How did you test this change?
Ran all of the fixtures to confirm byte output is identical.
Effects on memory and compile time:
| Benchmark | Peak allocation | Allocation count | Wall time |
|------------------|-----------------------------|------------------|-----------|
| legacy/image.tsx | 58.21 -> 33.40 MiB (-42.6%) | -51.1% | -39.5% |
| next-client | 58.21 -> 33.40 (-42.6%) | -40.5% | -25.1% |
| devtools | 26.39 -> 16.29 (-38.3%) | -26.7% | -14.8% |
| fixtures | 17.35 → 9.41 (-45.8%) | -9.9% | -9.0% |
## Summary
In the mutation / aliasing inference, the state is used twice, and both
get cloned. Only one clone is necessary, the second can be safely moved.
This has minimal impact on peak memory usage, but it does reduce wall
time by *10%* on real Next.js benchmark apps.
## How did you test this change?
Ran against benchmark apps to confirm identical byte output.
Ran against the 1800+ Rust Compiler test fixtures.
tl;dr this reduces peak memory allocation by 5-15%, and reduces codegen
time by 30-70% depending on payload. On heavy components with deep ASTs
the impact is more exaggerated.
## Summary
Codegen of temp vars records the expressions they replaced, so that they
can be unwound. In the TS version this uses a `Map` and stores pointers
to AST nodes - relatively cheap. For borrow-checking reasons, the Rust
version clones the AST. This results in recurring deep clones, making
codegen accidentally quadratic and using significant amounts of memory.
This introduces a convenience data structure for emitting temp vars in
an unwindable manner, without heavy AST allocation.
It also avoids a separate AST deep clone when propagating null values.
## How did you test this change?
All fixtures pass with byte-identical outputs.
Ran this against real codebases and pathological benchmark cases,
confirming byte-identical output as well.
#37357)
This follows #37315, which added the render lifetime controller to bound
the abort listener that `attachAbortSignal` attaches to a caller's
signal. `RequestInstance` constructed one for every request, so a render
that is given no signal allocated a controller, aborted it on
completion, and nothing ever observed either.
The controller is now created in `attachAbortSignal`, and the three
places that end the lifetime go through `endRenderLifetime`, which does
nothing when there is no controller. Callers that pass a signal are
unaffected. Callers that do not no longer allocate one, and `signal` is
optional in every browser, edge and static entry point, while
`renderToPipeableStream` and `resumeToPipeableStream` accept no signal
at all.
They also no longer reach `AbortController` at all, which matters more
than the allocation. Fizz had no runtime dependency on it before #37315,
and an unconditional one reaches environments that provide the API
through a polyfill. An incomplete polyfill can then fail a render that
never asked for abort support.
The new test asserts that no controller is constructed when no signal is
passed. It fails with the eager construction restored, since nothing
else in the suite would notice a regression to it.
@pullpullBot locked and limited conversation to collaborators Aug 24, 2026
@pull
pullBot merged commit 3d05080 into code:mainAug 24, 2026
17 checks passed
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@andrewimm@unstubbable