@samitouri / QOS-React / commits / 4a8651412d

Renamed fiber.parent -> fiber.return

This is not just the parent Instance but also the return Fiber for some piece of work. This clarifies and buys into this definition. Basically, in the current model you will always pass into a fiber from the parent that you're going to return to. Even if you get aborted and reused this will be updated to the correct return fiber before you get back here. I don't have any guarantees in place to enforce this right now. I don't really know how to, but seems safe. :) I confirmed that the use of keyword properties work for old engines because we have the transform enabled in our build system.

Sebastian Markbage committed Jun 24, 2016 at 15:11 UTC 4a8651412ddb3ee745ae578e23966b422259fd94
6 files changed +59 -61
src/renderers/shared/fiber/ReactChildFiber.js
+16 -16
@@ -29,7 +29,7 @@ var {
29 var ReactFiber = require('ReactFiber');
30 var ReactReifiedYield = require('ReactReifiedYield');
31
32 -function createSubsequentChild(parent : Fiber, existingChild : ?Fiber, previousSibling : Fiber, newChildren, priority : PriorityLevel) : Fiber {
32 +function createSubsequentChild(returnFiber : Fiber, existingChild : ?Fiber, previousSibling : Fiber, newChildren, priority : PriorityLevel) : Fiber {
33 if (typeof newChildren !== 'object' || newChildren === null) {
34 return previousSibling;
35 }
@@ -46,13 +46,13 @@ function createSubsequentChild(parent : Fiber, existingChild : ?Fiber, previousS
46 clone.pendingProps = element.props;
47 clone.child = existingChild.child;
48 clone.sibling = null;
49 - clone.parent = parent;
49 + clone.return = returnFiber;
50 previousSibling.sibling = clone;
51 return clone;
52 }
53 const child = ReactFiber.createFiberFromElement(element, priority);
54 previousSibling.sibling = child;
55 - child.parent = parent;
55 + child.return = returnFiber;
56 return child;
57 }
58
@@ -60,7 +60,7 @@ function createSubsequentChild(parent : Fiber, existingChild : ?Fiber, previousS
60 const coroutine = (newChildren : ReactCoroutine);
61 const child = ReactFiber.createFiberFromCoroutine(coroutine, priority);
62 previousSibling.sibling = child;
63 - child.parent = parent;
63 + child.return = returnFiber;
64 return child;
65 }
66
@@ -70,7 +70,7 @@ function createSubsequentChild(parent : Fiber, existingChild : ?Fiber, previousS
70 const child = ReactFiber.createFiberFromYield(yieldNode, priority);
71 child.output = reifiedYield;
72 previousSibling.sibling = child;
73 - child.parent = parent;
73 + child.return = returnFiber;
74 return child;
75 }
76 }
@@ -79,7 +79,7 @@ function createSubsequentChild(parent : Fiber, existingChild : ?Fiber, previousS
79 let prev : Fiber = previousSibling;
80 let existing : ?Fiber = existingChild;
81 for (var i = 0; i < newChildren.length; i++) {
82 - prev = createSubsequentChild(parent, existing, prev, newChildren[i], priority);
82 + prev = createSubsequentChild(returnFiber, existing, prev, newChildren[i], priority);
83 if (prev && existing) {
84 // TODO: This is not correct because there could've been more
85 // than one sibling consumed but I don't want to return a tuple.
@@ -93,7 +93,7 @@ function createSubsequentChild(parent : Fiber, existingChild : ?Fiber, previousS
93 }
94 }
95
96 -function createFirstChild(parent, existingChild, newChildren, priority) {
96 +function createFirstChild(returnFiber, existingChild, newChildren, priority) {
97 if (typeof newChildren !== 'object' || newChildren === null) {
98 return null;
99 }
@@ -109,18 +109,18 @@ function createFirstChild(parent, existingChild, newChildren, priority) {
109 clone.pendingProps = element.props;
110 clone.child = existingChild.child;
111 clone.sibling = null;
112 - clone.parent = parent;
112 + clone.return = returnFiber;
113 return clone;
114 }
115 const child = ReactFiber.createFiberFromElement(element, priority);
116 - child.parent = parent;
116 + child.return = returnFiber;
117 return child;
118 }
119
120 case REACT_COROUTINE_TYPE: {
121 const coroutine = (newChildren : ReactCoroutine);
122 const child = ReactFiber.createFiberFromCoroutine(coroutine, priority);
123 - child.parent = parent;
123 + child.return = returnFiber;
124 return child;
125 }
126
@@ -132,7 +132,7 @@ function createFirstChild(parent, existingChild, newChildren, priority) {
132 const reifiedYield = ReactReifiedYield.createReifiedYield(yieldNode);
133 const child = ReactFiber.createFiberFromYield(yieldNode, priority);
134 child.output = reifiedYield;
135 - child.parent = parent;
135 + child.return = returnFiber;
136 return child;
137 }
138 }
@@ -143,10 +143,10 @@ function createFirstChild(parent, existingChild, newChildren, priority) {
143 var existing : ?Fiber = existingChild;
144 for (var i = 0; i < newChildren.length; i++) {
145 if (prev == null) {
146 - prev = createFirstChild(parent, existing, newChildren[i], priority);
146 + prev = createFirstChild(returnFiber, existing, newChildren[i], priority);
147 first = prev;
148 } else {
149 - prev = createSubsequentChild(parent, existing, prev, newChildren[i], priority);
149 + prev = createSubsequentChild(returnFiber, existing, prev, newChildren[i], priority);
150 }
151 if (prev && existing) {
152 // TODO: This is not correct because there could've been more
@@ -162,7 +162,7 @@ function createFirstChild(parent, existingChild, newChildren, priority) {
162 }
163
164 // TODO: This API won't work because we'll need to transfer the side-effects of
165 -// unmounting children to the parent.
166 -exports.reconcileChildFibers = function(parent : Fiber, currentFirstChild : ?Fiber, newChildren : ReactNodeList, priority : PriorityLevel) : ?Fiber {
167 - return createFirstChild(parent, currentFirstChild, newChildren, priority);
165 +// unmounting children to the returnFiber.
166 +exports.reconcileChildFibers = function(returnFiber : Fiber, currentFirstChild : ?Fiber, newChildren : ReactNodeList, priority : PriorityLevel) : ?Fiber {
167 + return createFirstChild(returnFiber, currentFirstChild, newChildren, priority);
168 };
src/renderers/shared/fiber/ReactFiber.js
+18 -13
@@ -41,11 +41,6 @@ type Instance = {
41 // Tag identifying the type of fiber.
42 tag: TypeOfWork,
43
44 - // The parent Fiber used to create this one. The type is constrained to the
45 - // Instance part of the Fiber since it is not safe to traverse the tree from
46 - // the instance.
47 - parent: ?Instance, // Consider a regenerated temporary parent stack instead.
48 -
44 // Unique identifier of this child.
45 key: null | string,
46
@@ -55,12 +50,22 @@ type Instance = {
50 // The local state associated with this fiber.
51 stateNode: ?Object,
52
53 + // Conceptual aliases
54 + // parent : Instance -> return The parent happens to be the same as the
55 + // return fiber since we've merged the fiber and instance.
56 +
57 };
58
59 // A Fiber is work on a Component that needs to be done or was done. There can
60 // be more than one per component.
61 export type Fiber = Instance & {
62
63 + // The Fiber to return to after finishing processing this one.
64 + // This is effectively the parent, but there can be multiple parents (two)
65 + // so this is only the parent of the thing we're currently processing.
66 + // It is conceptually the same as the return address of a stack frame.
67 + return: ?Fiber,
68 +
69 // Singly Linked List Tree Structure.
70 child: ?Fiber,
71 sibling: ?Fiber,
@@ -71,8 +76,8 @@ export type Fiber = Instance & {
76
77 // Input is the data coming into process this fiber. Arguments. Props.
78 pendingProps: any, // This type will be more specific once we overload the tag.
74 - // TODO: I think that there is a way to merge input and memoizedProps somehow.
75 - memoizedProps: any, // The input used to create the output.
79 + // TODO: I think that there is a way to merge pendingProps and memoizedProps.
80 + memoizedProps: any, // The props used to create the output.
81 // Output is the return value of this fiber, or a linked list of return values
82 // if this returns multiple values. Such as a fragment.
83 output: any, // This type will be more specific once we overload the tag.
@@ -93,8 +98,8 @@ export type Fiber = Instance & {
98 hasWorkInProgress: bool,
99
100 // Conceptual aliases
96 - // parent : Instance -> returnFiber The parent happens to be the same as the return fiber.
97 - // workInProgress : Fiber -> alternate The alternate used for reuse happens to be the same as work in progress.
101 + // workInProgress : Fiber -> alternate The alternate used for reuse happens
102 + // to be the same as work in progress.
103
104 };
105
@@ -105,8 +110,6 @@ var createFiber = function(tag : TypeOfWork, key : null | string) : Fiber {
110
111 tag: tag,
112
108 - parent: null,
109 -
113 key: key,
114
115 type: null,
@@ -115,6 +118,8 @@ var createFiber = function(tag : TypeOfWork, key : null | string) : Fiber {
118
119 // Fiber
120
121 + return: null,
122 +
123 child: null,
124 sibling: null,
125
@@ -126,10 +131,10 @@ var createFiber = function(tag : TypeOfWork, key : null | string) : Fiber {
131
132 pendingWorkPriority: NoWork,
133
129 - alternate: null,
130 -
134 hasWorkInProgress: false,
135
136 + alternate: null,
137 +
138 };
139 };
140
src/renderers/shared/fiber/ReactFiberBeginWork.js
+7 -7
@@ -115,22 +115,22 @@ function updateCoroutineComponent(current, workInProgress) {
115 workInProgress.pendingWorkPriority = NoWork;
116 }
117
118 -function reuseChildren(newParent : Fiber, firstChild : Fiber) {
118 +function reuseChildren(returnFiber : Fiber, firstChild : Fiber) {
119 // TODO: None of this should be necessary if structured better.
120 - // The parent pointer only needs to be updated when we walk into this child
120 + // The returnFiber pointer only needs to be updated when we walk into this child
121 // which we don't do right now. If the pending work priority indicated only
122 // if a child has work rather than if the node has work, then we would know
123 // by a single lookup on workInProgress rather than having to go through
124 // each child.
125 let child = firstChild;
126 do {
127 - // Update the parent of the child to the newest fiber.
128 - child.parent = newParent;
127 + // Update the returnFiber of the child to the newest fiber.
128 + child.return = returnFiber;
129 // Retain the priority if there's any work left to do in the children.
130 if (child.pendingWorkPriority !== NoWork &&
131 - (newParent.pendingWorkPriority === NoWork ||
132 - newParent.pendingWorkPriority > child.pendingWorkPriority)) {
133 - newParent.pendingWorkPriority = child.pendingWorkPriority;
131 + (returnFiber.pendingWorkPriority === NoWork ||
132 + returnFiber.pendingWorkPriority > child.pendingWorkPriority)) {
133 + returnFiber.pendingWorkPriority = child.pendingWorkPriority;
134 }
135 } while (child = child.sibling);
136 }
src/renderers/shared/fiber/ReactFiberCompleteWork.js
+4 -4
@@ -30,12 +30,12 @@ var {
30 YieldComponent,
31 } = ReactTypeOfWork;
32
33 -function transferOutput(child : ?Fiber, parent : Fiber) {
33 +function transferOutput(child : ?Fiber, returnFiber : Fiber) {
34 // If we have a single result, we just pass that through as the output to
35 // avoid unnecessary traversal. When we have multiple output, we just pass
36 // the linked list of fibers that has the individual output values.
37 - parent.output = (child && !child.sibling) ? child.output : child;
38 - parent.memoizedProps = parent.pendingProps;
37 + returnFiber.output = (child && !child.sibling) ? child.output : child;
38 + returnFiber.memoizedProps = returnFiber.pendingProps;
39 }
40
41 function recursivelyFillYields(yields, output : ?Fiber | ?ReifiedYield) {
@@ -83,7 +83,7 @@ function moveCoroutineToHandlerPhase(current : ?Fiber, workInProgress : Fiber) {
83 var nextChildren = fn(props, yields);
84
85 var currentFirstChild = current ? current.stateNode : null;
86 - // Inherit the priority of the parent.
86 + // Inherit the priority of the returnFiber.
87 const priority = workInProgress.pendingWorkPriority;
88 workInProgress.stateNode = ReactChildFiber.reconcileChildFibers(
89 workInProgress,
src/renderers/shared/fiber/ReactFiberPendingWork.js
+5 -7
@@ -21,14 +21,14 @@ var {
21 NoWork,
22 } = require('ReactPriorityLevel');
23
24 -function cloneSiblings(current : Fiber, workInProgress : Fiber, parent : Fiber) {
24 +function cloneSiblings(current : Fiber, workInProgress : Fiber, returnFiber : Fiber) {
25 while (current.sibling) {
26 current = current.sibling;
27 workInProgress = workInProgress.sibling = ReactFiber.cloneFiber(
28 current,
29 current.pendingWorkPriority
30 );
31 - workInProgress.parent = parent;
31 + workInProgress.return = returnFiber;
32 }
33 workInProgress.sibling = null;
34 }
@@ -63,7 +63,7 @@ exports.findNextUnitOfWorkAtPriority = function(currentRoot : Fiber, priorityLev
63 }
64 workInProgress.pendingWorkPriority = current.pendingWorkPriority;
65 workInProgress.child = ReactFiber.cloneFiber(currentChild, NoWork);
66 - workInProgress.child.parent = workInProgress;
66 + workInProgress.child.return = workInProgress;
67 cloneSiblings(currentChild, workInProgress.child, workInProgress);
68 current = current.child;
69 continue;
@@ -79,9 +79,7 @@ exports.findNextUnitOfWorkAtPriority = function(currentRoot : Fiber, priorityLev
79 return null;
80 }
81 while (!current.sibling) {
82 - // TODO: Stop using parent here. See below.
83 - // $FlowFixMe: This downcast is not safe. It is intentionally an error.
84 - current = current.parent;
82 + current = current.return;
83 if (!current) {
84 return null;
85 }
@@ -95,4 +93,4 @@ exports.findNextUnitOfWorkAtPriority = function(currentRoot : Fiber, priorityLev
93 current = current.sibling;
94 }
95 return null;
98 -}
96 +};
src/renderers/shared/fiber/ReactFiberScheduler.js
+9 -14
@@ -94,29 +94,24 @@ module.exports = function<T, P, I>(config : HostConfig<T, P, I>) {
94 workInProgress.hasWorkInProgress = false;
95 }
96
97 - // TODO: Stop using the parent for this purpose. I think this will break
98 - // down in edge cases because when nodes are reused during bailouts, we
99 - // don't know which of two parents was used. Instead we should maintain
100 - // a temporary manual stack.
101 - // $FlowFixMe: This downcast is not safe. It is intentionally an error.
102 - const parent = workInProgress.parent;
97 + const returnFiber = workInProgress.return;
98
99 // Ensure that remaining work priority bubbles up.
105 - if (parent && workInProgress.pendingWorkPriority !== NoWork &&
106 - (parent.pendingWorkPriority === NoWork ||
107 - parent.pendingWorkPriority > workInProgress.pendingWorkPriority)) {
108 - parent.pendingWorkPriority = workInProgress.pendingWorkPriority;
100 + if (returnFiber && workInProgress.pendingWorkPriority !== NoWork &&
101 + (returnFiber.pendingWorkPriority === NoWork ||
102 + returnFiber.pendingWorkPriority > workInProgress.pendingWorkPriority)) {
103 + returnFiber.pendingWorkPriority = workInProgress.pendingWorkPriority;
104 }
105
106 if (next) {
107 // If completing this work spawned new work, do that next.
108 return next;
109 } else if (workInProgress.sibling) {
115 - // If there is more work to do in this parent, do that next.
110 + // If there is more work to do in this returnFiber, do that next.
111 return workInProgress.sibling;
117 - } else if (parent) {
118 - // If there's no more work in this parent. Complete the parent.
119 - workInProgress = parent;
112 + } else if (returnFiber) {
113 + // If there's no more work in this returnFiber. Complete the returnFiber.
114 + workInProgress = returnFiber;
115 } else {
116 // If we're at the root, there's no more work to do. We can flush it.
117 const root : FiberRoot = (workInProgress.stateNode : any);