From 21a23ad9c8732c0713f9c57565f67f03f3fd2a11 Mon Sep 17 00:00:00 2001 From: Sebastian Sebbie Silbermann Date: Wed, 15 Oct 2025 19:13:44 +0200 Subject: [PATCH 1/3] Only capture stacks for up to 10 frames for Owner Stacks --- packages/react/src/jsx/ReactJSXElement.js | 118 +++++++++++++++++++--- 1 file changed, 102 insertions(+), 16 deletions(-) diff --git a/packages/react/src/jsx/ReactJSXElement.js b/packages/react/src/jsx/ReactJSXElement.js index a77c4c3cdbf10..23622f8463255 100644 --- a/packages/react/src/jsx/ReactJSXElement.js +++ b/packages/react/src/jsx/ReactJSXElement.js @@ -57,6 +57,31 @@ function getOwner() { return null; } +// v8 (Chromium, Node.js) defaults to 10 +// SpiderMonkey (Firefox) does not support Error.stackTraceLimit +// JSC (Safari) defaults to 100 +// The lower the limit, the more likely we'll not reach react_stack_bottom_frame +// The higher the limit, the slower Error() is when not inspecting with a debugger. +// When inspecting with a debugger, Error.stackTraceLimit has no impact on Error() performance (in v8). +const ownerStackTraceLimit = 10; +/** try-catch setting `Error.stackTraceLimit` still in case the descriptor is overwritten later. */ +let supportsSettingStackTraceLimit = false; +if (__DEV__) { + const descriptor = Object.getOwnPropertyDescriptor(Error, 'stackTraceLimit'); + if (descriptor !== undefined) { + if (typeof descriptor.set === 'function') { + const previousStackTraceLimit = Error.stackTraceLimit; + try { + Error.stackTraceLimit = 1; + Error.stackTraceLimit = previousStackTraceLimit; + supportsSettingStackTraceLimit = true; + } catch {} + } else { + supportsSettingStackTraceLimit = descriptor.writable; + } + } +} + /** @noinline */ function UnknownOwner() { /** @noinline */ @@ -352,15 +377,31 @@ export function jsxProdSignatureRunningInDevWithDynamicChildren( const trackActualOwner = __DEV__ && ReactSharedInternals.recentlyCreatedOwnerStacks++ < ownerStackLimit; + let debugStackDEV = false; + if (__DEV__) { + if (trackActualOwner) { + if (supportsSettingStackTraceLimit) { + try { + const previousStackTraceLimit = Error.stackTraceLimit; + Error.stackTraceLimit = ownerStackTraceLimit; + debugStackDEV = Error('react-stack-top-frame'); + Error.stackTraceLimit = previousStackTraceLimit; + } catch {} + } + if (!debugStackDEV) { + debugStackDEV = Error('react-stack-top-frame'); + } + } else { + debugStackDEV = unknownOwnerDebugStack; + } + } + return jsxDEVImpl( type, config, maybeKey, isStaticChildren, - __DEV__ && - (trackActualOwner - ? Error('react-stack-top-frame') - : unknownOwnerDebugStack), + debugStackDEV, __DEV__ && (trackActualOwner ? createTask(getTaskName(type)) @@ -379,15 +420,30 @@ export function jsxProdSignatureRunningInDevWithStaticChildren( const trackActualOwner = __DEV__ && ReactSharedInternals.recentlyCreatedOwnerStacks++ < ownerStackLimit; + let debugStackDEV = false; + if (__DEV__) { + if (trackActualOwner) { + if (supportsSettingStackTraceLimit) { + try { + const previousStackTraceLimit = Error.stackTraceLimit; + Error.stackTraceLimit = ownerStackTraceLimit; + debugStackDEV = Error('react-stack-top-frame'); + Error.stackTraceLimit = previousStackTraceLimit; + } catch {} + } + if (!debugStackDEV) { + debugStackDEV = Error('react-stack-top-frame'); + } + } else { + debugStackDEV = unknownOwnerDebugStack; + } + } return jsxDEVImpl( type, config, maybeKey, isStaticChildren, - __DEV__ && - (trackActualOwner - ? Error('react-stack-top-frame') - : unknownOwnerDebugStack), + debugStackDEV, __DEV__ && (trackActualOwner ? createTask(getTaskName(type)) @@ -408,15 +464,30 @@ export function jsxDEV(type, config, maybeKey, isStaticChildren) { const trackActualOwner = __DEV__ && ReactSharedInternals.recentlyCreatedOwnerStacks++ < ownerStackLimit; + let debugStackDEV = false; + if (__DEV__) { + if (trackActualOwner) { + if (supportsSettingStackTraceLimit) { + try { + const previousStackTraceLimit = Error.stackTraceLimit; + Error.stackTraceLimit = ownerStackTraceLimit; + debugStackDEV = Error('react-stack-top-frame'); + Error.stackTraceLimit = previousStackTraceLimit; + } catch {} + } + if (!debugStackDEV) { + debugStackDEV = Error('react-stack-top-frame'); + } + } else { + debugStackDEV = unknownOwnerDebugStack; + } + } return jsxDEVImpl( type, config, maybeKey, isStaticChildren, - __DEV__ && - (trackActualOwner - ? Error('react-stack-top-frame') - : unknownOwnerDebugStack), + debugStackDEV, __DEV__ && (trackActualOwner ? createTask(getTaskName(type)) @@ -667,15 +738,30 @@ export function createElement(type, config, children) { const trackActualOwner = __DEV__ && ReactSharedInternals.recentlyCreatedOwnerStacks++ < ownerStackLimit; + let debugStackDEV = false; + if (__DEV__) { + if (trackActualOwner) { + if (supportsSettingStackTraceLimit) { + try { + const previousStackTraceLimit = Error.stackTraceLimit; + Error.stackTraceLimit = ownerStackTraceLimit; + debugStackDEV = Error('react-stack-top-frame'); + Error.stackTraceLimit = previousStackTraceLimit; + } catch {} + } + if (!debugStackDEV) { + debugStackDEV = Error('react-stack-top-frame'); + } + } else { + debugStackDEV = unknownOwnerDebugStack; + } + } return ReactElement( type, key, props, getOwner(), - __DEV__ && - (trackActualOwner - ? Error('react-stack-top-frame') - : unknownOwnerDebugStack), + debugStackDEV, __DEV__ && (trackActualOwner ? createTask(getTaskName(type)) From da0e07cf29ff95ee6de6dfc4c06adbc5f0db7bbf Mon Sep 17 00:00:00 2001 From: Sebastian Sebbie Silbermann Date: Thu, 16 Oct 2025 09:43:31 +0200 Subject: [PATCH 2/3] No try-catch --- packages/react/src/jsx/ReactJSXElement.js | 49 +++++++++-------------- 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/packages/react/src/jsx/ReactJSXElement.js b/packages/react/src/jsx/ReactJSXElement.js index 23622f8463255..84821f778c8ce 100644 --- a/packages/react/src/jsx/ReactJSXElement.js +++ b/packages/react/src/jsx/ReactJSXElement.js @@ -64,18 +64,15 @@ function getOwner() { // The higher the limit, the slower Error() is when not inspecting with a debugger. // When inspecting with a debugger, Error.stackTraceLimit has no impact on Error() performance (in v8). const ownerStackTraceLimit = 10; -/** try-catch setting `Error.stackTraceLimit` still in case the descriptor is overwritten later. */ let supportsSettingStackTraceLimit = false; if (__DEV__) { const descriptor = Object.getOwnPropertyDescriptor(Error, 'stackTraceLimit'); if (descriptor !== undefined) { if (typeof descriptor.set === 'function') { const previousStackTraceLimit = Error.stackTraceLimit; - try { - Error.stackTraceLimit = 1; - Error.stackTraceLimit = previousStackTraceLimit; - supportsSettingStackTraceLimit = true; - } catch {} + Error.stackTraceLimit = 1; + Error.stackTraceLimit = previousStackTraceLimit; + supportsSettingStackTraceLimit = true; } else { supportsSettingStackTraceLimit = descriptor.writable; } @@ -381,12 +378,10 @@ export function jsxProdSignatureRunningInDevWithDynamicChildren( if (__DEV__) { if (trackActualOwner) { if (supportsSettingStackTraceLimit) { - try { - const previousStackTraceLimit = Error.stackTraceLimit; - Error.stackTraceLimit = ownerStackTraceLimit; - debugStackDEV = Error('react-stack-top-frame'); - Error.stackTraceLimit = previousStackTraceLimit; - } catch {} + const previousStackTraceLimit = Error.stackTraceLimit; + Error.stackTraceLimit = ownerStackTraceLimit; + debugStackDEV = Error('react-stack-top-frame'); + Error.stackTraceLimit = previousStackTraceLimit; } if (!debugStackDEV) { debugStackDEV = Error('react-stack-top-frame'); @@ -424,12 +419,10 @@ export function jsxProdSignatureRunningInDevWithStaticChildren( if (__DEV__) { if (trackActualOwner) { if (supportsSettingStackTraceLimit) { - try { - const previousStackTraceLimit = Error.stackTraceLimit; - Error.stackTraceLimit = ownerStackTraceLimit; - debugStackDEV = Error('react-stack-top-frame'); - Error.stackTraceLimit = previousStackTraceLimit; - } catch {} + const previousStackTraceLimit = Error.stackTraceLimit; + Error.stackTraceLimit = ownerStackTraceLimit; + debugStackDEV = Error('react-stack-top-frame'); + Error.stackTraceLimit = previousStackTraceLimit; } if (!debugStackDEV) { debugStackDEV = Error('react-stack-top-frame'); @@ -468,12 +461,10 @@ export function jsxDEV(type, config, maybeKey, isStaticChildren) { if (__DEV__) { if (trackActualOwner) { if (supportsSettingStackTraceLimit) { - try { - const previousStackTraceLimit = Error.stackTraceLimit; - Error.stackTraceLimit = ownerStackTraceLimit; - debugStackDEV = Error('react-stack-top-frame'); - Error.stackTraceLimit = previousStackTraceLimit; - } catch {} + const previousStackTraceLimit = Error.stackTraceLimit; + Error.stackTraceLimit = ownerStackTraceLimit; + debugStackDEV = Error('react-stack-top-frame'); + Error.stackTraceLimit = previousStackTraceLimit; } if (!debugStackDEV) { debugStackDEV = Error('react-stack-top-frame'); @@ -742,12 +733,10 @@ export function createElement(type, config, children) { if (__DEV__) { if (trackActualOwner) { if (supportsSettingStackTraceLimit) { - try { - const previousStackTraceLimit = Error.stackTraceLimit; - Error.stackTraceLimit = ownerStackTraceLimit; - debugStackDEV = Error('react-stack-top-frame'); - Error.stackTraceLimit = previousStackTraceLimit; - } catch {} + const previousStackTraceLimit = Error.stackTraceLimit; + Error.stackTraceLimit = ownerStackTraceLimit; + debugStackDEV = Error('react-stack-top-frame'); + Error.stackTraceLimit = previousStackTraceLimit; } if (!debugStackDEV) { debugStackDEV = Error('react-stack-top-frame'); From d07263efc6accee2b4432ea1f9028be5bb6d3e0c Mon Sep 17 00:00:00 2001 From: Sebastian Sebbie Silbermann Date: Thu, 16 Oct 2025 09:47:21 +0200 Subject: [PATCH 3/3] Let it rip tv off --- packages/react/src/jsx/ReactJSXElement.js | 66 ++++++----------------- 1 file changed, 16 insertions(+), 50 deletions(-) diff --git a/packages/react/src/jsx/ReactJSXElement.js b/packages/react/src/jsx/ReactJSXElement.js index 84821f778c8ce..e23c998da511b 100644 --- a/packages/react/src/jsx/ReactJSXElement.js +++ b/packages/react/src/jsx/ReactJSXElement.js @@ -64,20 +64,6 @@ function getOwner() { // The higher the limit, the slower Error() is when not inspecting with a debugger. // When inspecting with a debugger, Error.stackTraceLimit has no impact on Error() performance (in v8). const ownerStackTraceLimit = 10; -let supportsSettingStackTraceLimit = false; -if (__DEV__) { - const descriptor = Object.getOwnPropertyDescriptor(Error, 'stackTraceLimit'); - if (descriptor !== undefined) { - if (typeof descriptor.set === 'function') { - const previousStackTraceLimit = Error.stackTraceLimit; - Error.stackTraceLimit = 1; - Error.stackTraceLimit = previousStackTraceLimit; - supportsSettingStackTraceLimit = true; - } else { - supportsSettingStackTraceLimit = descriptor.writable; - } - } -} /** @noinline */ function UnknownOwner() { @@ -377,15 +363,10 @@ export function jsxProdSignatureRunningInDevWithDynamicChildren( let debugStackDEV = false; if (__DEV__) { if (trackActualOwner) { - if (supportsSettingStackTraceLimit) { - const previousStackTraceLimit = Error.stackTraceLimit; - Error.stackTraceLimit = ownerStackTraceLimit; - debugStackDEV = Error('react-stack-top-frame'); - Error.stackTraceLimit = previousStackTraceLimit; - } - if (!debugStackDEV) { - debugStackDEV = Error('react-stack-top-frame'); - } + const previousStackTraceLimit = Error.stackTraceLimit; + Error.stackTraceLimit = ownerStackTraceLimit; + debugStackDEV = Error('react-stack-top-frame'); + Error.stackTraceLimit = previousStackTraceLimit; } else { debugStackDEV = unknownOwnerDebugStack; } @@ -418,15 +399,10 @@ export function jsxProdSignatureRunningInDevWithStaticChildren( let debugStackDEV = false; if (__DEV__) { if (trackActualOwner) { - if (supportsSettingStackTraceLimit) { - const previousStackTraceLimit = Error.stackTraceLimit; - Error.stackTraceLimit = ownerStackTraceLimit; - debugStackDEV = Error('react-stack-top-frame'); - Error.stackTraceLimit = previousStackTraceLimit; - } - if (!debugStackDEV) { - debugStackDEV = Error('react-stack-top-frame'); - } + const previousStackTraceLimit = Error.stackTraceLimit; + Error.stackTraceLimit = ownerStackTraceLimit; + debugStackDEV = Error('react-stack-top-frame'); + Error.stackTraceLimit = previousStackTraceLimit; } else { debugStackDEV = unknownOwnerDebugStack; } @@ -460,15 +436,10 @@ export function jsxDEV(type, config, maybeKey, isStaticChildren) { let debugStackDEV = false; if (__DEV__) { if (trackActualOwner) { - if (supportsSettingStackTraceLimit) { - const previousStackTraceLimit = Error.stackTraceLimit; - Error.stackTraceLimit = ownerStackTraceLimit; - debugStackDEV = Error('react-stack-top-frame'); - Error.stackTraceLimit = previousStackTraceLimit; - } - if (!debugStackDEV) { - debugStackDEV = Error('react-stack-top-frame'); - } + const previousStackTraceLimit = Error.stackTraceLimit; + Error.stackTraceLimit = ownerStackTraceLimit; + debugStackDEV = Error('react-stack-top-frame'); + Error.stackTraceLimit = previousStackTraceLimit; } else { debugStackDEV = unknownOwnerDebugStack; } @@ -732,15 +703,10 @@ export function createElement(type, config, children) { let debugStackDEV = false; if (__DEV__) { if (trackActualOwner) { - if (supportsSettingStackTraceLimit) { - const previousStackTraceLimit = Error.stackTraceLimit; - Error.stackTraceLimit = ownerStackTraceLimit; - debugStackDEV = Error('react-stack-top-frame'); - Error.stackTraceLimit = previousStackTraceLimit; - } - if (!debugStackDEV) { - debugStackDEV = Error('react-stack-top-frame'); - } + const previousStackTraceLimit = Error.stackTraceLimit; + Error.stackTraceLimit = ownerStackTraceLimit; + debugStackDEV = Error('react-stack-top-frame'); + Error.stackTraceLimit = previousStackTraceLimit; } else { debugStackDEV = unknownOwnerDebugStack; }