Skip to content

Commit

Permalink
Experiment with using an object literal for Fiber creation
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
kassens committed Apr 3, 2024
1 parent 20e710a commit 834d891
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 7 deletions.
226 changes: 219 additions & 7 deletions packages/react-reconciler/src/ReactFiber.js
Expand Up @@ -28,16 +28,17 @@ import {
isHostSingletonType,
} from './ReactFiberConfig';
import {
enableProfilerTimer,
enableScopeAPI,
enableLegacyHidden,
forceConcurrentByDefaultForTesting,
allowConcurrentByDefault,
enableTransitionTracing,
disableLegacyMode,
enableDebugTracing,
enableDO_NOT_USE_disableStrictPassiveEffect,
enableLegacyHidden,
enableObjectFiber,
enableProfilerTimer,
enableRenderableContext,
disableLegacyMode,
enableScopeAPI,
enableTransitionTracing,
forceConcurrentByDefaultForTesting,
} from 'shared/ReactFeatureFlags';
import {NoFlags, Placement, StaticMask} from './ReactFiberFlags';
import {ConcurrentRoot} from './ReactRootTags';
Expand Down Expand Up @@ -222,7 +223,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,
Expand All @@ -232,6 +233,217 @@ function createFiber(
return new FiberNode(tag, pendingProps, key, mode);
}

function createFiberImplObjectDev(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
): Fiber {
const 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,

// __DEV__ only
_debugInfo: null,
_debugOwner: null,
_debugNeedsRemount: false,
_debugHookTypes: null,
};
if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') {
Object.preventExtensions(fiber);
}
return fiber;
}
function createFiberImplObjectDevProfile(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
): Fiber {
const 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,

// enableProfilerTimer only
actualDuration: 0,
actualStartTime: -1,
selfBaseDuration: 0,
treeBaseDuration: 0,

// __DEV__ only
_debugInfo: null,
_debugOwner: null,
_debugNeedsRemount: false,
_debugHookTypes: null,
};
if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') {
Object.preventExtensions(fiber);
}
return fiber;
}
function createFiberImplObjectProd(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
): Fiber {
return {
// 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,
};
}
function createFiberImplObjectProdProfile(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
): Fiber {
return {
// 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,

// enableProfilerTimer only
actualDuration: 0,
actualStartTime: -1,
selfBaseDuration: 0,
treeBaseDuration: 0,
};
}

const createFiber = !enableObjectFiber
? createFiberImplClass
: __DEV__
? enableProfilerTimer
? createFiberImplObjectDevProfile
: createFiberImplObjectDev
: enableProfilerTimer
? createFiberImplObjectProdProfile
: createFiberImplObjectProd;

function shouldConstruct(Component: Function) {
const prototype = Component.prototype;
return !!(prototype && prototype.isReactComponent);
Expand Down
5 changes: 5 additions & 0 deletions packages/shared/ReactFeatureFlags.js
Expand Up @@ -83,6 +83,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
Expand Down
Expand Up @@ -27,3 +27,4 @@ export const enableRenderableContext = __VARIANT__;
export const enableUnifiedSyncLane = __VARIANT__;
export const passChildrenWhenCloningPersistedNodes = __VARIANT__;
export const useModernStrictMode = __VARIANT__;
export const enableObjectFiber = __VARIANT__;
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.native-fb.js
Expand Up @@ -25,6 +25,7 @@ export const {
enableComponentStackLocations,
enableDeferRootSchedulingToMicrotask,
enableInfiniteRenderLoopDetection,
enableObjectFiber,
enableRenderableContext,
enableUnifiedSyncLane,
passChildrenWhenCloningPersistedNodes,
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.native-oss.js
Expand Up @@ -72,6 +72,7 @@ export const enableSchedulingProfiler = __PROFILE__;
export const enableLegacyCache = false;
export const enableFetchInstrumentation = false;
export const enablePostpone = false;
export const enableObjectFiber = false;
export const disableCommentsAsDOMContainers = true;
export const disableInputAttributeSyncing = false;
export const disableIEWorkarounds = true;
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.test-renderer.js
Expand Up @@ -90,6 +90,7 @@ export const disableLegacyContext = true;
export const disableDOMTestUtils = true;
export const enableRenderableContext = true;
export const enableReactTestRendererWarning = true;
export const enableObjectFiber = false;

// Flow magic to verify the exports of this file match the original version.
((((null: any): ExportsType): FeatureFlagsType): ExportsType);
Expand Up @@ -84,6 +84,7 @@ export const disableStringRefs = false;
export const enableReactTestRendererWarning = false;
export const disableLegacyMode = false;
export const disableDOMTestUtils = false;
export const enableObjectFiber = false;

// Flow magic to verify the exports of this file match the original version.
((((null: any): ExportsType): FeatureFlagsType): ExportsType);
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.www.js
Expand Up @@ -114,6 +114,7 @@ export const disableStringRefs = false;
export const disableLegacyMode = __EXPERIMENTAL__;

export const disableDOMTestUtils = false;
export const enableObjectFiber = false;

// Flow magic to verify the exports of this file match the original version.
((((null: any): ExportsType): FeatureFlagsType): ExportsType);

0 comments on commit 834d891

Please sign in to comment.