Skip to content

Commit c2bc596

Browse files
committed
Experiment with using an object literal for Fiber creation
Object literals should be faster at least on React Native with Hermes as the JS engine. It might also be interesting to confirm the old comments in this file from years ago are even still valid. Creating an object from a literal should be a simpler operation. It's a bit unfortunate that this introduces a bunch of copied code, but since we rearely update the fields on fibers, this seems like an okay tradeoff for a hot code path. An alternative would be some sort of macro system, but that doesn't seem worth the extra complexity.
1 parent 34dccef commit c2bc596

10 files changed

+108
-25
lines changed

packages/react-reconciler/src/ReactFiber.js

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
enableDO_NOT_USE_disableStrictPassiveEffect,
3939
enableRenderableContext,
4040
disableLegacyMode,
41+
enableObjectFiber,
4142
enableOwnerStacks,
4243
} from 'shared/ReactFeatureFlags';
4344
import {NoFlags, Placement, StaticMask} from './ReactFiberFlags';
@@ -232,7 +233,7 @@ function FiberNode(
232233
// is faster.
233234
// 5) It should be easy to port this to a C struct and keep a C implementation
234235
// compatible.
235-
function createFiber(
236+
function createFiberImplClass(
236237
tag: WorkTag,
237238
pendingProps: mixed,
238239
key: null | string,
@@ -242,6 +243,75 @@ function createFiber(
242243
return new FiberNode(tag, pendingProps, key, mode);
243244
}
244245

246+
function createFiberImplObject(
247+
tag: WorkTag,
248+
pendingProps: mixed,
249+
key: null | string,
250+
mode: TypeOfMode,
251+
): Fiber {
252+
const fiber: Fiber = {
253+
// Instance
254+
// tag, key - defined at the bottom as dynamic properties
255+
elementType: null,
256+
type: null,
257+
stateNode: null,
258+
259+
// Fiber
260+
return: null,
261+
child: null,
262+
sibling: null,
263+
index: 0,
264+
265+
ref: null,
266+
refCleanup: null,
267+
268+
// pendingProps - defined at the bottom as dynamic properties
269+
memoizedProps: null,
270+
updateQueue: null,
271+
memoizedState: null,
272+
dependencies: null,
273+
274+
// Effects
275+
flags: NoFlags,
276+
subtreeFlags: NoFlags,
277+
deletions: null,
278+
279+
lanes: NoLanes,
280+
childLanes: NoLanes,
281+
282+
alternate: null,
283+
284+
// dynamic properties at the end for more efficient hermes bytecode
285+
tag,
286+
key,
287+
pendingProps,
288+
mode,
289+
};
290+
291+
if (enableProfilerTimer) {
292+
fiber.actualDuration = 0;
293+
fiber.actualStartTime = -1;
294+
fiber.selfBaseDuration = 0;
295+
fiber.treeBaseDuration = 0;
296+
}
297+
298+
if (__DEV__) {
299+
fiber._debugInfo = null;
300+
fiber._debugOwner = null;
301+
fiber._debugNeedsRemount = false;
302+
fiber._debugHookTypes = null;
303+
304+
if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') {
305+
Object.preventExtensions(fiber);
306+
}
307+
}
308+
return fiber;
309+
}
310+
311+
const createFiber = enableObjectFiber
312+
? createFiberImplObject
313+
: createFiberImplClass;
314+
245315
function shouldConstruct(Component: Function) {
246316
const prototype = Component.prototype;
247317
return !!(prototype && prototype.isReactComponent);

packages/shared/ReactFeatureFlags.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ export const enableTaint = __EXPERIMENTAL__;
8787

8888
export const enablePostpone = __EXPERIMENTAL__;
8989

90+
/**
91+
* Switches Fiber creation to a simple object instead of a constructor.
92+
*/
93+
export const enableObjectFiber = false;
94+
9095
export const enableTransitionTracing = false;
9196

9297
// No known bugs, but needs performance testing

packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ export const consoleManagedByDevToolsDuringStrictMode = __VARIANT__;
2222
export const disableDefaultPropsExceptForClasses = __VARIANT__;
2323
export const enableAddPropertiesFastPath = __VARIANT__;
2424
export const enableFastJSX = __VARIANT__;
25+
export const enableObjectFiber = __VARIANT__;
2526
export const enableShallowPropDiffing = __VARIANT__;
2627
export const passChildrenWhenCloningPersistedNodes = __VARIANT__;

packages/shared/forks/ReactFeatureFlags.native-fb.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export const {
2424
disableDefaultPropsExceptForClasses,
2525
enableAddPropertiesFastPath,
2626
enableFastJSX,
27+
enableObjectFiber,
2728
enableShallowPropDiffing,
2829
passChildrenWhenCloningPersistedNodes,
2930
} = dynamicFlags;

packages/shared/forks/ReactFeatureFlags.native-oss.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export const enableLegacyCache = false;
5555
export const enableLegacyFBSupport = false;
5656
export const enableLegacyHidden = false;
5757
export const enableNoCloningMemoCache = false;
58+
export const enableObjectFiber = false;
5859
export const enableOwnerStacks = __EXPERIMENTAL__;
5960
export const enablePostpone = false;
6061
export const enableReactTestRendererWarning = false;

packages/shared/forks/ReactFeatureFlags.test-renderer.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ export const enableRenderableContext = true;
9696
export const enableReactTestRendererWarning = true;
9797
export const disableDefaultPropsExceptForClasses = true;
9898

99+
export const enableObjectFiber = false;
99100
export const enableOwnerStacks = false;
100101

101102
// Flow magic to verify the exports of this file match the original version.

packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export const enableLegacyCache = false;
4747
export const enableLegacyFBSupport = false;
4848
export const enableLegacyHidden = false;
4949
export const enableNoCloningMemoCache = false;
50+
export const enableObjectFiber = false;
5051
export const enableOwnerStacks = false;
5152
export const enablePostpone = false;
5253
export const enableProfilerCommitHooks = __PROFILE__;

packages/shared/forks/ReactFeatureFlags.test-renderer.www.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export const enableAddPropertiesFastPath = false;
9090

9191
export const renameElementSymbol = false;
9292

93+
export const enableObjectFiber = false;
9394
export const enableOwnerStacks = false;
9495
export const enableShallowPropDiffing = false;
9596

packages/shared/forks/ReactFeatureFlags.www-dynamic.js

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,27 @@
1313
// Use __VARIANT__ to simulate a GK. The tests will be run twice: once
1414
// with the __VARIANT__ set to `true`, and once set to `false`.
1515

16+
export const alwaysThrottleRetries = true;
17+
export const disableDefaultPropsExceptForClasses = __VARIANT__;
18+
export const disableLegacyMode = __VARIANT__;
1619
export const disableSchedulerTimeoutInWorkLoop = __VARIANT__;
17-
export const enableLazyContextPropagation = __VARIANT__;
18-
export const forceConcurrentByDefaultForTesting = __VARIANT__;
19-
export const enableTransitionTracing = __VARIANT__;
20+
export const enableAddPropertiesFastPath = __VARIANT__;
2021
export const enableDeferRootSchedulingToMicrotask = __VARIANT__;
21-
export const alwaysThrottleRetries = true;
2222
export const enableDO_NOT_USE_disableStrictPassiveEffect = __VARIANT__;
23-
export const enableUseDeferredValueInitialArg = __VARIANT__;
24-
export const enableRenderableContext = __VARIANT__;
2523
export const enableFastJSX = __VARIANT__;
24+
export const enableLazyContextPropagation = __VARIANT__;
25+
export const enableNoCloningMemoCache = __VARIANT__;
26+
export const enableObjectFiber = __VARIANT__;
27+
export const enableRenderableContext = __VARIANT__;
2628
export const enableRetryLaneExpiration = __VARIANT__;
29+
export const enableTransitionTracing = __VARIANT__;
30+
export const enableUseDeferredValueInitialArg = __VARIANT__;
2731
export const favorSafetyOverHydrationPerf = __VARIANT__;
28-
export const disableDefaultPropsExceptForClasses = __VARIANT__;
29-
export const enableNoCloningMemoCache = __VARIANT__;
32+
export const forceConcurrentByDefaultForTesting = __VARIANT__;
33+
export const renameElementSymbol = __VARIANT__;
3034
export const retryLaneExpirationMs = 5000;
3135
export const syncLaneExpirationMs = 250;
3236
export const transitionLaneExpirationMs = 5000;
33-
export const enableAddPropertiesFastPath = __VARIANT__;
34-
export const disableLegacyMode = __VARIANT__;
35-
export const renameElementSymbol = __VARIANT__;
3637

3738
// Enable this flag to help with concurrent mode debugging.
3839
// It logs information to the console about React scheduling, rendering, and commit phases.

packages/shared/forks/ReactFeatureFlags.www.js

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,28 @@ import typeof * as DynamicFeatureFlags from './ReactFeatureFlags.www-dynamic';
1515
const dynamicFeatureFlags: DynamicFeatureFlags = require('ReactFeatureFlags');
1616

1717
export const {
18-
enableTrustedTypesIntegration,
18+
alwaysThrottleRetries,
19+
disableDefaultPropsExceptForClasses,
20+
disableSchedulerTimeoutInWorkLoop,
21+
enableAddPropertiesFastPath,
1922
enableDebugTracing,
23+
enableDeferRootSchedulingToMicrotask,
24+
enableDO_NOT_USE_disableStrictPassiveEffect,
25+
enableFastJSX,
26+
enableInfiniteRenderLoopDetection,
2027
enableLazyContextPropagation,
28+
enableNoCloningMemoCache,
29+
enableObjectFiber,
30+
enableRenderableContext,
2131
enableRetryLaneExpiration,
2232
enableTransitionTracing,
23-
enableDeferRootSchedulingToMicrotask,
24-
alwaysThrottleRetries,
25-
enableDO_NOT_USE_disableStrictPassiveEffect,
26-
disableSchedulerTimeoutInWorkLoop,
33+
enableTrustedTypesIntegration,
2734
enableUseDeferredValueInitialArg,
35+
favorSafetyOverHydrationPerf,
36+
renameElementSymbol,
2837
retryLaneExpirationMs,
2938
syncLaneExpirationMs,
3039
transitionLaneExpirationMs,
31-
enableInfiniteRenderLoopDetection,
32-
enableRenderableContext,
33-
favorSafetyOverHydrationPerf,
34-
disableDefaultPropsExceptForClasses,
35-
enableNoCloningMemoCache,
36-
enableAddPropertiesFastPath,
37-
enableFastJSX,
38-
renameElementSymbol,
3940
} = dynamicFeatureFlags;
4041

4142
// On WWW, __EXPERIMENTAL__ is used for a new modern build.

0 commit comments

Comments
 (0)