@samitouri / QOS-React-2 / commits / 401296310f

[Transition Tracing] Refactor Transition Tracing Root Code (#24766)

This PR refactors the transition tracing root code by reusing the tracing marker code. Namely it: * Refactors the tracing marker code so that it takes a tracing marker instance instead of a tracing marker fiber and rename the stack to `markerInstance` instead of `tracingMarker` * Pushes the root code onto the stack * Moves the instantiation of `root.incompleteTransitions` to the begin phase when we are pushing the root to the stack rather than in the commit phase

Luna Ruan committed Jun 30, 2022 at 11:16 UTC 401296310fbc6a9e769936eda6a6d0269e9c84d0
14 files changed +309 -179
packages/react-reconciler/src/ReactFiberBeginWork.new.js
+28 -9
@@ -27,6 +27,7 @@ import type {
27 OffscreenProps,
28 OffscreenState,
29 OffscreenQueue,
30 + OffscreenInstance,
31 } from './ReactFiberOffscreenComponent';
32 import type {
33 Cache,
@@ -262,8 +263,9 @@ import {
263 getPendingTransitions,
264 } from './ReactFiberTransition.new';
265 import {
265 - getTracingMarkers,
266 - pushTracingMarker,
266 + getMarkerInstances,
267 + pushMarkerInstance,
268 + pushRootMarkerInstance,
269 } from './ReactFiberTracingMarkerComponent.new';
270
271 const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
@@ -779,7 +781,10 @@ function updateOffscreenComponent(
781 if (enableTransitionTracing) {
782 // We have now gone from hidden to visible, so any transitions should
783 // be added to the stack to get added to any Offscreen/suspense children
782 - transitions = workInProgress.stateNode.transitions;
784 + const instance: OffscreenInstance | null = workInProgress.stateNode;
785 + if (instance !== null && instance.transitions != null) {
786 + transitions = Array.from(instance.transitions);
787 + }
788 }
789
790 pushTransition(workInProgress, prevCachePool, transitions);
@@ -909,7 +914,10 @@ function updateTracingMarkerComponent(
914 }
915 }
916
912 - pushTracingMarker(workInProgress);
917 + const instance: TracingMarkerInstance | null = workInProgress.stateNode;
918 + if (instance !== null) {
919 + pushMarkerInstance(workInProgress, instance);
920 + }
921 const nextChildren = workInProgress.pendingProps.children;
922 reconcileChildren(current, workInProgress, nextChildren, renderLanes);
923 return workInProgress.child;
@@ -1313,6 +1321,10 @@ function updateHostRoot(current, workInProgress, renderLanes) {
1321 const root: FiberRoot = workInProgress.stateNode;
1322 pushRootTransition(workInProgress, root, renderLanes);
1323
1324 + if (enableTransitionTracing) {
1325 + pushRootMarkerInstance(workInProgress);
1326 + }
1327 +
1328 if (enableCache) {
1329 const nextCache: Cache = nextState.cache;
1330 pushCacheProvider(workInProgress, nextCache);
@@ -2098,10 +2110,10 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
2110 const currentTransitions = getPendingTransitions();
2111 if (currentTransitions !== null) {
2112 // If there are no transitions, we don't need to keep track of tracing markers
2101 - const currentTracingMarkers = getTracingMarkers();
2113 + const parentMarkerInstances = getMarkerInstances();
2114 const primaryChildUpdateQueue: OffscreenQueue = {
2115 transitions: currentTransitions,
2104 - tracingMarkers: currentTracingMarkers,
2116 + markerInstances: parentMarkerInstances,
2117 };
2118 primaryChildFragment.updateQueue = primaryChildUpdateQueue;
2119 }
@@ -2188,10 +2200,10 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
2200 if (enableTransitionTracing) {
2201 const currentTransitions = getPendingTransitions();
2202 if (currentTransitions !== null) {
2191 - const currentTracingMarkers = getTracingMarkers();
2203 + const parentMarkerInstances = getMarkerInstances();
2204 const primaryChildUpdateQueue: OffscreenQueue = {
2205 transitions: currentTransitions,
2194 - tracingMarkers: currentTracingMarkers,
2206 + markerInstances: parentMarkerInstances,
2207 };
2208 primaryChildFragment.updateQueue = primaryChildUpdateQueue;
2209 }
@@ -3509,6 +3521,10 @@ function attemptEarlyBailoutIfNoScheduledUpdate(
3521 const root: FiberRoot = workInProgress.stateNode;
3522 pushRootTransition(workInProgress, root, renderLanes);
3523
3524 + if (enableTransitionTracing) {
3525 + pushRootMarkerInstance(workInProgress);
3526 + }
3527 +
3528 if (enableCache) {
3529 const cache: Cache = current.memoizedState.cache;
3530 pushCacheProvider(workInProgress, cache);
@@ -3694,7 +3710,10 @@ function attemptEarlyBailoutIfNoScheduledUpdate(
3710 }
3711 case TracingMarkerComponent: {
3712 if (enableTransitionTracing) {
3697 - pushTracingMarker(workInProgress);
3713 + const instance: TracingMarkerInstance | null = workInProgress.stateNode;
3714 + if (instance !== null) {
3715 + pushMarkerInstance(workInProgress, instance);
3716 + }
3717 }
3718 }
3719 }
packages/react-reconciler/src/ReactFiberBeginWork.old.js
+28 -9
@@ -27,6 +27,7 @@ import type {
27 OffscreenProps,
28 OffscreenState,
29 OffscreenQueue,
30 + OffscreenInstance,
31 } from './ReactFiberOffscreenComponent';
32 import type {
33 Cache,
@@ -259,8 +260,9 @@ import {
260 getPendingTransitions,
261 } from './ReactFiberTransition.old';
262 import {
262 - getTracingMarkers,
263 - pushTracingMarker,
263 + getMarkerInstances,
264 + pushMarkerInstance,
265 + pushRootMarkerInstance,
266 } from './ReactFiberTracingMarkerComponent.old';
267
268 const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
@@ -784,7 +786,10 @@ function updateOffscreenComponent(
786 if (enableTransitionTracing) {
787 // We have now gone from hidden to visible, so any transitions should
788 // be added to the stack to get added to any Offscreen/suspense children
787 - transitions = workInProgress.stateNode.transitions;
789 + const instance: OffscreenInstance | null = workInProgress.stateNode;
790 + if (instance !== null && instance.transitions != null) {
791 + transitions = Array.from(instance.transitions);
792 + }
793 }
794
795 pushTransition(workInProgress, prevCachePool, transitions);
@@ -909,7 +914,10 @@ function updateTracingMarkerComponent(
914 }
915 }
916
912 - pushTracingMarker(workInProgress);
917 + const instance: TracingMarkerInstance | null = workInProgress.stateNode;
918 + if (instance !== null) {
919 + pushMarkerInstance(workInProgress, instance);
920 + }
921 const nextChildren = workInProgress.pendingProps.children;
922 reconcileChildren(current, workInProgress, nextChildren, renderLanes);
923 return workInProgress.child;
@@ -1313,6 +1321,10 @@ function updateHostRoot(current, workInProgress, renderLanes) {
1321 const root: FiberRoot = workInProgress.stateNode;
1322 pushRootTransition(workInProgress, root, renderLanes);
1323
1324 + if (enableTransitionTracing) {
1325 + pushRootMarkerInstance(workInProgress);
1326 + }
1327 +
1328 if (enableCache) {
1329 const nextCache: Cache = nextState.cache;
1330 pushCacheProvider(workInProgress, nextCache);
@@ -2114,10 +2126,10 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
2126 const currentTransitions = getPendingTransitions();
2127 if (currentTransitions !== null) {
2128 // If there are no transitions, we don't need to keep track of tracing markers
2117 - const currentTracingMarkers = getTracingMarkers();
2129 + const parentMarkerInstances = getMarkerInstances();
2130 const primaryChildUpdateQueue: OffscreenQueue = {
2131 transitions: currentTransitions,
2120 - tracingMarkers: currentTracingMarkers,
2132 + markerInstances: parentMarkerInstances,
2133 };
2134 primaryChildFragment.updateQueue = primaryChildUpdateQueue;
2135 }
@@ -2200,10 +2212,10 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
2212 if (enableTransitionTracing) {
2213 const currentTransitions = getPendingTransitions();
2214 if (currentTransitions !== null) {
2203 - const currentTracingMarkers = getTracingMarkers();
2215 + const parentMarkerInstances = getMarkerInstances();
2216 const primaryChildUpdateQueue: OffscreenQueue = {
2217 transitions: currentTransitions,
2206 - tracingMarkers: currentTracingMarkers,
2218 + markerInstances: parentMarkerInstances,
2219 };
2220 primaryChildFragment.updateQueue = primaryChildUpdateQueue;
2221 }
@@ -3510,6 +3522,10 @@ function attemptEarlyBailoutIfNoScheduledUpdate(
3522 const root: FiberRoot = workInProgress.stateNode;
3523 pushRootTransition(workInProgress, root, renderLanes);
3524
3525 + if (enableTransitionTracing) {
3526 + pushRootMarkerInstance(workInProgress);
3527 + }
3528 +
3529 if (enableCache) {
3530 const cache: Cache = current.memoizedState.cache;
3531 pushCacheProvider(workInProgress, cache);
@@ -3702,7 +3718,10 @@ function attemptEarlyBailoutIfNoScheduledUpdate(
3718 }
3719 case TracingMarkerComponent: {
3720 if (enableTransitionTracing) {
3705 - pushTracingMarker(workInProgress);
3721 + const instance: TracingMarkerInstance | null = workInProgress.stateNode;
3722 + if (instance !== null) {
3723 + pushMarkerInstance(workInProgress, instance);
3724 + }
3725 }
3726 }
3727 }
packages/react-reconciler/src/ReactFiberCommitWork.new.js
+30 -63
@@ -2811,47 +2811,35 @@ function commitPassiveMountOnFiber(
2811 // Get the transitions that were initiatized during the render
2812 // and add a start transition callback for each of them
2813 const root = finishedWork.stateNode;
2814 - let incompleteTransitions = root.incompleteTransitions;
2814 + const incompleteTransitions = root.incompleteTransitions;
2815 // Initial render
2816 if (committedTransitions !== null) {
2817 - if (incompleteTransitions === null) {
2818 - root.incompleteTransitions = incompleteTransitions = new Map();
2819 - }
2820 -
2817 committedTransitions.forEach(transition => {
2818 addTransitionStartCallbackToPendingTransition({
2819 transitionName: transition.name,
2820 startTime: transition.startTime,
2821 });
2826 -
2827 - if (!incompleteTransitions.has(transition)) {
2828 - incompleteTransitions.set(transition, null);
2829 - }
2822 });
2823
2824 clearTransitionsForLanes(finishedRoot, committedLanes);
2825 }
2826
2835 - if (incompleteTransitions !== null) {
2836 - incompleteTransitions.forEach((pendingBoundaries, transition) => {
2837 - if (pendingBoundaries === null || pendingBoundaries.size === 0) {
2827 + incompleteTransitions.forEach(
2828 + ({pendingSuspenseBoundaries}, transition) => {
2829 + if (
2830 + pendingSuspenseBoundaries === null ||
2831 + pendingSuspenseBoundaries.size === 0
2832 + ) {
2833 addTransitionCompleteCallbackToPendingTransition({
2834 transitionName: transition.name,
2835 startTime: transition.startTime,
2836 });
2837 incompleteTransitions.delete(transition);
2838 }
2844 - });
2845 - }
2839 + },
2840 + );
2841
2847 - // If there are no more pending suspense boundaries we
2848 - // clear the transitions because they are all complete.
2849 - if (
2850 - incompleteTransitions === null ||
2851 - incompleteTransitions.size === 0
2852 - ) {
2853 - root.incompleteTransitions = null;
2854 - }
2842 + clearTransitionsForLanes(finishedRoot, committedLanes);
2843 }
2844 break;
2845 }
@@ -2896,14 +2884,6 @@ function commitPassiveMountOnFiber(
2884 if (isFallback) {
2885 const transitions = queue.transitions;
2886 let prevTransitions = instance.transitions;
2899 - let rootIncompleteTransitions = finishedRoot.incompleteTransitions;
2900 -
2901 - // We lazily instantiate transition tracing relevant maps
2902 - // and sets in the commit phase as we need to use them. We only
2903 - // instantiate them in the fallback phase on an as needed basis
2904 - if (rootIncompleteTransitions === null) {
2905 - finishedRoot.incompleteTransitions = rootIncompleteTransitions = new Map();
2906 - }
2887 if (instance.pendingMarkers === null) {
2888 instance.pendingMarkers = new Set();
2889 }
@@ -2911,56 +2891,43 @@ function commitPassiveMountOnFiber(
2891 instance.transitions = prevTransitions = new Set();
2892 }
2893
2914 - // TODO(luna): Combine the root code with the tracing marker code
2894 if (transitions !== null) {
2895 transitions.forEach(transition => {
2896 // Add all the transitions saved in the update queue during
2897 // the render phase (ie the transitions associated with this boundary)
2898 // into the transitions set.
2899 prevTransitions.add(transition);
2921 -
2922 - // Add the root transition's pending suspense boundary set to
2923 - // the queue's marker set. We will iterate through the marker
2924 - // set when we toggle state on the suspense boundary and
2925 - // add or remove the pending suspense boundaries as needed.
2926 - if (rootIncompleteTransitions !== null) {
2927 - if (!rootIncompleteTransitions.has(transition)) {
2928 - rootIncompleteTransitions.set(transition, new Map());
2929 - }
2930 - instance.pendingMarkers.add(
2931 - rootIncompleteTransitions.get(transition),
2932 - );
2933 - }
2900 });
2901 }
2902
2937 - const tracingMarkers = queue.tracingMarkers;
2938 - if (tracingMarkers !== null) {
2939 - tracingMarkers.forEach(marker => {
2940 - const markerInstance = marker.stateNode;
2903 + const markerInstances = queue.markerInstances;
2904 + if (markerInstances !== null) {
2905 + markerInstances.forEach(markerInstance => {
2906 + if (markerInstance.pendingSuspenseBoundaries === null) {
2907 + markerInstance.pendingSuspenseBoundaries = new Map();
2908 + }
2909 +
2910 + const markerTransitions = markerInstance.transitions;
2911 // There should only be a few tracing marker transitions because
2912 // they should be only associated with the transition that
2913 // caused them
2944 - markerInstance.transitions.forEach(transition => {
2945 - if (instance.transitions.has(transition)) {
2946 - instance.pendingMarkers.add(
2947 - markerInstance.pendingSuspenseBoundaries,
2948 - );
2949 - }
2950 - });
2914 + if (markerTransitions !== null) {
2915 + markerTransitions.forEach(transition => {
2916 + if (instance.transitions.has(transition)) {
2917 + instance.pendingMarkers.add(
2918 + markerInstance.pendingSuspenseBoundaries,
2919 + );
2920 + }
2921 + });
2922 + }
2923 });
2924 }
2925 }
2926
2955 - commitTransitionProgress(finishedWork);
2956 -
2957 - if (
2958 - instance.pendingMarkers === null ||
2959 - instance.pendingMarkers.size === 0
2960 - ) {
2961 - finishedWork.updateQueue = null;
2962 - }
2927 + finishedWork.updateQueue = null;
2928 }
2929 +
2930 + commitTransitionProgress(finishedWork);
2931 }
2932
2933 break;
packages/react-reconciler/src/ReactFiberCommitWork.old.js
+30 -63
@@ -2811,47 +2811,35 @@ function commitPassiveMountOnFiber(
2811 // Get the transitions that were initiatized during the render
2812 // and add a start transition callback for each of them
2813 const root = finishedWork.stateNode;
2814 - let incompleteTransitions = root.incompleteTransitions;
2814 + const incompleteTransitions = root.incompleteTransitions;
2815 // Initial render
2816 if (committedTransitions !== null) {
2817 - if (incompleteTransitions === null) {
2818 - root.incompleteTransitions = incompleteTransitions = new Map();
2819 - }
2820 -
2817 committedTransitions.forEach(transition => {
2818 addTransitionStartCallbackToPendingTransition({
2819 transitionName: transition.name,
2820 startTime: transition.startTime,
2821 });
2826 -
2827 - if (!incompleteTransitions.has(transition)) {
2828 - incompleteTransitions.set(transition, null);
2829 - }
2822 });
2823
2824 clearTransitionsForLanes(finishedRoot, committedLanes);
2825 }
2826
2835 - if (incompleteTransitions !== null) {
2836 - incompleteTransitions.forEach((pendingBoundaries, transition) => {
2837 - if (pendingBoundaries === null || pendingBoundaries.size === 0) {
2827 + incompleteTransitions.forEach(
2828 + ({pendingSuspenseBoundaries}, transition) => {
2829 + if (
2830 + pendingSuspenseBoundaries === null ||
2831 + pendingSuspenseBoundaries.size === 0
2832 + ) {
2833 addTransitionCompleteCallbackToPendingTransition({
2834 transitionName: transition.name,
2835 startTime: transition.startTime,
2836 });
2837 incompleteTransitions.delete(transition);
2838 }
2844 - });
2845 - }
2839 + },
2840 + );
2841
2847 - // If there are no more pending suspense boundaries we
2848 - // clear the transitions because they are all complete.
2849 - if (
2850 - incompleteTransitions === null ||
2851 - incompleteTransitions.size === 0
2852 - ) {
2853 - root.incompleteTransitions = null;
2854 - }
2842 + clearTransitionsForLanes(finishedRoot, committedLanes);
2843 }
2844 break;
2845 }
@@ -2896,14 +2884,6 @@ function commitPassiveMountOnFiber(
2884 if (isFallback) {
2885 const transitions = queue.transitions;
2886 let prevTransitions = instance.transitions;
2899 - let rootIncompleteTransitions = finishedRoot.incompleteTransitions;
2900 -
2901 - // We lazily instantiate transition tracing relevant maps
2902 - // and sets in the commit phase as we need to use them. We only
2903 - // instantiate them in the fallback phase on an as needed basis
2904 - if (rootIncompleteTransitions === null) {
2905 - finishedRoot.incompleteTransitions = rootIncompleteTransitions = new Map();
2906 - }
2887 if (instance.pendingMarkers === null) {
2888 instance.pendingMarkers = new Set();
2889 }
@@ -2911,56 +2891,43 @@ function commitPassiveMountOnFiber(
2891 instance.transitions = prevTransitions = new Set();
2892 }
2893
2914 - // TODO(luna): Combine the root code with the tracing marker code
2894 if (transitions !== null) {
2895 transitions.forEach(transition => {
2896 // Add all the transitions saved in the update queue during
2897 // the render phase (ie the transitions associated with this boundary)
2898 // into the transitions set.
2899 prevTransitions.add(transition);
2921 -
2922 - // Add the root transition's pending suspense boundary set to
2923 - // the queue's marker set. We will iterate through the marker
2924 - // set when we toggle state on the suspense boundary and
2925 - // add or remove the pending suspense boundaries as needed.
2926 - if (rootIncompleteTransitions !== null) {
2927 - if (!rootIncompleteTransitions.has(transition)) {
2928 - rootIncompleteTransitions.set(transition, new Map());
2929 - }
2930 - instance.pendingMarkers.add(
2931 - rootIncompleteTransitions.get(transition),
2932 - );
2933 - }
2900 });
2901 }
2902
2937 - const tracingMarkers = queue.tracingMarkers;
2938 - if (tracingMarkers !== null) {
2939 - tracingMarkers.forEach(marker => {
2940 - const markerInstance = marker.stateNode;
2903 + const markerInstances = queue.markerInstances;
2904 + if (markerInstances !== null) {
2905 + markerInstances.forEach(markerInstance => {
2906 + if (markerInstance.pendingSuspenseBoundaries === null) {
2907 + markerInstance.pendingSuspenseBoundaries = new Map();
2908 + }
2909 +
2910 + const markerTransitions = markerInstance.transitions;
2911 // There should only be a few tracing marker transitions because
2912 // they should be only associated with the transition that
2913 // caused them
2944 - markerInstance.transitions.forEach(transition => {
2945 - if (instance.transitions.has(transition)) {
2946 - instance.pendingMarkers.add(
2947 - markerInstance.pendingSuspenseBoundaries,
2948 - );
2949 - }
2950 - });
2914 + if (markerTransitions !== null) {
2915 + markerTransitions.forEach(transition => {
2916 + if (instance.transitions.has(transition)) {
2917 + instance.pendingMarkers.add(
2918 + markerInstance.pendingSuspenseBoundaries,
2919 + );
2920 + }
2921 + });
2922 + }
2923 });
2924 }
2925 }
2926
2955 - commitTransitionProgress(finishedWork);
2956 -
2957 - if (
2958 - instance.pendingMarkers === null ||
2959 - instance.pendingMarkers.size === 0
2960 - ) {
2961 - finishedWork.updateQueue = null;
2962 - }
2927 + finishedWork.updateQueue = null;
2928 }
2929 +
2930 + commitTransitionProgress(finishedWork);
2931 }
2932
2933 break;
packages/react-reconciler/src/ReactFiberCompleteWork.new.js
+14 -2
@@ -28,6 +28,7 @@ import type {
28 SuspenseListRenderState,
29 } from './ReactFiberSuspenseComponent.new';
30 import type {OffscreenState} from './ReactFiberOffscreenComponent';
31 +import type {TracingMarkerInstance} from './ReactFiberTracingMarkerComponent.new';
32 import type {Cache} from './ReactFiberCacheComponent.new';
33 import {
34 enableSuspenseAvoidThisFallback,
@@ -164,7 +165,10 @@ import {transferActualDuration} from './ReactProfilerTimer.new';
165 import {popCacheProvider} from './ReactFiberCacheComponent.new';
166 import {popTreeContext} from './ReactFiberTreeContext.new';
167 import {popRootTransition, popTransition} from './ReactFiberTransition.new';
167 -import {popTracingMarker} from './ReactFiberTracingMarkerComponent.new';
168 +import {
169 + popMarkerInstance,
170 + popRootMarkerInstance,
171 +} from './ReactFiberTracingMarkerComponent.new';
172
173 function markUpdate(workInProgress: Fiber) {
174 // Tag the fiber with an update effect. This turns a Placement into
@@ -900,6 +904,11 @@ function completeWork(
904 }
905 popCacheProvider(workInProgress, cache);
906 }
907 +
908 + if (enableTransitionTracing) {
909 + popRootMarkerInstance(workInProgress);
910 + }
911 +
912 popRootTransition(workInProgress, fiberRoot, renderLanes);
913 popHostContainer(workInProgress);
914 popTopLevelLegacyContextObject(workInProgress);
@@ -1579,7 +1588,10 @@ function completeWork(
1588 }
1589 case TracingMarkerComponent: {
1590 if (enableTransitionTracing) {
1582 - popTracingMarker(workInProgress);
1591 + const instance: TracingMarkerInstance | null = workInProgress.stateNode;
1592 + if (instance !== null) {
1593 + popMarkerInstance(workInProgress);
1594 + }
1595 bubbleProperties(workInProgress);
1596
1597 if (
packages/react-reconciler/src/ReactFiberCompleteWork.old.js
+14 -2
@@ -29,6 +29,7 @@ import type {
29 } from './ReactFiberSuspenseComponent.old';
30 import type {SuspenseContext} from './ReactFiberSuspenseContext.old';
31 import type {OffscreenState} from './ReactFiberOffscreenComponent';
32 +import type {TracingMarkerInstance} from './ReactFiberTracingMarkerComponent.old';
33 import type {Cache} from './ReactFiberCacheComponent.old';
34 import {
35 enableSuspenseAvoidThisFallback,
@@ -164,7 +165,10 @@ import {transferActualDuration} from './ReactProfilerTimer.old';
165 import {popCacheProvider} from './ReactFiberCacheComponent.old';
166 import {popTreeContext} from './ReactFiberTreeContext.old';
167 import {popRootTransition, popTransition} from './ReactFiberTransition.old';
167 -import {popTracingMarker} from './ReactFiberTracingMarkerComponent.old';
168 +import {
169 + popMarkerInstance,
170 + popRootMarkerInstance,
171 +} from './ReactFiberTracingMarkerComponent.old';
172
173 function markUpdate(workInProgress: Fiber) {
174 // Tag the fiber with an update effect. This turns a Placement into
@@ -900,6 +904,11 @@ function completeWork(
904 }
905 popCacheProvider(workInProgress, cache);
906 }
907 +
908 + if (enableTransitionTracing) {
909 + popRootMarkerInstance(workInProgress);
910 + }
911 +
912 popRootTransition(workInProgress, fiberRoot, renderLanes);
913 popHostContainer(workInProgress);
914 popTopLevelLegacyContextObject(workInProgress);
@@ -1579,7 +1588,10 @@ function completeWork(
1588 }
1589 case TracingMarkerComponent: {
1590 if (enableTransitionTracing) {
1582 - popTracingMarker(workInProgress);
1591 + const instance: TracingMarkerInstance | null = workInProgress.stateNode;
1592 + if (instance !== null) {
1593 + popMarkerInstance(workInProgress);
1594 + }
1595 bubbleProperties(workInProgress);
1596
1597 if (
packages/react-reconciler/src/ReactFiberOffscreenComponent.js
+2 -2
@@ -8,12 +8,12 @@
8 */
9
10 import type {ReactNodeList, OffscreenMode} from 'shared/ReactTypes';
11 -import type {Fiber} from './ReactInternalTypes';
11 import type {Lanes} from './ReactFiberLane.old';
12 import type {SpawnedCachePool} from './ReactFiberCacheComponent.new';
13 import type {
14 Transition,
15 PendingSuspenseBoundaries,
16 + TracingMarkerInstance,
17 } from './ReactFiberTracingMarkerComponent.new';
18
19 export type OffscreenProps = {|
@@ -39,7 +39,7 @@ export type OffscreenState = {|
39
40 export type OffscreenQueue = {|
41 transitions: Array<Transition> | null,
42 - tracingMarkers: Array<Fiber> | null,
42 + markerInstances: Array<TracingMarkerInstance> | null,
43 |} | null;
44
45 export type OffscreenInstance = {|
packages/react-reconciler/src/ReactFiberRoot.new.js
+1 -1
@@ -92,13 +92,13 @@ function FiberRootNode(
92 this.hydrationCallbacks = null;
93 }
94
95 + this.incompleteTransitions = new Map();
96 if (enableTransitionTracing) {
97 this.transitionCallbacks = null;
98 const transitionLanesMap = (this.transitionLanes = []);
99 for (let i = 0; i < TotalLanes; i++) {
100 transitionLanesMap.push(null);
101 }
101 - this.incompleteTransitions = null;
102 }
103
104 if (enableProfilerTimer && enableProfilerCommitHooks) {
packages/react-reconciler/src/ReactFiberRoot.old.js
+1 -1
@@ -92,13 +92,13 @@ function FiberRootNode(
92 this.hydrationCallbacks = null;
93 }
94
95 + this.incompleteTransitions = new Map();
96 if (enableTransitionTracing) {
97 this.transitionCallbacks = null;
98 const transitionLanesMap = (this.transitionLanes = []);
99 for (let i = 0; i < TotalLanes; i++) {
100 transitionLanesMap.push(null);
101 }
101 - this.incompleteTransitions = null;
102 }
103
104 if (enableProfilerTimer && enableProfilerCommitHooks) {
packages/react-reconciler/src/ReactFiberTracingMarkerComponent.new.js
+57 -10
@@ -13,6 +13,7 @@ import type {StackCursor} from './ReactFiberStack.new';
13
14 import {enableTransitionTracing} from 'shared/ReactFeatureFlags';
15 import {createCursor, push, pop} from './ReactFiberStack.new';
16 +import {getWorkInProgressTransitions} from './ReactFiberWorkLoop.new';
17
18 export type SuspenseInfo = {name: string | null};
19
@@ -100,31 +101,77 @@ export function processTransitionCallbacks(
101 // tracing marker can be logged as complete
102 // This code lives separate from the ReactFiberTransition code because
103 // we push and pop on the tracing marker, not the suspense boundary
103 -const tracingMarkerStack: StackCursor<Array<Fiber> | null> = createCursor(null);
104 +const markerInstanceStack: StackCursor<Array<TracingMarkerInstance> | null> = createCursor(
105 + null,
106 +);
107
105 -export function pushTracingMarker(workInProgress: Fiber): void {
108 +export function pushRootMarkerInstance(workInProgress: Fiber): void {
109 if (enableTransitionTracing) {
107 - if (tracingMarkerStack.current === null) {
108 - push(tracingMarkerStack, [workInProgress], workInProgress);
110 + // On the root, every transition gets mapped to it's own map of
111 + // suspense boundaries. The transition is marked as complete when
112 + // the suspense boundaries map is empty. We do this because every
113 + // transition completes at different times and depends on different
114 + // suspense boundaries to complete. We store all the transitions
115 + // along with its map of suspense boundaries in the root incomplete
116 + // transitions map. Each entry in this map functions like a tracing
117 + // marker does, so we can push it onto the marker instance stack
118 + const transitions = getWorkInProgressTransitions();
119 + const root = workInProgress.stateNode;
120 +
121 + if (transitions !== null) {
122 + transitions.forEach(transition => {
123 + if (!root.incompleteTransitions.has(transition)) {
124 + root.incompleteTransitions.set(transition, {
125 + transitions: new Set([transition]),
126 + pendingSuspenseBoundaries: null,
127 + });
128 + }
129 + });
130 + }
131 +
132 + const markerInstances = [];
133 + // For ever transition on the suspense boundary, we push the transition
134 + // along with its map of pending suspense boundaries onto the marker
135 + // instance stack.
136 + root.incompleteTransitions.forEach(markerInstance => {
137 + markerInstances.push(markerInstance);
138 + });
139 + push(markerInstanceStack, markerInstances, workInProgress);
140 + }
141 +}
142 +
143 +export function popRootMarkerInstance(workInProgress: Fiber) {
144 + if (enableTransitionTracing) {
145 + pop(markerInstanceStack, workInProgress);
146 + }
147 +}
148 +
149 +export function pushMarkerInstance(
150 + workInProgress: Fiber,
151 + markerInstance: TracingMarkerInstance,
152 +): void {
153 + if (enableTransitionTracing) {
154 + if (markerInstanceStack.current === null) {
155 + push(markerInstanceStack, [markerInstance], workInProgress);
156 } else {
157 push(
111 - tracingMarkerStack,
112 - tracingMarkerStack.current.concat(workInProgress),
158 + markerInstanceStack,
159 + markerInstanceStack.current.concat(markerInstance),
160 workInProgress,
161 );
162 }
163 }
164 }
165
119 -export function popTracingMarker(workInProgress: Fiber): void {
166 +export function popMarkerInstance(workInProgress: Fiber): void {
167 if (enableTransitionTracing) {
121 - pop(tracingMarkerStack, workInProgress);
168 + pop(markerInstanceStack, workInProgress);
169 }
170 }
171
125 -export function getTracingMarkers(): Array<Fiber> | null {
172 +export function getMarkerInstances(): Array<TracingMarkerInstance> | null {
173 if (enableTransitionTracing) {
127 - return tracingMarkerStack.current;
174 + return markerInstanceStack.current;
175 }
176 return null;
177 }
packages/react-reconciler/src/ReactFiberTracingMarkerComponent.old.js
+57 -10
@@ -13,6 +13,7 @@ import type {StackCursor} from './ReactFiberStack.old';
13
14 import {enableTransitionTracing} from 'shared/ReactFeatureFlags';
15 import {createCursor, push, pop} from './ReactFiberStack.old';
16 +import {getWorkInProgressTransitions} from './ReactFiberWorkLoop.old';
17
18 export type SuspenseInfo = {name: string | null};
19
@@ -100,31 +101,77 @@ export function processTransitionCallbacks(
101 // tracing marker can be logged as complete
102 // This code lives separate from the ReactFiberTransition code because
103 // we push and pop on the tracing marker, not the suspense boundary
103 -const tracingMarkerStack: StackCursor<Array<Fiber> | null> = createCursor(null);
104 +const markerInstanceStack: StackCursor<Array<TracingMarkerInstance> | null> = createCursor(
105 + null,
106 +);
107
105 -export function pushTracingMarker(workInProgress: Fiber): void {
108 +export function pushRootMarkerInstance(workInProgress: Fiber): void {
109 if (enableTransitionTracing) {
107 - if (tracingMarkerStack.current === null) {
108 - push(tracingMarkerStack, [workInProgress], workInProgress);
110 + // On the root, every transition gets mapped to it's own map of
111 + // suspense boundaries. The transition is marked as complete when
112 + // the suspense boundaries map is empty. We do this because every
113 + // transition completes at different times and depends on different
114 + // suspense boundaries to complete. We store all the transitions
115 + // along with its map of suspense boundaries in the root incomplete
116 + // transitions map. Each entry in this map functions like a tracing
117 + // marker does, so we can push it onto the marker instance stack
118 + const transitions = getWorkInProgressTransitions();
119 + const root = workInProgress.stateNode;
120 +
121 + if (transitions !== null) {
122 + transitions.forEach(transition => {
123 + if (!root.incompleteTransitions.has(transition)) {
124 + root.incompleteTransitions.set(transition, {
125 + transitions: new Set([transition]),
126 + pendingSuspenseBoundaries: null,
127 + });
128 + }
129 + });
130 + }
131 +
132 + const markerInstances = [];
133 + // For ever transition on the suspense boundary, we push the transition
134 + // along with its map of pending suspense boundaries onto the marker
135 + // instance stack.
136 + root.incompleteTransitions.forEach(markerInstance => {
137 + markerInstances.push(markerInstance);
138 + });
139 + push(markerInstanceStack, markerInstances, workInProgress);
140 + }
141 +}
142 +
143 +export function popRootMarkerInstance(workInProgress: Fiber) {
144 + if (enableTransitionTracing) {
145 + pop(markerInstanceStack, workInProgress);
146 + }
147 +}
148 +
149 +export function pushMarkerInstance(
150 + workInProgress: Fiber,
151 + markerInstance: TracingMarkerInstance,
152 +): void {
153 + if (enableTransitionTracing) {
154 + if (markerInstanceStack.current === null) {
155 + push(markerInstanceStack, [markerInstance], workInProgress);
156 } else {
157 push(
111 - tracingMarkerStack,
112 - tracingMarkerStack.current.concat(workInProgress),
158 + markerInstanceStack,
159 + markerInstanceStack.current.concat(markerInstance),
160 workInProgress,
161 );
162 }
163 }
164 }
165
119 -export function popTracingMarker(workInProgress: Fiber): void {
166 +export function popMarkerInstance(workInProgress: Fiber): void {
167 if (enableTransitionTracing) {
121 - pop(tracingMarkerStack, workInProgress);
168 + pop(markerInstanceStack, workInProgress);
169 }
170 }
171
125 -export function getTracingMarkers(): Array<Fiber> | null {
172 +export function getMarkerInstances(): Array<TracingMarkerInstance> | null {
173 if (enableTransitionTracing) {
127 - return tracingMarkerStack.current;
174 + return markerInstanceStack.current;
175 }
176 return null;
177 }
packages/react-reconciler/src/ReactFiberUnwindWork.new.js
+23 -3
@@ -12,6 +12,7 @@ import type {Fiber, FiberRoot} from './ReactInternalTypes';
12 import type {Lanes} from './ReactFiberLane.new';
13 import type {SuspenseState} from './ReactFiberSuspenseComponent.new';
14 import type {Cache} from './ReactFiberCacheComponent.new';
15 +import type {TracingMarkerInstance} from './ReactFiberTracingMarkerComponent.new';
16
17 import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource.new';
18 import {
@@ -52,7 +53,10 @@ import {popCacheProvider} from './ReactFiberCacheComponent.new';
53 import {transferActualDuration} from './ReactProfilerTimer.new';
54 import {popTreeContext} from './ReactFiberTreeContext.new';
55 import {popRootTransition, popTransition} from './ReactFiberTransition.new';
55 -import {popTracingMarker} from './ReactFiberTracingMarkerComponent.new';
56 +import {
57 + popMarkerInstance,
58 + popRootMarkerInstance,
59 +} from './ReactFiberTracingMarkerComponent.new';
60
61 function unwindWork(
62 current: Fiber | null,
@@ -89,6 +93,11 @@ function unwindWork(
93 const cache: Cache = workInProgress.memoizedState.cache;
94 popCacheProvider(workInProgress, cache);
95 }
96 +
97 + if (enableTransitionTracing) {
98 + popRootMarkerInstance(workInProgress);
99 + }
100 +
101 popRootTransition(workInProgress, root, renderLanes);
102 popHostContainer(workInProgress);
103 popTopLevelLegacyContextObject(workInProgress);
@@ -165,7 +174,9 @@ function unwindWork(
174 return null;
175 case TracingMarkerComponent:
176 if (enableTransitionTracing) {
168 - popTracingMarker(workInProgress);
177 + if (workInProgress.stateNode !== null) {
178 + popMarkerInstance(workInProgress);
179 + }
180 }
181 return null;
182 default:
@@ -197,6 +208,11 @@ function unwindInterruptedWork(
208 const cache: Cache = interruptedWork.memoizedState.cache;
209 popCacheProvider(interruptedWork, cache);
210 }
211 +
212 + if (enableTransitionTracing) {
213 + popRootMarkerInstance(interruptedWork);
214 + }
215 +
216 popRootTransition(interruptedWork, root, renderLanes);
217 popHostContainer(interruptedWork);
218 popTopLevelLegacyContextObject(interruptedWork);
@@ -233,7 +249,11 @@ function unwindInterruptedWork(
249 break;
250 case TracingMarkerComponent:
251 if (enableTransitionTracing) {
236 - popTracingMarker(interruptedWork);
252 + const instance: TracingMarkerInstance | null =
253 + interruptedWork.stateNode;
254 + if (instance !== null) {
255 + popMarkerInstance(interruptedWork);
256 + }
257 }
258 break;
259 default:
packages/react-reconciler/src/ReactFiberUnwindWork.old.js
+23 -3
@@ -12,6 +12,7 @@ import type {Fiber, FiberRoot} from './ReactInternalTypes';
12 import type {Lanes} from './ReactFiberLane.old';
13 import type {SuspenseState} from './ReactFiberSuspenseComponent.old';
14 import type {Cache} from './ReactFiberCacheComponent.old';
15 +import type {TracingMarkerInstance} from './ReactFiberTracingMarkerComponent.old';
16
17 import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource.old';
18 import {
@@ -49,7 +50,10 @@ import {popCacheProvider} from './ReactFiberCacheComponent.old';
50 import {transferActualDuration} from './ReactProfilerTimer.old';
51 import {popTreeContext} from './ReactFiberTreeContext.old';
52 import {popRootTransition, popTransition} from './ReactFiberTransition.old';
52 -import {popTracingMarker} from './ReactFiberTracingMarkerComponent.old';
53 +import {
54 + popMarkerInstance,
55 + popRootMarkerInstance,
56 +} from './ReactFiberTracingMarkerComponent.old';
57
58 function unwindWork(
59 current: Fiber | null,
@@ -86,6 +90,11 @@ function unwindWork(
90 const cache: Cache = workInProgress.memoizedState.cache;
91 popCacheProvider(workInProgress, cache);
92 }
93 +
94 + if (enableTransitionTracing) {
95 + popRootMarkerInstance(workInProgress);
96 + }
97 +
98 popRootTransition(workInProgress, root, renderLanes);
99 popHostContainer(workInProgress);
100 popTopLevelLegacyContextObject(workInProgress);
@@ -162,7 +171,9 @@ function unwindWork(
171 return null;
172 case TracingMarkerComponent:
173 if (enableTransitionTracing) {
165 - popTracingMarker(workInProgress);
174 + if (workInProgress.stateNode !== null) {
175 + popMarkerInstance(workInProgress);
176 + }
177 }
178 return null;
179 default:
@@ -194,6 +205,11 @@ function unwindInterruptedWork(
205 const cache: Cache = interruptedWork.memoizedState.cache;
206 popCacheProvider(interruptedWork, cache);
207 }
208 +
209 + if (enableTransitionTracing) {
210 + popRootMarkerInstance(interruptedWork);
211 + }
212 +
213 popRootTransition(interruptedWork, root, renderLanes);
214 popHostContainer(interruptedWork);
215 popTopLevelLegacyContextObject(interruptedWork);
@@ -230,7 +246,11 @@ function unwindInterruptedWork(
246 break;
247 case TracingMarkerComponent:
248 if (enableTransitionTracing) {
233 - popTracingMarker(interruptedWork);
249 + const instance: TracingMarkerInstance | null =
250 + interruptedWork.stateNode;
251 + if (instance !== null) {
252 + popMarkerInstance(interruptedWork);
253 + }
254 }
255 break;
256 default:
packages/react-reconciler/src/ReactInternalTypes.js
+1 -1
@@ -335,7 +335,7 @@ type TransitionTracingOnlyFiberRootProperties = {|
335 // are considered complete when the pending suspense boundaries set is
336 // empty. We can represent this as a Map of transitions to suspense
337 // boundary sets
338 - incompleteTransitions: Map<Transition, PendingSuspenseBoundaries> | null,
338 + incompleteTransitions: Map<Transition, PendingSuspenseBoundaries>,
339 |};
340
341 // Exported FiberRoot type includes all properties,