Skip to content

Commit e0160d5

Browse files
authored
add transition tracing transitions stack (#24321)
Added a transitions stack for to keep track of which transitions are still happening for the current boundary. * On the root, we will get all transitions that have been initiated for the corresponding lanes. * Whenever we encounter a suspended boundary, we will add all transitions on the stack onto the boundary * Whenever we encounter a boundary that just unsuspended, we will add all transitions on the boundary onto the stack A transition will be considered complete when there are no boundaries that have the associated transition
1 parent b0f13e5 commit e0160d5

8 files changed

+162
-88
lines changed

packages/react-reconciler/src/ReactFiberBeginWork.new.js

+10-7
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ function updateOffscreenComponent(
661661
// push the cache pool even though we're going to bail out
662662
// because otherwise there'd be a context mismatch
663663
if (current !== null) {
664-
pushTransition(workInProgress, null);
664+
pushTransition(workInProgress, null, null);
665665
}
666666
}
667667
pushRenderLanes(workInProgress, renderLanes);
@@ -695,7 +695,7 @@ function updateOffscreenComponent(
695695
// push the cache pool even though we're going to bail out
696696
// because otherwise there'd be a context mismatch
697697
if (current !== null) {
698-
pushTransition(workInProgress, null);
698+
pushTransition(workInProgress, null, null);
699699
}
700700
}
701701

@@ -733,7 +733,9 @@ function updateOffscreenComponent(
733733
// using the same cache. Unless the parent changed, since that means
734734
// there was a refresh.
735735
const prevCachePool = prevState !== null ? prevState.cachePool : null;
736-
pushTransition(workInProgress, prevCachePool);
736+
// TODO: Consider if and how Offscreen pre-rendering should
737+
// be attributed to the transition that spawned it
738+
pushTransition(workInProgress, prevCachePool, null);
737739
}
738740

739741
pushRenderLanes(workInProgress, subtreeRenderLanes);
@@ -751,7 +753,7 @@ function updateOffscreenComponent(
751753
// using the same cache. Unless the parent changed, since that means
752754
// there was a refresh.
753755
const prevCachePool = prevState.cachePool;
754-
pushTransition(workInProgress, prevCachePool);
756+
pushTransition(workInProgress, prevCachePool, null);
755757
}
756758

757759
// Since we're not hidden anymore, reset the state
@@ -767,7 +769,7 @@ function updateOffscreenComponent(
767769
// using the same cache. Unless the parent changed, since that means
768770
// there was a refresh.
769771
if (current !== null) {
770-
pushTransition(workInProgress, null);
772+
pushTransition(workInProgress, null, null);
771773
}
772774
}
773775
}
@@ -1330,10 +1332,10 @@ function updateHostRoot(current, workInProgress, renderLanes) {
13301332

13311333
const nextState: RootState = workInProgress.memoizedState;
13321334
const root: FiberRoot = workInProgress.stateNode;
1335+
pushRootTransition(workInProgress, root, renderLanes);
13331336

13341337
if (enableCache) {
13351338
const nextCache: Cache = nextState.cache;
1336-
pushRootTransition(root);
13371339
pushCacheProvider(workInProgress, nextCache);
13381340
if (nextCache !== prevState.cache) {
13391341
// The root cache refreshed.
@@ -3572,10 +3574,11 @@ function attemptEarlyBailoutIfNoScheduledUpdate(
35723574
case HostRoot:
35733575
pushHostRootContext(workInProgress);
35743576
const root: FiberRoot = workInProgress.stateNode;
3577+
pushRootTransition(workInProgress, root, renderLanes);
3578+
35753579
if (enableCache) {
35763580
const cache: Cache = current.memoizedState.cache;
35773581
pushCacheProvider(workInProgress, cache);
3578-
pushRootTransition(root);
35793582
}
35803583
if (enableTransitionTracing) {
35813584
workInProgress.memoizedState.transitions = getWorkInProgressTransitions();

packages/react-reconciler/src/ReactFiberBeginWork.old.js

+10-7
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ function updateOffscreenComponent(
661661
// push the cache pool even though we're going to bail out
662662
// because otherwise there'd be a context mismatch
663663
if (current !== null) {
664-
pushTransition(workInProgress, null);
664+
pushTransition(workInProgress, null, null);
665665
}
666666
}
667667
pushRenderLanes(workInProgress, renderLanes);
@@ -695,7 +695,7 @@ function updateOffscreenComponent(
695695
// push the cache pool even though we're going to bail out
696696
// because otherwise there'd be a context mismatch
697697
if (current !== null) {
698-
pushTransition(workInProgress, null);
698+
pushTransition(workInProgress, null, null);
699699
}
700700
}
701701

@@ -733,7 +733,9 @@ function updateOffscreenComponent(
733733
// using the same cache. Unless the parent changed, since that means
734734
// there was a refresh.
735735
const prevCachePool = prevState !== null ? prevState.cachePool : null;
736-
pushTransition(workInProgress, prevCachePool);
736+
// TODO: Consider if and how Offscreen pre-rendering should
737+
// be attributed to the transition that spawned it
738+
pushTransition(workInProgress, prevCachePool, null);
737739
}
738740

739741
pushRenderLanes(workInProgress, subtreeRenderLanes);
@@ -751,7 +753,7 @@ function updateOffscreenComponent(
751753
// using the same cache. Unless the parent changed, since that means
752754
// there was a refresh.
753755
const prevCachePool = prevState.cachePool;
754-
pushTransition(workInProgress, prevCachePool);
756+
pushTransition(workInProgress, prevCachePool, null);
755757
}
756758

757759
// Since we're not hidden anymore, reset the state
@@ -767,7 +769,7 @@ function updateOffscreenComponent(
767769
// using the same cache. Unless the parent changed, since that means
768770
// there was a refresh.
769771
if (current !== null) {
770-
pushTransition(workInProgress, null);
772+
pushTransition(workInProgress, null, null);
771773
}
772774
}
773775
}
@@ -1330,10 +1332,10 @@ function updateHostRoot(current, workInProgress, renderLanes) {
13301332

13311333
const nextState: RootState = workInProgress.memoizedState;
13321334
const root: FiberRoot = workInProgress.stateNode;
1335+
pushRootTransition(workInProgress, root, renderLanes);
13331336

13341337
if (enableCache) {
13351338
const nextCache: Cache = nextState.cache;
1336-
pushRootTransition(root);
13371339
pushCacheProvider(workInProgress, nextCache);
13381340
if (nextCache !== prevState.cache) {
13391341
// The root cache refreshed.
@@ -3572,10 +3574,11 @@ function attemptEarlyBailoutIfNoScheduledUpdate(
35723574
case HostRoot:
35733575
pushHostRootContext(workInProgress);
35743576
const root: FiberRoot = workInProgress.stateNode;
3577+
pushRootTransition(workInProgress, root, renderLanes);
3578+
35753579
if (enableCache) {
35763580
const cache: Cache = current.memoizedState.cache;
35773581
pushCacheProvider(workInProgress, cache);
3578-
pushRootTransition(root);
35793582
}
35803583
if (enableTransitionTracing) {
35813584
workInProgress.memoizedState.transitions = getWorkInProgressTransitions();

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

+3-5
Original file line numberDiff line numberDiff line change
@@ -875,8 +875,6 @@ function completeWork(
875875
}
876876

877877
if (enableCache) {
878-
popRootTransition(fiberRoot, renderLanes);
879-
880878
let previousCache: Cache | null = null;
881879
if (current !== null) {
882880
previousCache = current.memoizedState.cache;
@@ -888,6 +886,7 @@ function completeWork(
888886
}
889887
popCacheProvider(workInProgress, cache);
890888
}
889+
popRootTransition(workInProgress, fiberRoot, renderLanes);
891890
popHostContainer(workInProgress);
892891
popTopLevelLegacyContextObject(workInProgress);
893892
resetMutableSourceWorkInProgressVersions();
@@ -1593,11 +1592,10 @@ function completeWork(
15931592
// Run passive effects to retain/release the cache.
15941593
workInProgress.flags |= Passive;
15951594
}
1596-
if (current !== null) {
1597-
popTransition(workInProgress);
1598-
}
15991595
}
16001596

1597+
popTransition(workInProgress, current);
1598+
16011599
return null;
16021600
}
16031601
case CacheComponent: {

packages/react-reconciler/src/ReactFiberCompleteWork.old.js

+3-5
Original file line numberDiff line numberDiff line change
@@ -875,8 +875,6 @@ function completeWork(
875875
}
876876

877877
if (enableCache) {
878-
popRootTransition(fiberRoot, renderLanes);
879-
880878
let previousCache: Cache | null = null;
881879
if (current !== null) {
882880
previousCache = current.memoizedState.cache;
@@ -888,6 +886,7 @@ function completeWork(
888886
}
889887
popCacheProvider(workInProgress, cache);
890888
}
889+
popRootTransition(workInProgress, fiberRoot, renderLanes);
891890
popHostContainer(workInProgress);
892891
popTopLevelLegacyContextObject(workInProgress);
893892
resetMutableSourceWorkInProgressVersions();
@@ -1593,11 +1592,10 @@ function completeWork(
15931592
// Run passive effects to retain/release the cache.
15941593
workInProgress.flags |= Passive;
15951594
}
1596-
if (current !== null) {
1597-
popTransition(workInProgress);
1598-
}
15991595
}
16001596

1597+
popTransition(workInProgress, current);
1598+
16011599
return null;
16021600
}
16031601
case CacheComponent: {

packages/react-reconciler/src/ReactFiberTransition.new.js

+62-15
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ import type {FiberRoot} from './ReactInternalTypes';
1010
import type {Lanes} from './ReactFiberLane.new';
1111
import type {StackCursor} from './ReactFiberStack.new';
1212
import type {Cache, SpawnedCachePool} from './ReactFiberCacheComponent.new';
13+
import type {Transition} from './ReactFiberTracingMarkerComponent.new';
1314

14-
import {enableCache} from 'shared/ReactFeatureFlags';
15+
import {enableCache, enableTransitionTracing} from 'shared/ReactFeatureFlags';
1516
import {isPrimaryRenderer} from './ReactFiberHostConfig';
1617
import {createCursor, push, pop} from './ReactFiberStack.new';
17-
import {getWorkInProgressRoot} from './ReactFiberWorkLoop.new';
18+
import {
19+
getWorkInProgressRoot,
20+
getWorkInProgressTransitions,
21+
} from './ReactFiberWorkLoop.new';
1822
import {
1923
createCache,
2024
retainCache,
@@ -25,6 +29,15 @@ import {
2529
// used during the previous render by placing it here, on the stack.
2630
const resumedCache: StackCursor<Cache | null> = createCursor(null);
2731

32+
// During the render/synchronous commit phase, we don't actually process the
33+
// transitions. Therefore, we want to lazily combine transitions. Instead of
34+
// comparing the arrays of transitions when we combine them and storing them
35+
// and filtering out the duplicates, we will instead store the unprocessed transitions
36+
// in an array and actually filter them in the passive phase.
37+
const transitionStack: StackCursor<Array<Transition> | null> = createCursor(
38+
null,
39+
);
40+
2841
function peekCacheFromPool(): Cache | null {
2942
if (!enableCache) {
3043
return (null: any);
@@ -75,25 +88,31 @@ export function requestCacheFromPool(renderLanes: Lanes): Cache {
7588
return freshCache;
7689
}
7790

78-
export function pushRootTransition(root: FiberRoot) {
79-
if (enableCache) {
80-
return;
91+
export function pushRootTransition(
92+
workInProgress: Fiber,
93+
root: FiberRoot,
94+
renderLanes: Lanes,
95+
) {
96+
if (enableTransitionTracing) {
97+
const rootTransitions = getWorkInProgressTransitions();
98+
push(transitionStack, rootTransitions, workInProgress);
8199
}
82-
// Note: This function currently does nothing but I'll leave it here for
83-
// code organization purposes in case that changes.
84100
}
85101

86-
export function popRootTransition(root: FiberRoot, renderLanes: Lanes) {
87-
if (enableCache) {
88-
return;
102+
export function popRootTransition(
103+
workInProgress: Fiber,
104+
root: FiberRoot,
105+
renderLanes: Lanes,
106+
) {
107+
if (enableTransitionTracing) {
108+
pop(transitionStack, workInProgress);
89109
}
90-
// Note: This function currently does nothing but I'll leave it here for
91-
// code organization purposes in case that changes.
92110
}
93111

94112
export function pushTransition(
95113
offscreenWorkInProgress: Fiber,
96114
prevCachePool: SpawnedCachePool | null,
115+
newTransitions: Array<Transition> | null,
97116
): void {
98117
if (enableCache) {
99118
if (prevCachePool === null) {
@@ -102,12 +121,40 @@ export function pushTransition(
102121
push(resumedCache, prevCachePool.pool, offscreenWorkInProgress);
103122
}
104123
}
124+
125+
if (enableTransitionTracing) {
126+
if (transitionStack.current === null) {
127+
push(transitionStack, newTransitions, offscreenWorkInProgress);
128+
} else if (newTransitions === null) {
129+
push(transitionStack, transitionStack.current, offscreenWorkInProgress);
130+
} else {
131+
push(
132+
transitionStack,
133+
transitionStack.current.concat(newTransitions),
134+
offscreenWorkInProgress,
135+
);
136+
}
137+
}
105138
}
106139

107-
export function popTransition(workInProgress: Fiber) {
108-
if (enableCache) {
109-
pop(resumedCache, workInProgress);
140+
export function popTransition(workInProgress: Fiber, current: Fiber | null) {
141+
if (current !== null) {
142+
if (enableCache) {
143+
pop(resumedCache, workInProgress);
144+
}
145+
146+
if (enableTransitionTracing) {
147+
pop(transitionStack, workInProgress);
148+
}
149+
}
150+
}
151+
152+
export function getSuspendedTransitions(): Array<Transition> | null {
153+
if (!enableTransitionTracing) {
154+
return null;
110155
}
156+
157+
return transitionStack.current;
111158
}
112159

113160
export function getSuspendedCache(): SpawnedCachePool | null {

0 commit comments

Comments
 (0)