Skip to content

Commit

Permalink
Moved resetChildLanes into complete work (#19836)
Browse files Browse the repository at this point in the history
This allows us to inline a few checks that are specific to a certain tag-type.
  • Loading branch information
Brian Vaughn authored Sep 15, 2020
1 parent b93f3e7 commit 16fb2b6
Show file tree
Hide file tree
Showing 2 changed files with 198 additions and 156 deletions.
202 changes: 197 additions & 5 deletions packages/react-reconciler/src/ReactFiberCompleteWork.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/

import type {Fiber} from './ReactInternalTypes';
import type {Lanes} from './ReactFiberLane';
import type {Lanes, Lane} from './ReactFiberLane';
import type {
ReactFundamentalComponentInstance,
ReactScopeInstance,
Expand Down Expand Up @@ -58,14 +58,20 @@ import {
OffscreenComponent,
LegacyHiddenComponent,
} from './ReactWorkTags';
import {NoMode, BlockingMode, ProfileMode} from './ReactTypeOfMode';
import {
NoMode,
BlockingMode,
ConcurrentMode,
ProfileMode,
} from './ReactTypeOfMode';
import {
Ref,
Update,
NoFlags,
DidCapture,
Snapshot,
MutationMask,
StaticMask,
} from './ReactFiberFlags';
import invariant from 'shared/invariant';

Expand Down Expand Up @@ -137,9 +143,16 @@ import {
renderHasNotSuspendedYet,
popRenderLanes,
getRenderTargetTime,
subtreeRenderLanes,
} from './ReactFiberWorkLoop.new';
import {createFundamentalStateInstance} from './ReactFiberFundamental.new';
import {OffscreenLane, SomeRetryLane} from './ReactFiberLane';
import {
OffscreenLane,
SomeRetryLane,
NoLanes,
includesSomeLane,
mergeLanes,
} from './ReactFiberLane';
import {resetChildFibers} from './ReactChildFiber.new';
import {createScopeInstance} from './ReactFiberScope.new';
import {transferActualDuration} from './ReactProfilerTimer.new';
Expand Down Expand Up @@ -668,6 +681,114 @@ function cutOffTailIfNeeded(
}
}

function bubbleProperties(completedWork: Fiber) {
const didBailout =
completedWork.alternate !== null &&
completedWork.alternate.child === completedWork.child;

let newChildLanes = NoLanes;
let subtreeFlags = NoFlags;

if (!didBailout) {
// Bubble up the earliest expiration time.
if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
// In profiling mode, resetChildExpirationTime is also used to reset
// profiler durations.
let actualDuration = completedWork.actualDuration;
let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);

let child = completedWork.child;
while (child !== null) {
newChildLanes = mergeLanes(
newChildLanes,
mergeLanes(child.lanes, child.childLanes),
);

subtreeFlags |= child.subtreeFlags;
subtreeFlags |= child.flags;

// When a fiber is cloned, its actualDuration is reset to 0. This value will
// only be updated if work is done on the fiber (i.e. it doesn't bailout).
// When work is done, it should bubble to the parent's actualDuration. If
// the fiber has not been cloned though, (meaning no work was done), then
// this value will reflect the amount of time spent working on a previous
// render. In that case it should not bubble. We determine whether it was
// cloned by comparing the child pointer.
actualDuration += child.actualDuration;

treeBaseDuration += child.treeBaseDuration;
child = child.sibling;
}

completedWork.actualDuration = actualDuration;
completedWork.treeBaseDuration = treeBaseDuration;
} else {
let child = completedWork.child;
while (child !== null) {
newChildLanes = mergeLanes(
newChildLanes,
mergeLanes(child.lanes, child.childLanes),
);

subtreeFlags |= child.subtreeFlags;
subtreeFlags |= child.flags;

child = child.sibling;
}
}

completedWork.subtreeFlags |= subtreeFlags;
} else {
// Bubble up the earliest expiration time.
if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {
// In profiling mode, resetChildExpirationTime is also used to reset
// profiler durations.
let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);

let child = completedWork.child;
while (child !== null) {
newChildLanes = mergeLanes(
newChildLanes,
mergeLanes(child.lanes, child.childLanes),
);

// "Static" flags share the lifetime of the fiber/hook they belong to,
// so we should bubble those up even during a bailout. All the other
// flags have a lifetime only of a single render + commit, so we should
// ignore them.
subtreeFlags |= child.subtreeFlags & StaticMask;
subtreeFlags |= child.flags & StaticMask;

treeBaseDuration += child.treeBaseDuration;
child = child.sibling;
}

completedWork.treeBaseDuration = treeBaseDuration;
} else {
let child = completedWork.child;
while (child !== null) {
newChildLanes = mergeLanes(
newChildLanes,
mergeLanes(child.lanes, child.childLanes),
);

// "Static" flags share the lifetime of the fiber/hook they belong to,
// so we should bubble those up even during a bailout. All the other
// flags have a lifetime only of a single render + commit, so we should
// ignore them.
subtreeFlags |= child.subtreeFlags & StaticMask;
subtreeFlags |= child.flags & StaticMask;

child = child.sibling;
}
}

