Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fizz] Add FormatContext and Refactor Work #21103

Merged
merged 5 commits into from
Mar 26, 2021

Conversation

sebmarkbage
Copy link
Collaborator

@sebmarkbage sebmarkbage commented Mar 26, 2021

I'll need the equivalent of HostContext for keeping track of which namespace we're rendering in and some other things. There are also some contextual things already and we need to add some more for "New" Context and Legacy Context.

There are a couple of ways we could deal with Context. We could pass it on the stack to every function (that's what I was doing before). We could store it on something "thread local" in module scope like how "New" Context works.

In Fizz we don't need to yield in the middle of rendering so we can use the stack and we only need one "thread local". However, we might need to be able to switch between various contexts and pick up a context. That's what SuspendedWork is. A heap allocation for where to pick back up.

There's also a downside to passing everything recursively in the stack. 1) We use extra stack memory which risks running out. 2) We have to write to the stack for each call. Typically the same thing over and over. 3) We also have to save/restore it every time we context switch.

So instead, I opted to just keep the "SuspendedWork" as the place where these contextual things are stored and we can temporarily override them along the stack where we need to. It's just one extra hidden class check I think to get it from there rather than the stack so should be strictly faster.

The "New" Context implementation does need restore/reset but that's a separate later issue and dependent on implementation details.

I also took this opportunity to synchronously render the content of Suspense boundaries since we can cheaply take advantage of already being in the right context.

Note: We could actually implement Fiber like this too. We'd just create SuspendedWork if we run out of time same as what we do when we suspend. In other words, it would use a recursive stack up until a point and then create a continuation there.

Stacks are nice and all but there's a cost to maintaining each frame
both in terms of stack size usage and writing to it.
We don't have to spawn work and snapshot the context. Instead we can try
to render the boundary immediately in case it works.
Instead of eagerly create the fallback work and then immediately abort it.
We can just avoid creating it if we finish synchronously.
@facebook-github-bot facebook-github-bot added CLA Signed React Core Team Opened by a member of the React Core Team labels Mar 26, 2021
@sizebot
Copy link

sizebot commented Mar 26, 2021

Comparing: a7c5726...6dcd49a

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.min.js = 122.93 kB 122.93 kB = 39.53 kB 39.53 kB
oss-experimental/react-dom/cjs/react-dom.production.min.js = 129.45 kB 129.45 kB = 41.61 kB 41.61 kB
facebook-www/ReactDOM-prod.classic.js = 407.25 kB 407.25 kB = 75.67 kB 75.67 kB
facebook-www/ReactDOM-prod.modern.js = 395.51 kB 395.51 kB = 73.72 kB 73.71 kB
facebook-www/ReactDOMForked-prod.classic.js = 407.25 kB 407.25 kB = 75.67 kB 75.67 kB
oss-experimental/react-dom/cjs/react-dom-unstable-fizz.browser.production.min.js +7.33% 11.41 kB 12.25 kB +6.65% 4.14 kB 4.41 kB
oss-experimental/react-dom/umd/react-dom-unstable-fizz.browser.production.min.js +7.23% 11.61 kB 12.44 kB +6.52% 4.23 kB 4.51 kB
oss-experimental/react-dom/cjs/react-dom-unstable-fizz.node.production.min.js +7.20% 11.60 kB 12.44 kB +6.52% 4.16 kB 4.43 kB
oss-experimental/react-server/cjs/react-server.production.min.js +6.63% 8.88 kB 9.46 kB +4.53% 3.15 kB 3.30 kB
oss-stable/react-server/cjs/react-server.production.min.js +6.63% 8.88 kB 9.46 kB +4.53% 3.15 kB 3.30 kB
oss-experimental/react-dom/cjs/react-dom-unstable-fizz.browser.development.js +5.80% 50.43 kB 53.36 kB +5.93% 12.95 kB 13.72 kB
oss-experimental/react-dom/cjs/react-dom-unstable-fizz.node.development.js +5.80% 50.38 kB 53.30 kB +5.97% 12.86 kB 13.62 kB
oss-experimental/react-dom/umd/react-dom-unstable-fizz.browser.development.js +5.74% 53.05 kB 56.09 kB +5.84% 13.12 kB 13.89 kB
oss-experimental/react-server/cjs/react-server.development.js +5.13% 34.72 kB 36.50 kB +4.81% 9.10 kB 9.54 kB
oss-stable/react-server/cjs/react-server.development.js +5.13% 34.72 kB 36.50 kB +4.81% 9.10 kB 9.54 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
oss-experimental/react-dom/cjs/react-dom-unstable-fizz.browser.production.min.js +7.33% 11.41 kB 12.25 kB +6.65% 4.14 kB 4.41 kB
oss-experimental/react-dom/umd/react-dom-unstable-fizz.browser.production.min.js +7.23% 11.61 kB 12.44 kB +6.52% 4.23 kB 4.51 kB
oss-experimental/react-dom/cjs/react-dom-unstable-fizz.node.production.min.js +7.20% 11.60 kB 12.44 kB +6.52% 4.16 kB 4.43 kB
oss-experimental/react-server/cjs/react-server.production.min.js +6.63% 8.88 kB 9.46 kB +4.53% 3.15 kB 3.30 kB
oss-stable/react-server/cjs/react-server.production.min.js +6.63% 8.88 kB 9.46 kB +4.53% 3.15 kB 3.30 kB
oss-experimental/react-dom/cjs/react-dom-unstable-fizz.browser.development.js +5.80% 50.43 kB 53.36 kB +5.93% 12.95 kB 13.72 kB
oss-experimental/react-dom/cjs/react-dom-unstable-fizz.node.development.js +5.80% 50.38 kB 53.30 kB +5.97% 12.86 kB 13.62 kB
oss-experimental/react-dom/umd/react-dom-unstable-fizz.browser.development.js +5.74% 53.05 kB 56.09 kB +5.84% 13.12 kB 13.89 kB
oss-experimental/react-server/cjs/react-server.development.js +5.13% 34.72 kB 36.50 kB +4.81% 9.10 kB 9.54 kB
oss-stable/react-server/cjs/react-server.development.js +5.13% 34.72 kB 36.50 kB +4.81% 9.10 kB 9.54 kB
oss-experimental/react-noop-renderer/cjs/react-noop-renderer-server.production.min.js +1.99% 2.56 kB 2.61 kB +2.37% 1.01 kB 1.04 kB
oss-stable/react-noop-renderer/cjs/react-noop-renderer-server.production.min.js +1.99% 2.56 kB 2.61 kB +2.37% 1.01 kB 1.04 kB
oss-experimental/react-noop-renderer/cjs/react-noop-renderer-server.development.js +1.25% 5.34 kB 5.41 kB +1.37% 1.53 kB 1.55 kB
oss-stable/react-noop-renderer/cjs/react-noop-renderer-server.development.js +1.25% 5.34 kB 5.41 kB +1.37% 1.53 kB 1.55 kB

Generated by 🚫 dangerJS against 6dcd49a

@acdlite
Copy link
Collaborator

acdlite commented Mar 26, 2021

In other words, it would use a recursive stack up until a point and then create a continuation there.

Yeah I like this. I had a similar thought when working on the lazy context implementation. Right now, we have to eagerly propagate context to suspended trees (children of the Fiber that throws) because during the retry the stack of which providers changed is no longer available. To make that lazy, we'd need to store it as continuation instead. (Which is also how Cache retries work, so we could unify the implementations further).

Kinda funny because that's basically what a "fiber" already is :D The lazy context implementation works by backtracking the Fiber return path to check which contexts changed. Can't do that during the retry because of the alternate pooling mechanism, but maybe post-alternate refactor we can literally just use the previous Fiber as the continuation.

@sebmarkbage sebmarkbage merged commit 38a1aed into facebook:master Mar 26, 2021
facebook-github-bot pushed a commit to facebook/react-native that referenced this pull request Apr 6, 2021
Summary:
This sync includes the following changes:
- **[c9aab1c9d](facebook/react@c9aab1c9d )**: react-refresh@0.10.0 //<Dan Abramov>//
- **[516b76b9a](facebook/react@516b76b9a )**: [Fast Refresh] Support callthrough HOCs ([#21104](facebook/react#21104)) //<Dan Abramov>//
- **[0853aab74](facebook/react@0853aab74 )**: Log all errors to console.error by default ([#21130](facebook/react#21130)) //<Sebastian Markbåge>//
- **[d1294c9d4](facebook/react@d1294c9d4 )**: Add global onError handler ([#21129](facebook/react#21129)) //<Sebastian Markbåge>//
- **[64983aab5](facebook/react@64983aab5 )**: Remove redundant setUpdatePriority call ([#21127](facebook/react#21127)) //<Andrew Clark>//
- **[634cc52e6](facebook/react@634cc52e6 )**: Delete dead variable: currentEventWipLanes ([#21123](facebook/react#21123)) //<Andrew Clark>//
- **[1102224bb](facebook/react@1102224bb )**: Fix: flushSync changes priority inside effect ([#21122](facebook/react#21122)) //<Andrew Clark>//
- **[dbe98a5aa](facebook/react@dbe98a5aa )**: Move sync task queue to its own module ([#21109](facebook/react#21109)) //<Andrew Clark>//
- **[3ba5c8737](facebook/react@3ba5c8737 )**: Remove Scheduler indirection ([#21107](facebook/react#21107)) //<Andrew Clark>//
- **[46b68eaf6](facebook/react@46b68eaf6 )**: Delete LanePriority type ([#21090](facebook/react#21090)) //<Andrew Clark>//
- **[dcd13045e](facebook/react@dcd13045e )**: Use Lane to track root callback priority ([#21089](facebook/react#21089)) //<Andrew Clark>//
- **[5f21a9fca](facebook/react@5f21a9fca )**: Clean up host pointers in level 2 of clean-up flag ([#21112](facebook/react#21112)) //<Andrew Clark>//
- **[32d6f39ed](facebook/react@32d6f39ed )**: [Fizz] Support special HTML/SVG/MathML tags to suspend ([#21113](facebook/react#21113)) //<Sebastian Markbåge>//
- **[a77dd13ed](facebook/react@a77dd13ed )**: Delete enableDiscreteEventFlushingChange ([#21110](facebook/react#21110)) //<Andrew Clark>//
- **[048ee4c0c](facebook/react@048ee4c0c )**: Use `act` in fuzz tester to flush expired work ([#21108](facebook/react#21108)) //<Andrew Clark>//
- **[556644e23](facebook/react@556644e23 )**: Fix plurals ([#21106](facebook/react#21106)) //<Sebastian Markbåge>//
- **[8b741437b](facebook/react@8b741437b )**: Rename SuspendedWork to Task ([#21105](facebook/react#21105)) //<Sebastian Markbåge>//
- **[38a1aedb4](facebook/react@38a1aedb4 )**: [Fizz] Add FormatContext and Refactor Work ([#21103](facebook/react#21103)) //<Sebastian Markbåge>//
- **[1b7e471b9](facebook/react@1b7e471b9 )**: React Native New Architecture: Support passing nativeViewTag to getInspectorDataForViewAtPoint callback, for React DevTools compat ([#21080](facebook/react#21080)) //<Joshua Gross>//
- **[4a99c5c3a](facebook/react@4a99c5c3a )**: Use highest priority lane to detect interruptions ([#21088](facebook/react#21088)) //<Andrew Clark>//
- **[77be52729](facebook/react@77be52729 )**: Remove LanePriority from computeExpirationTime ([#21087](facebook/react#21087)) //<Andrew Clark>//
- **[3221e8fba](facebook/react@3221e8fba )**: Remove LanePriority from getBumpedLaneForHydration ([#21086](facebook/react#21086)) //<Andrew Clark>//
- **[05ec0d764](facebook/react@05ec0d764 )**: Entangled expired lanes with SyncLane ([#21083](facebook/react#21083)) //<Andrew Clark>//
- **[03ede83d2](facebook/react@03ede83d2 )**: Use EventPriority to track update priority ([#21082](facebook/react#21082)) //<Andrew Clark>//
- **[a63f0953b](facebook/react@a63f0953b )**: Delete SyncBatchedLane ([#21061](facebook/react#21061)) //<Ricky>//
- **[fa868d6be](facebook/react@fa868d6be )**: Make opaque EventPriority type a Lane internally ([#21065](facebook/react#21065)) //<Andrew Clark>//
- **[eb58c3909](facebook/react@eb58c3909 )**: react-hooks/exhaustive-deps: Handle optional chained methods as dependency ([#20204](facebook/react#20204)) ([#20247](facebook/react#20247)) //<Ari Perkkiö>//
- **[7b84dbd16](facebook/react@7b84dbd16 )**: Fail build on deep requires in npm packages ([#21063](facebook/react#21063)) //<Dan Abramov>//
- **[2c9d8efc8](facebook/react@2c9d8efc8 )**: Add react-reconciler/constants entry point ([#21062](facebook/react#21062)) //<Dan Abramov>//
- **[d0eaf7829](facebook/react@d0eaf7829 )**: Move priorities to separate import to break cycle ([#21060](facebook/react#21060)) //<Andrew Clark>//
- **[435cff986](facebook/react@435cff986 )**: [Fizz] Expose callbacks in options for when various stages of the content is done ([#21056](facebook/react#21056)) //<Sebastian Markbåge>//
- **[25bfa287f](facebook/react@25bfa287f )**: [Experiment] Add feature flag for more aggressive memory clean-up of deleted fiber trees ([#21039](facebook/react#21039)) //<Benoit Girard>//
- **[8fe7810e7](facebook/react@8fe7810e7 )**: Remove already completed comment ([#21054](facebook/react#21054)) //<Sebastian Markbåge>//
- **[6c3202b1e](facebook/react@6c3202b1e )**: [Fizz] Use identifierPrefix to avoid conflicts within the same response ([#21037](facebook/react#21037)) //<Sebastian Markbåge>//
- **[dcdf8de7e](facebook/react@dcdf8de7e )**: Remove discrete lanes and priorities ([#21040](facebook/react#21040)) //<Andrew Clark>//
- **[ca99ae97b](facebook/react@ca99ae97b )**: Replace some flushExpired callsites ([#20975](facebook/react#20975)) //<Ricky>//
- **[1fafac002](facebook/react@1fafac002 )**: Use SyncLane for discrete event hydration ([#21038](facebook/react#21038)) //<Andrew Clark>//

Changelog:
[General][Changed] - React Native sync for revisions 6d3ecb7...c9aab1c

jest_e2e[run_all_tests]

Reviewed By: JoshuaGross

Differential Revision: D27436763

fbshipit-source-id: da79a41e26bffdcdacd293178062edf098e9b58a
acdlite pushed a commit to acdlite/react that referenced this pull request Apr 11, 2021
* Add format context

* Let the Work node hold all working state for the recursive loop

Stacks are nice and all but there's a cost to maintaining each frame
both in terms of stack size usage and writing to it.

* Move current format context into work

* Synchronously render children of a Suspense boundary

We don't have to spawn work and snapshot the context. Instead we can try
to render the boundary immediately in case it works.

* Lazily create the fallback work

Instead of eagerly create the fallback work and then immediately abort it.
We can just avoid creating it if we finish synchronously.
acdlite pushed a commit to acdlite/react that referenced this pull request Apr 13, 2021
* Add format context

* Let the Work node hold all working state for the recursive loop

Stacks are nice and all but there's a cost to maintaining each frame
both in terms of stack size usage and writing to it.

* Move current format context into work

* Synchronously render children of a Suspense boundary

We don't have to spawn work and snapshot the context. Instead we can try
to render the boundary immediately in case it works.

* Lazily create the fallback work

Instead of eagerly create the fallback work and then immediately abort it.
We can just avoid creating it if we finish synchronously.
acdlite pushed a commit to acdlite/react that referenced this pull request Apr 16, 2021
* Add format context

* Let the Work node hold all working state for the recursive loop

Stacks are nice and all but there's a cost to maintaining each frame
both in terms of stack size usage and writing to it.

* Move current format context into work

* Synchronously render children of a Suspense boundary

We don't have to spawn work and snapshot the context. Instead we can try
to render the boundary immediately in case it works.

* Lazily create the fallback work

Instead of eagerly create the fallback work and then immediately abort it.
We can just avoid creating it if we finish synchronously.
acdlite pushed a commit to acdlite/react that referenced this pull request Apr 16, 2021
* Add format context

* Let the Work node hold all working state for the recursive loop

Stacks are nice and all but there's a cost to maintaining each frame
both in terms of stack size usage and writing to it.

* Move current format context into work

* Synchronously render children of a Suspense boundary

We don't have to spawn work and snapshot the context. Instead we can try
to render the boundary immediately in case it works.

* Lazily create the fallback work

Instead of eagerly create the fallback work and then immediately abort it.
We can just avoid creating it if we finish synchronously.
acdlite pushed a commit to acdlite/react that referenced this pull request Apr 19, 2021
* Add format context

* Let the Work node hold all working state for the recursive loop

Stacks are nice and all but there's a cost to maintaining each frame
both in terms of stack size usage and writing to it.

* Move current format context into work

* Synchronously render children of a Suspense boundary

We don't have to spawn work and snapshot the context. Instead we can try
to render the boundary immediately in case it works.

* Lazily create the fallback work

Instead of eagerly create the fallback work and then immediately abort it.
We can just avoid creating it if we finish synchronously.
koto pushed a commit to koto/react that referenced this pull request Jun 15, 2021
* Add format context

* Let the Work node hold all working state for the recursive loop

Stacks are nice and all but there's a cost to maintaining each frame
both in terms of stack size usage and writing to it.

* Move current format context into work

* Synchronously render children of a Suspense boundary

We don't have to spawn work and snapshot the context. Instead we can try
to render the boundary immediately in case it works.

* Lazily create the fallback work

Instead of eagerly create the fallback work and then immediately abort it.
We can just avoid creating it if we finish synchronously.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed React Core Team Opened by a member of the React Core Team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants