@samitouri / QOS-React-2 / commits / 7baf9d4128

Combine Flags and SubtreeFlags types (#19775)

Because the `subtreeFlags` is the union of all the flags present in a subtree, we can use the same type as `flags`. One practical benefit is that we can bubble up the flags from the children with a single `|=` operator. Structurally, everything else about the effect algorithm is unchanged.

Andrew Clark committed Sep 4, 2020 at 16:48 UTC 7baf9d4128d41903de125527b50285ea9862cf9a
6 files changed +38 -113
packages/react-reconciler/src/ReactFiber.new.js
+3 -4
@@ -30,7 +30,6 @@ import {
30 enableBlocksAPI,
31 } from 'shared/ReactFeatureFlags';
32 import {NoFlags, Placement, StaticMask} from './ReactFiberFlags';
33 -import {NoFlags as NoSubtreeEffect} from './ReactSubtreeFlags';
33 import {ConcurrentRoot, BlockingRoot} from './ReactRootTags';
34 import {
35 IndeterminateComponent,
@@ -145,7 +144,7 @@ function FiberNode(
144
145 // Effects
146 this.flags = NoFlags;
148 - this.subtreeFlags = NoSubtreeEffect;
147 + this.subtreeFlags = NoFlags;
148 this.deletions = null;
149
150 this.lanes = NoLanes;
@@ -284,7 +283,7 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
283 workInProgress.type = current.type;
284
285 // We already have an alternate.
287 - workInProgress.subtreeFlags = NoSubtreeEffect;
286 + workInProgress.subtreeFlags = NoFlags;
287 workInProgress.deletions = null;
288
289 if (enableProfilerTimer) {
@@ -372,7 +371,7 @@ export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
371 workInProgress.lanes = renderLanes;
372
373 workInProgress.child = null;
375 - workInProgress.subtreeFlags = NoSubtreeEffect;
374 + workInProgress.subtreeFlags = NoFlags;
375 workInProgress.memoizedProps = null;
376 workInProgress.memoizedState = null;
377 workInProgress.updateQueue = null;
packages/react-reconciler/src/ReactFiberCommitWork.new.js
+2 -8
@@ -71,6 +71,7 @@ import {
71 Placement,
72 Snapshot,
73 Update,
74 + PassiveMask,
75 } from './ReactFiberFlags';
76 import getComponentName from 'shared/getComponentName';
77 import invariant from 'shared/invariant';
@@ -130,10 +131,6 @@ import {
131 Passive as HookPassive,
132 } from './ReactHookEffectTags';
133 import {didWarnAboutReassigningProps} from './ReactFiberBeginWork.new';
133 -import {
134 - NoFlags as NoSubtreeFlags,
135 - Passive as PassiveSubtreeFlags,
136 -} from './ReactSubtreeFlags';
134
135 let didWarnAboutUndefinedSnapshotBeforeUpdate: Set<mixed> | null = null;
136 if (__DEV__) {
@@ -595,10 +592,7 @@ function commitLifeCycles(
592 commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);
593 }
594
598 - if (
599 - (finishedWork.subtreeFlags & PassiveSubtreeFlags) !==
600 - NoSubtreeFlags
601 - ) {
595 + if ((finishedWork.subtreeFlags & PassiveMask) !== NoFlags) {
596 schedulePassiveEffectCallback();
597 }
598 return;
packages/react-reconciler/src/ReactFiberCompleteWork.new.js
+1 -2
@@ -67,7 +67,6 @@ import {
67 Snapshot,
68 MutationMask,
69 } from './ReactFiberFlags';
70 -import {NoFlags as NoSubtreeFlags, Mutation} from './ReactSubtreeFlags';
70 import invariant from 'shared/invariant';
71
72 import {
@@ -166,7 +165,7 @@ function hadNoMutationsEffects(current: null | Fiber, completedWork: Fiber) {
165 if ((child.flags & MutationMask) !== NoFlags) {
166 return false;
167 }
169 - if ((child.subtreeFlags & Mutation) !== NoSubtreeFlags) {
168 + if ((child.subtreeFlags & MutationMask) !== NoFlags) {
169 return false;
170 }
171 child = child.sibling;
packages/react-reconciler/src/ReactFiberWorkLoop.new.js
+31 -79
@@ -139,15 +139,8 @@ import {
139 MutationMask,
140 LayoutMask,
141 PassiveMask,
142 + StaticMask,
143 } from './ReactFiberFlags';
143 -import {
144 - NoFlags as NoSubtreeFlags,
145 - BeforeMutation as BeforeMutationSubtreeFlags,
146 - Mutation as MutationSubtreeFlags,
147 - Layout as LayoutSubtreeFlags,
148 - Passive as PassiveSubtreeFlags,
149 - PassiveStatic as PassiveStaticSubtreeFlags,
150 -} from './ReactSubtreeFlags';
144 import {
145 NoLanePriority,
146 SyncLanePriority,
@@ -1766,7 +1759,7 @@ function completeUnitOfWork(unitOfWork: Fiber): void {
1759 if (returnFiber !== null) {
1760 // Mark the parent fiber as incomplete
1761 returnFiber.flags |= Incomplete;
1769 - returnFiber.subtreeFlags = NoSubtreeFlags;
1762 + returnFiber.subtreeFlags = NoFlags;
1763 returnFiber.deletions = null;
1764 }
1765 }
@@ -1809,7 +1802,7 @@ function resetChildLanes(completedWork: Fiber) {
1802 completedWork.alternate.child === completedWork.child;
1803
1804 let newChildLanes = NoLanes;
1812 - let subtreeFlags = NoSubtreeFlags;
1805 + let subtreeFlags = NoFlags;
1806
1807 if (!didBailout) {
1808 // Bubble up the earliest expiration time.
@@ -1827,23 +1820,7 @@ function resetChildLanes(completedWork: Fiber) {
1820 );
1821
1822 subtreeFlags |= child.subtreeFlags;
1830 -
1831 - const flags = child.flags;
1832 - if ((flags & BeforeMutationMask) !== NoFlags) {
1833 - subtreeFlags |= BeforeMutationSubtreeFlags;
1834 - }
1835 - if ((flags & MutationMask) !== NoFlags) {
1836 - subtreeFlags |= MutationSubtreeFlags;
1837 - }
1838 - if ((flags & LayoutMask) !== NoFlags) {
1839 - subtreeFlags |= LayoutSubtreeFlags;
1840 - }
1841 - if ((flags & PassiveMask) !== NoFlags) {
1842 - subtreeFlags |= PassiveSubtreeFlags;
1843 - }
1844 - if ((flags & PassiveStatic) !== NoFlags) {
1845 - subtreeFlags |= PassiveStaticSubtreeFlags;
1846 - }
1823 + subtreeFlags |= child.flags;
1824
1825 // When a fiber is cloned, its actualDuration is reset to 0. This value will
1826 // only be updated if work is done on the fiber (i.e. it doesn't bailout).
@@ -1880,23 +1857,7 @@ function resetChildLanes(completedWork: Fiber) {
1857 );
1858
1859 subtreeFlags |= child.subtreeFlags;
1883 -
1884 - const flags = child.flags;
1885 - if ((flags & BeforeMutationMask) !== NoFlags) {
1886 - subtreeFlags |= BeforeMutationSubtreeFlags;
1887 - }
1888 - if ((flags & MutationMask) !== NoFlags) {
1889 - subtreeFlags |= MutationSubtreeFlags;
1890 - }
1891 - if ((flags & LayoutMask) !== NoFlags) {
1892 - subtreeFlags |= LayoutSubtreeFlags;
1893 - }
1894 - if ((flags & PassiveMask) !== NoFlags) {
1895 - subtreeFlags |= PassiveSubtreeFlags;
1896 - }
1897 - if ((flags & PassiveStatic) !== NoFlags) {
1898 - subtreeFlags |= PassiveStaticSubtreeFlags;
1899 - }
1860 + subtreeFlags |= child.flags;
1861
1862 child = child.sibling;
1863 }
@@ -1917,13 +1878,12 @@ function resetChildLanes(completedWork: Fiber) {
1878 mergeLanes(child.lanes, child.childLanes),
1879 );
1880
1920 - // Preserve passive static flag even in the case of a bailout;
1921 - // otherwise a subsequent unmount may bailout before calling destroy functions.
1922 - subtreeFlags |= child.subtreeFlags & PassiveStaticSubtreeFlags;
1923 - const flags = child.flags;
1924 - if ((flags & PassiveStatic) !== NoFlags) {
1925 - subtreeFlags |= PassiveStaticSubtreeFlags;
1926 - }
1881 + // "Static" flags share the lifetime of the fiber/hook they belong to,
1882 + // so we should bubble those up even during a bailout. All the other
1883 + // flags have a lifetime only of a single render + commit, so we should
1884 + // ignore them.
1885 + subtreeFlags |= child.subtreeFlags & StaticMask;
1886 + subtreeFlags |= child.flags & StaticMask;
1887
1888 treeBaseDuration += child.treeBaseDuration;
1889 child = child.sibling;
@@ -1949,13 +1909,12 @@ function resetChildLanes(completedWork: Fiber) {
1909 mergeLanes(child.lanes, child.childLanes),
1910 );
1911
1952 - // Preserve passive static flag even in the case of a bailout;
1953 - // otherwise a subsequent unmount may bailout before calling destroy functions.
1954 - subtreeFlags |= child.subtreeFlags & PassiveStaticSubtreeFlags;
1955 - const flags = child.flags;
1956 - if ((flags & PassiveStatic) !== NoFlags) {
1957 - subtreeFlags |= PassiveStaticSubtreeFlags;
1958 - }
1912 + // "Static" flags share the lifetime of the fiber/hook they belong to,
1913 + // so we should bubble those up even during a bailout. All the other
1914 + // flags have a lifetime only of a single render + commit, so we should
1915 + // ignore them.
1916 + subtreeFlags |= child.subtreeFlags & StaticMask;
1917 + subtreeFlags |= child.flags & StaticMask;
1918
1919 child = child.sibling;
1920 }
@@ -2067,11 +2026,8 @@ function commitRootImpl(root, renderPriorityLevel) {
2026 // Reconsider whether this is necessary.
2027 const subtreeHasEffects =
2028 (finishedWork.subtreeFlags &
2070 - (BeforeMutationSubtreeFlags |
2071 - MutationSubtreeFlags |
2072 - LayoutSubtreeFlags |
2073 - PassiveSubtreeFlags)) !==
2074 - NoSubtreeFlags;
2029 + (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==
2030 + NoFlags;
2031 const rootHasEffect =
2032 (finishedWork.flags &
2033 (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==
@@ -2152,7 +2108,7 @@ function commitRootImpl(root, renderPriorityLevel) {
2108
2109 // If there are pending passive effects, schedule a callback to process them.
2110 if (
2155 - (finishedWork.subtreeFlags & PassiveSubtreeFlags) !== NoSubtreeFlags ||
2111 + (finishedWork.subtreeFlags & PassiveMask) !== NoFlags ||
2112 (finishedWork.flags & PassiveMask) !== NoFlags
2113 ) {
2114 if (!rootDoesHavePassiveEffects) {
@@ -2306,9 +2262,8 @@ function commitBeforeMutationEffects(firstChild: Fiber) {
2262 }
2263
2264 if (fiber.child !== null) {
2309 - const primarySubtreeFlags =
2310 - fiber.subtreeFlags & BeforeMutationSubtreeFlags;
2311 - if (primarySubtreeFlags !== NoSubtreeFlags) {
2265 + const primarySubtreeFlags = fiber.subtreeFlags & BeforeMutationMask;
2266 + if (primarySubtreeFlags !== NoFlags) {
2267 commitBeforeMutationEffects(fiber.child);
2268 }
2269 }
@@ -2402,8 +2357,8 @@ function commitMutationEffects(
2357 }
2358
2359 if (fiber.child !== null) {
2405 - const primarySubtreeFlags = fiber.subtreeFlags & MutationSubtreeFlags;
2406 - if (primarySubtreeFlags !== NoSubtreeFlags) {
2360 + const mutationFlags = fiber.subtreeFlags & MutationMask;
2361 + if (mutationFlags !== NoFlags) {
2362 commitMutationEffects(fiber.child, root, renderPriorityLevel);
2363 }
2364 }
@@ -2560,8 +2515,8 @@ function commitLayoutEffects(
2515 let fiber = firstChild;
2516 while (fiber !== null) {
2517 if (fiber.child !== null) {
2563 - const primarySubtreeFlags = fiber.subtreeFlags & LayoutSubtreeFlags;
2564 - if (primarySubtreeFlags !== NoSubtreeFlags) {
2518 + const primarySubtreeFlags = fiber.subtreeFlags & LayoutMask;
2519 + if (primarySubtreeFlags !== NoFlags) {
2520 commitLayoutEffects(fiber.child, root, committedLanes);
2521 }
2522 }
@@ -2662,9 +2617,9 @@ export function enqueuePendingPassiveProfilerEffect(fiber: Fiber): void {
2617 function flushPassiveMountEffects(firstChild: Fiber): void {
2618 let fiber = firstChild;
2619 while (fiber !== null) {
2665 - const primarySubtreeFlags = fiber.subtreeFlags & PassiveSubtreeFlags;
2620 + const primarySubtreeFlags = fiber.subtreeFlags & PassiveMask;
2621
2667 - if (fiber.child !== null && primarySubtreeFlags !== NoSubtreeFlags) {
2622 + if (fiber.child !== null && primarySubtreeFlags !== NoFlags) {
2623 flushPassiveMountEffects(fiber.child);
2624 }
2625
@@ -2698,8 +2653,8 @@ function flushPassiveUnmountEffects(firstChild: Fiber): void {
2653 // Note that this requires checking subtreeFlags of the current Fiber,
2654 // rather than the subtreeFlags/effectsTag of the first child,
2655 // since that would not cover passive effects in siblings.
2701 - const primarySubtreeFlags = fiber.subtreeFlags & PassiveSubtreeFlags;
2702 - if (primarySubtreeFlags !== NoSubtreeFlags) {
2656 + const passiveFlags = fiber.subtreeFlags & PassiveMask;
2657 + if (passiveFlags !== NoFlags) {
2658 flushPassiveUnmountEffects(child);
2659 }
2660 }
@@ -2719,10 +2674,7 @@ function flushPassiveUnmountEffectsInsideOfDeletedTree(
2674 fiberToDelete: Fiber,
2675 nearestMountedAncestor: Fiber,
2676 ): void {
2722 - if (
2723 - (fiberToDelete.subtreeFlags & PassiveStaticSubtreeFlags) !==
2724 - NoSubtreeFlags
2725 - ) {
2677 + if ((fiberToDelete.subtreeFlags & PassiveStatic) !== NoFlags) {
2678 // If any children have passive effects then traverse the subtree.
2679 // Note that this requires checking subtreeFlags of the current Fiber,
2680 // rather than the subtreeFlags/effectsTag of the first child,
packages/react-reconciler/src/ReactInternalTypes.js
+1 -2
@@ -20,7 +20,6 @@ import type {SuspenseInstance} from './ReactFiberHostConfig';
20 import type {WorkTag} from './ReactWorkTags';
21 import type {TypeOfMode} from './ReactTypeOfMode';
22 import type {Flags} from './ReactFiberFlags';
23 -import type {SubtreeFlags} from './ReactSubtreeFlags';
23 import type {Lane, LanePriority, Lanes, LaneMap} from './ReactFiberLane';
24 import type {HookType} from './ReactFiberHooks.old';
25 import type {RootTag} from './ReactRootTags';
@@ -119,7 +118,7 @@ export type Fiber = {|
118
119 // Effect
120 flags: Flags,
122 - subtreeFlags: SubtreeFlags,
121 + subtreeFlags: Flags,
122 deletions: Array<Fiber> | null,
123
124 // Singly linked list fast path to the next fiber with side-effects.
packages/react-reconciler/src/ReactSubtreeFlags.js deleted
-18
@@ -1,18 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -// TODO: Move this to ReactFiberFlags so it's easier to line up the bits
11 -export type SubtreeFlags = number;
12 -
13 -export const NoFlags = /* */ 0b00000;
14 -export const BeforeMutation = /* */ 0b00001;
15 -export const Mutation = /* */ 0b00010;
16 -export const Layout = /* */ 0b00100;
17 -export const Passive = /* */ 0b01000;
18 -export const PassiveStatic = /* */ 0b10000;