completedWork.subtreeFlags |= subtreeFlags;
}

completedWork.childLanes = newChildLanes;
}

function completeWork(
current: Fiber | null,
workInProgress: Fiber,
Expand All @@ -686,12 +807,14 @@ function completeWork(
case Profiler:
case ContextConsumer:
case MemoComponent:
bubbleProperties(workInProgress);
return null;
case ClassComponent: {
const Component = workInProgress.type;
if (isLegacyContextProvider(Component)) {
popLegacyContext(workInProgress);
}
bubbleProperties(workInProgress);
return null;
}
case HostRoot: {
Expand Down Expand Up @@ -720,6 +843,7 @@ function completeWork(
}
}
updateHostContainer(current, workInProgress);
bubbleProperties(workInProgress);
return null;
}
case HostComponent: {
Expand All @@ -746,6 +870,7 @@ function completeWork(
'caused by a bug in React. Please file an issue.',
);
// This can happen when we abort work.
bubbleProperties(workInProgress);
return null;
}

Expand Down Expand Up @@ -803,6 +928,7 @@ function completeWork(
markRef(workInProgress);
}
}
bubbleProperties(workInProgress);
return null;
}
case HostText: {
Expand Down Expand Up @@ -837,6 +963,7 @@ function completeWork(
);
}
}
bubbleProperties(workInProgress);
return null;
}
case SuspenseComponent: {
Expand All @@ -856,6 +983,20 @@ function completeWork(
if (enableSchedulerTracing) {
markSpawnedWork(OffscreenLane);
}
bubbleProperties(workInProgress);
if (enableProfilerTimer) {
if ((workInProgress.mode & ProfileMode) !== NoMode) {
const isTimedOutSuspense = nextState !== null;
if (isTimedOutSuspense) {
// Don't count time spent in a timed out Suspense subtree as part of the base duration.
const primaryChildFragment = workInProgress.child;
if (primaryChildFragment !== null) {
// $FlowFixMe Flow doens't support type casting in combiation with the -= operator
workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
}
}
}
}
return null;
} else {
// We should never have been in a hydration state if we didn't have a current.
Expand All @@ -872,6 +1013,20 @@ function completeWork(
// If something suspended, schedule an effect to attach retry listeners.
// So we might as well always mark this.
workInProgress.flags |= Update;
bubbleProperties(workInProgress);
if (enableProfilerTimer) {
if ((workInProgress.mode & ProfileMode) !== NoMode) {
const isTimedOutSuspense = nextState !== null;
if (isTimedOutSuspense) {
// Don't count time spent in a timed out Suspense subtree as part of the base duration.
const primaryChildFragment = workInProgress.child;
if (primaryChildFragment !== null) {
// $FlowFixMe Flow doens't support type casting in combiation with the -= operator
workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
}
}
}
}
return null;
}
}
Expand All @@ -887,6 +1042,7 @@ function completeWork(
) {
transferActualDuration(workInProgress);
}
// Don't bubble properties in this case.
return workInProgress;
}

