Make class prop resolution faster (#28766)

`delete` causes an object (in V8, and maybe other engines) to deopt to a
dictionary instead of a class. Instead of `assign` + `delete`, manually
iterate over all the properties, like the JSX runtime does.

To avoid copying the object twice I moved the `ref` prop removal to come
before handling default props. If we already cloned the props to remove
`ref`, then we can skip cloning again to handle default props.

DiffTrain build for commit https://github.com/facebook/react/commit/bfd8da807c75a2d123627415f9eaf2d36ac3ed6a.
This commit is contained in:
acdlite
2024-04-05 17:11:19 +00:00
parent 6eddd13b28
commit 4e6493a6c1
10 changed files with 58 additions and 46 deletions
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<fa29b2fc6de1e6452849c40ebd890ad7>>
* @generated SignedSource<<5dd37abeea74ddd8ec0ebe6450152a2d>>
*/
"use strict";
@@ -12999,7 +12999,7 @@ if (__DEV__) {
// remove this extra check.
alreadyResolvedDefaultProps
) {
var newProps = baseProps; // Resolve default props. Taken from old JSX runtime, where this used to live.
var newProps = baseProps;
var defaultProps = Component.defaultProps;
@@ -13008,11 +13008,15 @@ if (__DEV__) {
// default props here in the reconciler, rather than in the JSX runtime.
!alreadyResolvedDefaultProps
) {
newProps = assign({}, newProps, baseProps);
// We may have already copied the props object above to remove ref. If so,
// we can modify that. Otherwise, copy the props object with Object.assign.
if (newProps === baseProps) {
newProps = assign({}, newProps, baseProps);
} // Taken from old JSX runtime, where this used to live.
for (var propName in defaultProps) {
if (newProps[propName] === undefined) {
newProps[propName] = defaultProps[propName];
for (var _propName in defaultProps) {
if (newProps[_propName] === undefined) {
newProps[_propName] = defaultProps[_propName];
}
}
}
@@ -26620,7 +26624,7 @@ if (__DEV__) {
return root;
}
var ReactVersion = "19.0.0-canary-2f991a8a";
var ReactVersion = "19.0.0-canary-dd665447";
/*
* The `'' + value` pattern (used in perf-sensitive code) throws for Symbol
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<c280d92632a452d04a57733b09d6735d>>
* @generated SignedSource<<000f349e62b33714c1beb5b32a865608>>
*/
"use strict";
@@ -3472,7 +3472,7 @@ function resolveClassComponentProps(
) {
var newProps = baseProps;
if ((Component = Component.defaultProps) && !alreadyResolvedDefaultProps) {
newProps = assign({}, newProps, baseProps);
newProps === baseProps && (newProps = assign({}, newProps, baseProps));
for (var propName in Component)
void 0 === newProps[propName] &&
(newProps[propName] = Component[propName]);
@@ -9154,7 +9154,7 @@ var devToolsConfig$jscomp$inline_994 = {
throw Error("TestRenderer does not support findFiberByHostInstance()");
},
bundleType: 0,
version: "19.0.0-canary-f92daaf1",
version: "19.0.0-canary-f60d093a",
rendererPackageName: "react-test-renderer"
};
var internals$jscomp$inline_1214 = {
@@ -9185,7 +9185,7 @@ var internals$jscomp$inline_1214 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "19.0.0-canary-f92daaf1"
reconcilerVersion: "19.0.0-canary-f60d093a"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_1215 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<74899a6d3fe92773c2f385a9916407bb>>
* @generated SignedSource<<b9d1eed3b9bd859cc782a84afe6d9a15>>
*/
"use strict";
@@ -3630,7 +3630,7 @@ function resolveClassComponentProps(
) {
var newProps = baseProps;
if ((Component = Component.defaultProps) && !alreadyResolvedDefaultProps) {
newProps = assign({}, newProps, baseProps);
newProps === baseProps && (newProps = assign({}, newProps, baseProps));
for (var propName in Component)
void 0 === newProps[propName] &&
(newProps[propName] = Component[propName]);
@@ -9770,7 +9770,7 @@ var devToolsConfig$jscomp$inline_1078 = {
throw Error("TestRenderer does not support findFiberByHostInstance()");
},
bundleType: 0,
version: "19.0.0-canary-aa699661",
version: "19.0.0-canary-461e8e8d",
rendererPackageName: "react-test-renderer"
};
(function (internals) {
@@ -9814,7 +9814,7 @@ var devToolsConfig$jscomp$inline_1078 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "19.0.0-canary-aa699661"
reconcilerVersion: "19.0.0-canary-461e8e8d"
});
exports._Scheduler = Scheduler;
exports.act = act;
@@ -1 +1 @@
f33a6b69c6cb406ea0cc51d07bc4d3fd2d8d8744
bfd8da807c75a2d123627415f9eaf2d36ac3ed6a
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<5dd386bf9cd76540dc618bfac3e54671>>
* @generated SignedSource<<4a4d1580791e4b04df69f1d39838d86e>>
*/
"use strict";
@@ -16552,7 +16552,7 @@ to return true:wantsResponderID| |
// remove this extra check.
alreadyResolvedDefaultProps
) {
var newProps = baseProps; // Resolve default props. Taken from old JSX runtime, where this used to live.
var newProps = baseProps;
var defaultProps = Component.defaultProps;
@@ -16561,11 +16561,15 @@ to return true:wantsResponderID| |
// default props here in the reconciler, rather than in the JSX runtime.
(disableDefaultPropsExceptForClasses || !alreadyResolvedDefaultProps)
) {
newProps = assign({}, newProps, baseProps);
// We may have already copied the props object above to remove ref. If so,
// we can modify that. Otherwise, copy the props object with Object.assign.
if (newProps === baseProps) {
newProps = assign({}, newProps, baseProps);
} // Taken from old JSX runtime, where this used to live.
for (var propName in defaultProps) {
if (newProps[propName] === undefined) {
newProps[propName] = defaultProps[propName];
for (var _propName in defaultProps) {
if (newProps[_propName] === undefined) {
newProps[_propName] = defaultProps[_propName];
}
}
}
@@ -30314,7 +30318,7 @@ to return true:wantsResponderID| |
return root;
}
var ReactVersion = "19.0.0-canary-2c2952e8";
var ReactVersion = "19.0.0-canary-86741a5e";
/*
* The `'' + value` pattern (used in perf-sensitive code) throws for Symbol
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<54298e069f406267149c6223a3e091da>>
* @generated SignedSource<<40b9e8d1940ea7c4aa128e958d245bc0>>
*/
"use strict";
@@ -5018,7 +5018,7 @@ function resolveClassComponentProps(
(Component = Component.defaultProps) &&
(disableDefaultPropsExceptForClasses || !alreadyResolvedDefaultProps)
) {
newProps = assign({}, newProps, baseProps);
newProps === baseProps && (newProps = assign({}, newProps, baseProps));
for (var propName in Component)
void 0 === newProps[propName] &&
(newProps[propName] = Component[propName]);
@@ -10584,7 +10584,7 @@ var roots = new Map(),
devToolsConfig$jscomp$inline_1095 = {
findFiberByHostInstance: getInstanceFromNode,
bundleType: 0,
version: "19.0.0-canary-dd9880b4",
version: "19.0.0-canary-01f2d6f5",
rendererPackageName: "react-native-renderer",
rendererConfig: {
getInspectorDataForInstance: getInspectorDataForInstance,
@@ -10627,7 +10627,7 @@ var internals$jscomp$inline_1364 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "19.0.0-canary-dd9880b4"
reconcilerVersion: "19.0.0-canary-01f2d6f5"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_1365 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<abdef96f99146c2621cf22ff704541f5>>
* @generated SignedSource<<20b7d465c184525ed91fa85c2d27663d>>
*/
"use strict";
@@ -5210,7 +5210,7 @@ function resolveClassComponentProps(
(Component = Component.defaultProps) &&
(disableDefaultPropsExceptForClasses || !alreadyResolvedDefaultProps)
) {
newProps = assign({}, newProps, baseProps);
newProps === baseProps && (newProps = assign({}, newProps, baseProps));
for (var propName in Component)
void 0 === newProps[propName] &&
(newProps[propName] = Component[propName]);
@@ -11289,7 +11289,7 @@ var roots = new Map(),
devToolsConfig$jscomp$inline_1177 = {
findFiberByHostInstance: getInstanceFromNode,
bundleType: 0,
version: "19.0.0-canary-da67beca",
version: "19.0.0-canary-4fe4467c",
rendererPackageName: "react-native-renderer",
rendererConfig: {
getInspectorDataForInstance: getInspectorDataForInstance,
@@ -11345,7 +11345,7 @@ var roots = new Map(),
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "19.0.0-canary-da67beca"
reconcilerVersion: "19.0.0-canary-4fe4467c"
});
exports.createPortal = function (children, containerTag) {
return createPortal$1(
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<50a9b99ec068577f4323f59c87924a6b>>
* @generated SignedSource<<c73a551f4a3130c37086d7107a16668b>>
*/
"use strict";
@@ -16823,7 +16823,7 @@ to return true:wantsResponderID| |
// remove this extra check.
alreadyResolvedDefaultProps
) {
var newProps = baseProps; // Resolve default props. Taken from old JSX runtime, where this used to live.
var newProps = baseProps;
var defaultProps = Component.defaultProps;
@@ -16832,11 +16832,15 @@ to return true:wantsResponderID| |
// default props here in the reconciler, rather than in the JSX runtime.
(disableDefaultPropsExceptForClasses || !alreadyResolvedDefaultProps)
) {
newProps = assign({}, newProps, baseProps);
// We may have already copied the props object above to remove ref. If so,
// we can modify that. Otherwise, copy the props object with Object.assign.
if (newProps === baseProps) {
newProps = assign({}, newProps, baseProps);
} // Taken from old JSX runtime, where this used to live.
for (var propName in defaultProps) {
if (newProps[propName] === undefined) {
newProps[propName] = defaultProps[propName];
for (var _propName in defaultProps) {
if (newProps[_propName] === undefined) {
newProps[_propName] = defaultProps[_propName];
}
}
}
@@ -30754,7 +30758,7 @@ to return true:wantsResponderID| |
return root;
}
var ReactVersion = "19.0.0-canary-6807d8d2";
var ReactVersion = "19.0.0-canary-4c6edcb1";
/*
* The `'' + value` pattern (used in perf-sensitive code) throws for Symbol
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<23b66786bd7f0bd71723c2bf074a88b0>>
* @generated SignedSource<<a975d416ac4c7f46931f4ff8e2183f5c>>
*/
"use strict";
@@ -5083,7 +5083,7 @@ function resolveClassComponentProps(
(Component = Component.defaultProps) &&
(disableDefaultPropsExceptForClasses || !alreadyResolvedDefaultProps)
) {
newProps = assign({}, newProps, baseProps);
newProps === baseProps && (newProps = assign({}, newProps, baseProps));
for (var propName in Component)
void 0 === newProps[propName] &&
(newProps[propName] = Component[propName]);
@@ -10800,7 +10800,7 @@ var roots = new Map(),
devToolsConfig$jscomp$inline_1162 = {
findFiberByHostInstance: getInstanceFromTag,
bundleType: 0,
version: "19.0.0-canary-8d422163",
version: "19.0.0-canary-bbe25df7",
rendererPackageName: "react-native-renderer",
rendererConfig: {
getInspectorDataForInstance: getInspectorDataForInstance,
@@ -10843,7 +10843,7 @@ var internals$jscomp$inline_1445 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "19.0.0-canary-8d422163"
reconcilerVersion: "19.0.0-canary-bbe25df7"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_1446 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<b334f048486473032d93217c6858a766>>
* @generated SignedSource<<4a679b19e322c1ae35a57c741538ab4c>>
*/
"use strict";
@@ -5275,7 +5275,7 @@ function resolveClassComponentProps(
(Component = Component.defaultProps) &&
(disableDefaultPropsExceptForClasses || !alreadyResolvedDefaultProps)
) {
newProps = assign({}, newProps, baseProps);
newProps === baseProps && (newProps = assign({}, newProps, baseProps));
for (var propName in Component)
void 0 === newProps[propName] &&
(newProps[propName] = Component[propName]);
@@ -11506,7 +11506,7 @@ var roots = new Map(),
devToolsConfig$jscomp$inline_1244 = {
findFiberByHostInstance: getInstanceFromTag,
bundleType: 0,
version: "19.0.0-canary-596ee199",
version: "19.0.0-canary-d2e200b3",
rendererPackageName: "react-native-renderer",
rendererConfig: {
getInspectorDataForInstance: getInspectorDataForInstance,
@@ -11562,7 +11562,7 @@ var roots = new Map(),
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "19.0.0-canary-596ee199"
reconcilerVersion: "19.0.0-canary-d2e200b3"
});
exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = {
computeComponentStackForErrorReporting: function (reactTag) {