Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ac157d0

Browse files
author
Brian Vaughn
committedJul 29, 2020
Moved resetChildLanes into complete work
This enabled us to remove a few hot path tag-type checks, but did not otherwise change any functionality.
1 parent 9dc5188 commit ac157d0

File tree

2 files changed

+216
-170
lines changed

2 files changed

+216
-170
lines changed
 

‎packages/react-reconciler/src/ReactFiberCompleteWork.new.js

Lines changed: 215 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*/
99

1010
import type {Fiber} from './ReactInternalTypes';
11-
import type {Lanes} from './ReactFiberLane';
11+
import type {Lanes, Lane} from './ReactFiberLane';
1212
import type {
1313
ReactFundamentalComponentInstance,
1414
ReactScopeInstance,
@@ -58,16 +58,30 @@ import {
5858
OffscreenComponent,
5959
LegacyHiddenComponent,
6060
} from './ReactWorkTags';
61-
import {NoMode, BlockingMode, ProfileMode} from './ReactTypeOfMode';
61+
import {
62+
NoMode,
63+
BlockingMode,
64+
ProfileMode,
65+
ConcurrentMode,
66+
} from './ReactTypeOfMode';
6267
import {
6368
Ref,
6469
Update,
6570
NoEffect,
6671
DidCapture,
6772
Snapshot,
73+
BeforeMutationMask,
6874
MutationMask,
75+
LayoutMask,
76+
PassiveMask,
6977
} from './ReactSideEffectTags';
70-
import {NoEffect as NoSubtreeTag, Mutation} from './ReactSubtreeTags';
78+
import {
79+
NoEffect as NoSubtreeTag,
80+
BeforeMutation as BeforeMutationSubtreeTag,
81+
Mutation as MutationSubtreeTag,
82+
Layout as LayoutSubtreeTag,
83+
Passive as PassiveSubtreeTag,
84+
} from './ReactSubtreeTags';
7185
import invariant from 'shared/invariant';
7286

7387
import {
@@ -138,9 +152,15 @@ import {
138152
renderDidSuspendDelayIfPossible,
139153
renderHasNotSuspendedYet,
140154
popRenderLanes,
155+
subtreeRenderLanes,
141156
} from './ReactFiberWorkLoop.new';
142157
import {createFundamentalStateInstance} from './ReactFiberFundamental.new';
143-
import {OffscreenLane} from './ReactFiberLane';
158+
import {
159+
includesSomeLane,
160+
OffscreenLane,
161+
mergeLanes,
162+
NoLanes,
163+
} from './ReactFiberLane';
144164
import {resetChildFibers} from './ReactChildFiber.new';
145165
import {updateDeprecatedEventListeners} from './ReactFiberDeprecatedEvents.new';
146166
import {createScopeInstance} from './ReactFiberScope.new';
@@ -167,7 +187,7 @@ function hadNoMutationsEffects(current: null | Fiber, completedWork: Fiber) {
167187
if ((child.effectTag & MutationMask) !== NoEffect) {
168188
return false;
169189
}
170-
if ((child.subtreeTag & Mutation) !== NoSubtreeTag) {
190+
if ((child.subtreeTag & MutationSubtreeTag) !== NoSubtreeTag) {
171191
return false;
172192
}
173193
child = child.sibling;
@@ -670,6 +690,124 @@ function cutOffTailIfNeeded(
670690
}
671691
}
672692

693+
function bubbleProperties(completedWork: Fiber): void {
694+
const didBailout =
695+
completedWork.alternate !== null &&
696+
completedWork.alternate.child === completedWork.child;
697+
698+
let newChildLanes = NoLanes;
699+
let subtreeTag = NoSubtreeTag;
700+
701+
if (!didBailout) {
702+
// Bubble up the earliest expiration time.
703+
if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
704+
// In profiling mode, resetChildExpirationTime is also used to reset
705+
// profiler durations.
706+
let actualDuration = completedWork.actualDuration;
707+
let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);
708+
709+
let child = completedWork.child;
710+
while (child !== null) {
711+
newChildLanes = mergeLanes(
712+
newChildLanes,
713+
mergeLanes(child.lanes, child.childLanes),
714+
);
715+
716+
subtreeTag |= child.subtreeTag;
717+
718+
const effectTag = child.effectTag;
719+
if ((effectTag & BeforeMutationMask) !== NoEffect) {
720+
subtreeTag |= BeforeMutationSubtreeTag;
721+
}
722+
if ((effectTag & MutationMask) !== NoEffect) {
723+
subtreeTag |= MutationSubtreeTag;
724+
}
725+
if ((effectTag & LayoutMask) !== NoEffect) {
726+
subtreeTag |= LayoutSubtreeTag;
727+
}
728+
if ((effectTag & PassiveMask) !== NoEffect) {
729+
subtreeTag |= PassiveSubtreeTag;
730+
}
731+
732+
// When a fiber is cloned, its actualDuration is reset to 0. This value will
733+
// only be updated if work is done on the fiber (i.e. it doesn't bailout).
734+
// When work is done, it should bubble to the parent's actualDuration. If
735+
// the fiber has not been cloned though, (meaning no work was done), then
736+
// this value will reflect the amount of time spent working on a previous
737+
// render. In that case it should not bubble. We determine whether it was
738+
// cloned by comparing the child pointer.
739+
actualDuration += child.actualDuration;
740+
741+
treeBaseDuration += child.treeBaseDuration;
742+
child = child.sibling;
743+
}
744+
745+
completedWork.actualDuration = actualDuration;
746+
completedWork.treeBaseDuration = treeBaseDuration;
747+
} else {
748+
let child = completedWork.child;
749+
while (child !== null) {
750+
newChildLanes = mergeLanes(
751+
newChildLanes,
752+
mergeLanes(child.lanes, child.childLanes),
753+
);
754+
755+
subtreeTag |= child.subtreeTag;
756+
757+
const effectTag = child.effectTag;
758+
if ((effectTag & BeforeMutationMask) !== NoEffect) {
759+
subtreeTag |= BeforeMutationSubtreeTag;
760+
}
761+
if ((effectTag & MutationMask) !== NoEffect) {
762+
subtreeTag |= MutationSubtreeTag;
763+
}
764+
if ((effectTag & LayoutMask) !== NoEffect) {
765+
subtreeTag |= LayoutSubtreeTag;
766+
}
767+
if ((effectTag & PassiveMask) !== NoEffect) {
768+
subtreeTag |= PassiveSubtreeTag;
769+
}
770+
771+
child = child.sibling;
772+
}
773+
}
774+
775+
completedWork.subtreeTag |= subtreeTag;
776+
} else {
777+
// Bubble up the earliest expiration time.
778+
if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
779+
// In profiling mode, resetChildExpirationTime is also used to reset
780+
// profiler durations.
781+
let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);
782+
783+
let child = completedWork.child;
784+
while (child !== null) {
785+
newChildLanes = mergeLanes(
786+
newChildLanes,
787+
mergeLanes(child.lanes, child.childLanes),
788+
);
789+
790+
treeBaseDuration += child.treeBaseDuration;
791+
child = child.sibling;
792+
}
793+
794+
completedWork.treeBaseDuration = treeBaseDuration;
795+
} else {
796+
let child = completedWork.child;
797+
while (child !== null) {
798+
newChildLanes = mergeLanes(
799+
newChildLanes,
800+
mergeLanes(child.lanes, child.childLanes),
801+
);
802+
803+
child = child.sibling;
804+
}
805+
}
806+
}
807+
808+
completedWork.childLanes = newChildLanes;
809+
}
810+
673811
function completeWork(
674812
current: Fiber | null,
675813
workInProgress: Fiber,
@@ -688,12 +826,14 @@ function completeWork(
688826
case Profiler:
689827
case ContextConsumer:
690828
case MemoComponent:
829+
bubbleProperties(workInProgress);
691830
return null;
692831
case ClassComponent: {
693832
const Component = workInProgress.type;
694833
if (isLegacyContextProvider(Component)) {
695834
popLegacyContext(workInProgress);
696835
}
836+
bubbleProperties(workInProgress);
697837
return null;
698838
}
699839
case HostRoot: {
@@ -722,6 +862,7 @@ function completeWork(
722862
}
723863
}
724864
updateHostContainer(current, workInProgress);
865+
bubbleProperties(workInProgress);
725866
return null;
726867
}
727868
case HostComponent: {
@@ -756,6 +897,7 @@ function completeWork(
756897
'caused by a bug in React. Please file an issue.',
757898
);
758899
// This can happen when we abort work.
900+
bubbleProperties(workInProgress);
759901
return null;
760902
}
761903

@@ -835,6 +977,8 @@ function completeWork(
835977
markRef(workInProgress);
836978
}
837979
}
980+
981+
bubbleProperties(workInProgress);
838982
return null;
839983
}
840984
case HostText: {
@@ -869,6 +1013,7 @@ function completeWork(
8691013
);
8701014
}
8711015
}
1016+
bubbleProperties(workInProgress);
8721017
return null;
8731018
}
8741019
case SuspenseComponent: {
@@ -888,6 +1033,20 @@ function completeWork(
8881033
if (enableSchedulerTracing) {
8891034
markSpawnedWork(OffscreenLane);
8901035
}
1036+
bubbleProperties(workInProgress);
1037+
if (enableProfilerTimer) {
1038+
if ((workInProgress.mode & ProfileMode) !== NoMode) {
1039+
const isTimedOutSuspense = nextState !== null;
1040+
if (isTimedOutSuspense) {
1041+
// Don't count time spent in a timed out Suspense subtree as part of the base duration.
1042+
const primaryChildFragment = workInProgress.child;
1043+
if (primaryChildFragment !== null) {
1044+
// $FlowFixMe Flow doens't support type casting in combiation with the -= operator
1045+
workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
1046+
}
1047+
}
1048+
}
1049+
}
8911050
return null;
8921051
} else {
8931052
// We should never have been in a hydration state if we didn't have a current.
@@ -904,6 +1063,20 @@ function completeWork(
9041063
// If something suspended, schedule an effect to attach retry listeners.
9051064
// So we might as well always mark this.
9061065
workInProgress.effectTag |= Update;
1066+
bubbleProperties(workInProgress);
1067+
if (enableProfilerTimer) {
1068+
if ((workInProgress.mode & ProfileMode) !== NoMode) {
1069+
const isTimedOutSuspense = nextState !== null;
1070+
if (isTimedOutSuspense) {
1071+
// Don't count time spent in a timed out Suspense subtree as part of the base duration.
1072+
const primaryChildFragment = workInProgress.child;
1073+
if (primaryChildFragment !== null) {
1074+
// $FlowFixMe Flow doens't support type casting in combiation with the -= operator
1075+
workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
1076+
}
1077+
}
1078+
}
1079+
}
9071080
return null;
9081081
}
9091082
}
@@ -996,6 +1169,20 @@ function completeWork(
9961169
// Always notify the callback
9971170
workInProgress.effectTag |= Update;
9981171
}
1172+
bubbleProperties(workInProgress);
1173+
if (enableProfilerTimer) {
1174+
if ((workInProgress.mode & ProfileMode) !== NoMode) {
1175+
const isTimedOutSuspense = nextState !== null;
1176+
if (isTimedOutSuspense) {
1177+
// Don't count time spent in a timed out Suspense subtree as part of the base duration.
1178+
const primaryChildFragment = workInProgress.child;
1179+
if (primaryChildFragment !== null) {
1180+
// $FlowFixMe Flow doens't support type casting in combiation with the -= operator
1181+
workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
1182+
}
1183+
}
1184+
}
1185+
}
9991186
return null;
10001187
}
10011188
case HostPortal:
@@ -1004,10 +1191,12 @@ function completeWork(
10041191
if (current === null) {
10051192
preparePortalMount(workInProgress.stateNode.containerInfo);
10061193
}
1194+
bubbleProperties(workInProgress);
10071195
return null;
10081196
case ContextProvider:
10091197
// Pop provider fiber
10101198
popProvider(workInProgress);
1199+
bubbleProperties(workInProgress);
10111200
return null;
10121201
case IncompleteClassComponent: {
10131202
// Same as class component case. I put it down here so that the tags are
@@ -1016,6 +1205,7 @@ function completeWork(
10161205
if (isLegacyContextProvider(Component)) {
10171206
popLegacyContext(workInProgress);
10181207
}
1208+
bubbleProperties(workInProgress);
10191209
return null;
10201210
}
10211211
case SuspenseListComponent: {
@@ -1027,6 +1217,7 @@ function completeWork(
10271217
if (renderState === null) {
10281218
// We're running in the default, "independent" mode.
10291219
// We don't do anything in this mode.
1220+
bubbleProperties(workInProgress);
10301221
return null;
10311222
}
10321223

@@ -1146,6 +1337,7 @@ function completeWork(
11461337
lastEffect.nextEffect = null;
11471338
}
11481339
// We're done.
1340+
bubbleProperties(workInProgress);
11491341
return null;
11501342
}
11511343
} else if (
@@ -1231,6 +1423,7 @@ function completeWork(
12311423
// Do a pass over the next row.
12321424
return next;
12331425
}
1426+
bubbleProperties(workInProgress);
12341427
return null;
12351428
}
12361429
case FundamentalComponent: {
@@ -1258,6 +1451,7 @@ function completeWork(
12581451
): any): Instance);
12591452
fundamentalInstance.instance = instance;
12601453
if (fundamentalImpl.reconcileChildren === false) {
1454+
bubbleProperties(workInProgress);
12611455
return null;
12621456
}
12631457
appendAllChildren(instance, workInProgress, false, false);
@@ -1280,6 +1474,7 @@ function completeWork(
12801474
markUpdate(workInProgress);
12811475
}
12821476
}
1477+
bubbleProperties(workInProgress);
12831478
return null;
12841479
}
12851480
break;
@@ -1325,31 +1520,44 @@ function completeWork(
13251520
markRef(workInProgress);
13261521
}
13271522
}
1523+
bubbleProperties(workInProgress);
13281524
return null;
13291525
}
13301526
break;
13311527
}
13321528
case Block:
13331529
if (enableBlocksAPI) {
1530+
bubbleProperties(workInProgress);
13341531
return null;
13351532
}
13361533
break;
13371534
case OffscreenComponent:
13381535
case LegacyHiddenComponent: {
13391536
popRenderLanes(workInProgress);
1537+
const nextState: OffscreenState | null = workInProgress.memoizedState;
1538+
const nextIsHidden = nextState !== null;
1539+
13401540
if (current !== null) {
1341-
const nextState: OffscreenState | null = workInProgress.memoizedState;
13421541
const prevState: OffscreenState | null = current.memoizedState;
13431542

13441543
const prevIsHidden = prevState !== null;
1345-
const nextIsHidden = nextState !== null;
13461544
if (
13471545
prevIsHidden !== nextIsHidden &&
13481546
newProps.mode !== 'unstable-defer-without-hiding'
13491547
) {
13501548
workInProgress.effectTag |= Update;
13511549
}
13521550
}
1551+
1552+
// Don't bubble properties for hidden children.
1553+
if (
1554+
!nextIsHidden ||
1555+
includesSomeLane(subtreeRenderLanes, (OffscreenLane: Lane)) ||
1556+
(workInProgress.mode & ConcurrentMode) === NoLanes
1557+
) {
1558+
bubbleProperties(workInProgress);
1559+
}
1560+
13531561
return null;
13541562
}
13551563
}