Expand Down Expand Up @@ -964,6 +1120,19 @@ function completeWork(
// Always notify the callback
workInProgress.flags |= Update;
}
bubbleProperties(workInProgress);
if (enableProfilerTimer) {
if ((workInProgress.mode & ProfileMode) !== NoMode) {
if (nextDidTimeout) {
// Don't count time spent in a timed out Suspense subtree as part of the base duration.
const primaryChildFragment = workInProgress.child;
if (primaryChildFragment !== null) {
// $FlowFixMe Flow doens't support type casting in combiation with the -= operator
workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);
}
}
}
}
return null;
}
case HostPortal:
Expand All @@ -972,10 +1141,12 @@ function completeWork(
if (current === null) {
preparePortalMount(workInProgress.stateNode.containerInfo);
}
bubbleProperties(workInProgress);
return null;
case ContextProvider:
// Pop provider fiber
popProvider(workInProgress);
bubbleProperties(workInProgress);
return null;
case IncompleteClassComponent: {
// Same as class component case. I put it down here so that the tags are
Expand All @@ -984,6 +1155,7 @@ function completeWork(
if (isLegacyContextProvider(Component)) {
popLegacyContext(workInProgress);
}
bubbleProperties(workInProgress);
return null;
}
case SuspenseListComponent: {
Expand All @@ -995,6 +1167,7 @@ function completeWork(
if (renderState === null) {
// We're running in the default, "independent" mode.
// We don't do anything in this mode.
bubbleProperties(workInProgress);
return null;
}

Expand Down Expand Up @@ -1060,6 +1233,7 @@ function completeWork(
ForceSuspenseFallback,
),
);
// Don't bubble properties in this case.
return workInProgress.child;
}
row = row.sibling;
Expand Down Expand Up @@ -1117,6 +1291,7 @@ function completeWork(
!getIsHydrating() // We don't cut it if we're hydrating.
) {
// We're done.
bubbleProperties(workInProgress);
return null;
}
} else if (
Expand Down Expand Up @@ -1188,8 +1363,10 @@ function completeWork(
}
pushSuspenseContext(workInProgress, suspenseContext);
// Do a pass over the next row.
// Don't bubble properties in this case.
return next;
}
bubbleProperties(workInProgress);
return null;
}
case FundamentalComponent: {
Expand Down Expand Up @@ -1217,6 +1394,7 @@ function completeWork(
): any): Instance);
fundamentalInstance.instance = instance;
if (fundamentalImpl.reconcileChildren === false) {
bubbleProperties(workInProgress);
return null;
}
appendAllChildren(instance, workInProgress, false, false);
Expand All @@ -1239,6 +1417,7 @@ function completeWork(
markUpdate(workInProgress);
}
}
bubbleProperties(workInProgress);
return null;
}
break;
Expand All @@ -1261,31 +1440,44 @@ function completeWork(
markRef(workInProgress);
}
}
bubbleProperties(workInProgress);
return null;
}
break;
}
case Block:
if (enableBlocksAPI) {
bubbleProperties(workInProgress);
return null;
}
break;
case OffscreenComponent:
case LegacyHiddenComponent: {
popRenderLanes(workInProgress);
const nextState: OffscreenState | null = workInProgress.memoizedState;
const nextIsHidden = nextState !== null;

if (current !== null) {
const nextState: OffscreenState | null = workInProgress.memoizedState;
const prevState: OffscreenState | null = current.memoizedState;

const prevIsHidden = prevState !== null;
const nextIsHidden = nextState !== null;
if (
prevIsHidden !== nextIsHidden &&
newProps.mode !== 'unstable-defer-without-hiding'
) {
workInProgress.flags |= Update;
}
}

// Don't bubble properties for hidden children.
if (
!nextIsHidden ||
includesSomeLane(subtreeRenderLanes, (OffscreenLane: Lane)) ||
(workInProgress.mode & ConcurrentMode) === NoMode
) {
bubbleProperties(workInProgress);
}

return null;
}
}
Expand Down
Loading

0 comments on commit 16fb2b6

Please sign in to comment.