From b7db858d37352ebd77c0f7a06dd4d6db830e12a4 Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Fri, 21 Jun 2024 10:25:22 -0400 Subject: [PATCH] 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. --- packages/react-reconciler/src/ReactFiber.js | 69 ++++++++++++++++++- packages/shared/ReactFeatureFlags.js | 5 ++ .../ReactFeatureFlags.native-fb-dynamic.js | 1 + .../forks/ReactFeatureFlags.native-fb.js | 1 + .../forks/ReactFeatureFlags.native-oss.js | 1 + .../forks/ReactFeatureFlags.test-renderer.js | 1 + ...actFeatureFlags.test-renderer.native-fb.js | 1 + .../ReactFeatureFlags.test-renderer.www.js | 1 + .../shared/forks/ReactFeatureFlags.www.js | 1 + 9 files changed, 80 insertions(+), 1 deletion(-) diff --git a/packages/react-reconciler/src/ReactFiber.js b/packages/react-reconciler/src/ReactFiber.js index 28cd65dbb3c07..0ee4345802a11 100644 --- a/packages/react-reconciler/src/ReactFiber.js +++ b/packages/react-reconciler/src/ReactFiber.js @@ -38,6 +38,7 @@ import { enableDO_NOT_USE_disableStrictPassiveEffect, enableRenderableContext, disableLegacyMode, + enableObjectFiber, enableOwnerStacks, } from 'shared/ReactFeatureFlags'; import {NoFlags, Placement, StaticMask} from './ReactFiberFlags'; @@ -232,7 +233,7 @@ function FiberNode( // is faster. // 5) It should be easy to port this to a C struct and keep a C implementation // compatible. -function createFiber( +function createFiberImplClass( tag: WorkTag, pendingProps: mixed, key: null | string, @@ -242,6 +243,72 @@ function createFiber( return new FiberNode(tag, pendingProps, key, mode); } +function createFiberImplObject( + tag: WorkTag, + pendingProps: mixed, + key: null | string, + mode: TypeOfMode, +): Fiber { + const fiber: Fiber = { + // Instance + tag, + key, + elementType: null, + type: null, + stateNode: null, + + // Fiber + return: null, + child: null, + sibling: null, + index: 0, + + ref: null, + refCleanup: null, + + pendingProps, + memoizedProps: null, + updateQueue: null, + memoizedState: null, + dependencies: null, + + mode, + + // Effects + flags: NoFlags, + subtreeFlags: NoFlags, + deletions: null, + + lanes: NoLanes, + childLanes: NoLanes, + + alternate: null, + }; + + if (enableProfilerTimer) { + fiber.actualDuration = 0; + fiber.actualStartTime = -1; + fiber.selfBaseDuration = 0; + fiber.treeBaseDuration = 0; + } + + if (__DEV__) { + fiber._debugInfo = null; + fiber._debugOwner = null; + fiber._debugNeedsRemount = false; + fiber._debugHookTypes = null; + + if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') { + Object.preventExtensions(fiber); + } + } + return fiber; +} + +const createFiber = enableObjectFiber + ? createFiberImplObject + : createFiberImplClass; + function shouldConstruct(Component: Function) { const prototype = Component.prototype; return !!(prototype && prototype.isReactComponent); diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 8b2d0800cb933..3dc8b0308c083 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -87,6 +87,11 @@ export const enableTaint = __EXPERIMENTAL__; export const enablePostpone = __EXPERIMENTAL__; +/** + * Switches Fiber creation to a simple object instead of a constructor. + */ +export const enableObjectFiber = false; + export const enableTransitionTracing = false; // No known bugs, but needs performance testing diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js index ecdb3755691d2..20dc45cf3f51c 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js @@ -24,5 +24,6 @@ export const enableAddPropertiesFastPath = __VARIANT__; export const enableDeferRootSchedulingToMicrotask = __VARIANT__; export const enableFastJSX = __VARIANT__; export const enableInfiniteRenderLoopDetection = __VARIANT__; +export const enableObjectFiber = __VARIANT__; export const enableShallowPropDiffing = __VARIANT__; export const passChildrenWhenCloningPersistedNodes = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index a9e2b146e1bc3..a639ee48d8ca5 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -26,6 +26,7 @@ export const { enableDeferRootSchedulingToMicrotask, enableFastJSX, enableInfiniteRenderLoopDetection, + enableObjectFiber, enableShallowPropDiffing, passChildrenWhenCloningPersistedNodes, } = dynamicFlags; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 88e49d2bc94a3..e9e8805e8aa30 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -55,6 +55,7 @@ export const enableLegacyCache = false; export const enableLegacyFBSupport = false; export const enableLegacyHidden = false; export const enableNoCloningMemoCache = false; +export const enableObjectFiber = false; export const enableOwnerStacks = __EXPERIMENTAL__; export const enablePostpone = false; export const enableReactTestRendererWarning = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index e40351ae1fcf4..632e2b575a686 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -97,6 +97,7 @@ export const enableRenderableContext = true; export const enableReactTestRendererWarning = true; export const disableDefaultPropsExceptForClasses = true; +export const enableObjectFiber = false; export const enableOwnerStacks = false; // Flow magic to verify the exports of this file match the original version. diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js index ec4a96f9c868f..73bbc992c8285 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js @@ -47,6 +47,7 @@ export const enableLegacyCache = false; export const enableLegacyFBSupport = false; export const enableLegacyHidden = false; export const enableNoCloningMemoCache = false; +export const enableObjectFiber = false; export const enableOwnerStacks = false; export const enablePostpone = false; export const enableProfilerCommitHooks = __PROFILE__; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 2bd4e0798911c..24eda0696270f 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -91,6 +91,7 @@ export const enableAddPropertiesFastPath = false; export const renameElementSymbol = false; +export const enableObjectFiber = false; export const enableOwnerStacks = false; export const enableShallowPropDiffing = false; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 9404b877f532b..050552c531f36 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -122,6 +122,7 @@ export const disableStringRefs = false; export const disableLegacyMode: boolean = __EXPERIMENTAL__ || dynamicFeatureFlags.disableLegacyMode; +export const enableObjectFiber = false; export const enableOwnerStacks = false; export const enableShallowPropDiffing = false;