‎packages/react-reconciler/src/ReactFiberWorkLoop.new.js

Lines changed: 1 addition & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,6 @@ import {
116116
MemoComponent,
117117
SimpleMemoComponent,
118118
Block,
119-
OffscreenComponent,
120-
LegacyHiddenComponent,
121119
ScopeComponent,
122120
} from './ReactWorkTags';
123121
import {LegacyRoot} from './ReactRootTags';
@@ -137,9 +135,6 @@ import {
137135
HostEffectMask,
138136
Hydrating,
139137
HydratingAndUpdate,
140-
BeforeMutationMask,
141-
MutationMask,
142-
LayoutMask,
143138
PassiveMask,
144139
} from './ReactSideEffectTags';
145140
import {
@@ -161,7 +156,6 @@ import {
161156
NoLane,
162157
SyncLane,
163158
SyncBatchedLane,
164-
OffscreenLane,
165159
NoTimestamp,
166160
findUpdateLane,
167161
findTransitionLane,
@@ -297,7 +291,7 @@ let workInProgressRootRenderLanes: Lanes = NoLanes;
297291
//
298292
// Most things in the work loop should deal with workInProgressRootRenderLanes.
299293
// Most things in begin/complete phases should deal with subtreeRenderLanes.
300-
let subtreeRenderLanes: Lanes = NoLanes;
294+
export let subtreeRenderLanes: Lanes = NoLanes;
301295
const subtreeRenderLanesCursor: StackCursor<Lanes> = createCursor(NoLanes);
302296

303297
// Whether to root completed, errored, suspended, etc.
@@ -1745,8 +1739,6 @@ function completeUnitOfWork(unitOfWork: Fiber): void {
17451739
return;
17461740
}
17471741

1748-
resetChildLanes(completedWork);
1749-
17501742
if (
17511743
returnFiber !== null &&
17521744
// Do not append effects to parents if a sibling failed to complete
@@ -1847,160 +1839,6 @@ function completeUnitOfWork(unitOfWork: Fiber): void {
18471839
}
18481840
}
18491841

1850-
function resetChildLanes(completedWork: Fiber) {
1851-
if (
1852-
// TODO: Move this check out of the hot path by moving `resetChildLanes`
1853-
// to switch statement in `completeWork`.
1854-
(completedWork.tag === LegacyHiddenComponent ||
1855-
completedWork.tag === OffscreenComponent) &&
1856-
completedWork.memoizedState !== null &&
1857-
!includesSomeLane(subtreeRenderLanes, (OffscreenLane: Lane)) &&
1858-
(completedWork.mode & ConcurrentMode) !== NoLanes
1859-
) {
1860-
// The children of this component are hidden. Don't bubble their
1861-
// expiration times.
1862-
return;
1863-
}
1864-
1865-
const didBailout =
1866-
completedWork.alternate !== null &&
1867-
completedWork.alternate.child === completedWork.child;
1868-
1869-
let newChildLanes = NoLanes;
1870-
let subtreeTag = NoSubtreeTag;
1871-
1872-
if (!didBailout) {
1873-
// Bubble up the earliest expiration time.
1874-
if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
1875-
// In profiling mode, resetChildExpirationTime is also used to reset
1876-
// profiler durations.
1877-
let actualDuration = completedWork.actualDuration;
1878-
let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);
1879-
1880-
let child = completedWork.child;
1881-
while (child !== null) {
1882-
newChildLanes = mergeLanes(
1883-
newChildLanes,
1884-
mergeLanes(child.lanes, child.childLanes),
1885-
);
1886-
1887-
subtreeTag |= child.subtreeTag;
1888-
1889-
const effectTag = child.effectTag;
1890-
if ((effectTag & BeforeMutationMask) !== NoEffect) {
1891-
subtreeTag |= BeforeMutationSubtreeTag;
1892-
}
1893-
if ((effectTag & MutationMask) !== NoEffect) {
1894-
subtreeTag |= MutationSubtreeTag;
1895-
}
1896-
if ((effectTag & LayoutMask) !== NoEffect) {
1897-
subtreeTag |= LayoutSubtreeTag;
1898-
}
1899-
if ((effectTag & PassiveMask) !== NoEffect) {
1900-
subtreeTag |= PassiveSubtreeTag;
1901-
}
1902-
1903-
// When a fiber is cloned, its actualDuration is reset to 0. This value will
1904-
// only be updated if work is done on the fiber (i.e. it doesn't bailout).
1905-
// When work is done, it should bubble to the parent's actualDuration. If
1906-
// the fiber has not been cloned though, (meaning no work was done), then
1907-
// this value will reflect the amount of time spent working on a previous
1908-
// render. In that case it should not bubble. We determine whether it was
1909-
// cloned by comparing the child pointer.
1910-
actualDuration += child.actualDuration;
1911-
1912-
treeBaseDuration += child.treeBaseDuration;
1913-
child = child.sibling;
1914-
}
1915-
1916-
const isTimedOutSuspense =
1917-
completedWork.tag === SuspenseComponent &&
1918-
completedWork.memoizedState !== null;
1919-
if (isTimedOutSuspense) {
1920-
// Don't count time spent in a timed out Suspense subtree as part of the base duration.
1921-
const primaryChildFragment = completedWork.child;
1922-
if (primaryChildFragment !== null) {
1923-
treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
1924-
}
1925-
}
1926-
1927-
completedWork.actualDuration = actualDuration;
1928-
completedWork.treeBaseDuration = treeBaseDuration;
1929-
} else {
1930-
let child = completedWork.child;
1931-
while (child !== null) {
1932-
newChildLanes = mergeLanes(
1933-
newChildLanes,
1934-
mergeLanes(child.lanes, child.childLanes),
1935-
);
1936-
1937-
subtreeTag |= child.subtreeTag;
1938-
1939-
const effectTag = child.effectTag;
1940-
if ((effectTag & BeforeMutationMask) !== NoEffect) {
1941-
subtreeTag |= BeforeMutationSubtreeTag;
1942-
}
1943-
if ((effectTag & MutationMask) !== NoEffect) {
1944-
subtreeTag |= MutationSubtreeTag;
1945-
}
1946-
if ((effectTag & LayoutMask) !== NoEffect) {
1947-
subtreeTag |= LayoutSubtreeTag;
1948-
}
1949-
if ((effectTag & PassiveMask) !== NoEffect) {
1950-
subtreeTag |= PassiveSubtreeTag;
1951-
}
1952-
1953-
child = child.sibling;
1954-
}
1955-
}
1956-
1957-
completedWork.subtreeTag |= subtreeTag;
1958-
} else {
1959-
// Bubble up the earliest expiration time.
1960-
if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
1961-
// In profiling mode, resetChildExpirationTime is also used to reset
1962-
// profiler durations.
1963-
let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);
1964-
1965-
let child = completedWork.child;
1966-
while (child !== null) {
1967-
newChildLanes = mergeLanes(
1968-
newChildLanes,
1969-
mergeLanes(child.lanes, child.childLanes),
1970-
);
1971-
1972-
treeBaseDuration += child.treeBaseDuration;
1973-
child = child.sibling;
1974-
}
1975-
1976-
const isTimedOutSuspense =
1977-
completedWork.tag === SuspenseComponent &&
1978-
completedWork.memoizedState !== null;
1979-
if (isTimedOutSuspense) {
1980-
// Don't count time spent in a timed out Suspense subtree as part of the base duration.
1981-
const primaryChildFragment = completedWork.child;
1982-
if (primaryChildFragment !== null) {
1983-
treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
1984-
}
1985-
}
1986-
1987-
completedWork.treeBaseDuration = treeBaseDuration;
1988-
} else {
1989-
let child = completedWork.child;
1990-
while (child !== null) {
1991-
newChildLanes = mergeLanes(
1992-
newChildLanes,
1993-
mergeLanes(child.lanes, child.childLanes),
1994-
);
1995-
1996-
child = child.sibling;
1997-
}
1998-
}
1999-
}
2000-
2001-
completedWork.childLanes = newChildLanes;
2002-
}
2003-
20041842
function commitRoot(root) {
20051843
const renderPriorityLevel = getCurrentPriorityLevel();
20061844
runWithPriority(

0 commit comments

Comments
 (0)
Please sign in to comment.