Clean up feature flag preventShadowTreeCommitExhaustionWithLocking (#52791)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52791

Changelog: [internal]

This cleans up this feature flag as it doesn't work as intended. We'll try another approach with a different flag instead.

Reviewed By: sammy-SC

Differential Revision: D78815892

fbshipit-source-id: 4c651a3a225de9cfb54d00346343c7f2e3bea1d5
This commit is contained in:
Rubén Norte
2025-07-28 11:52:56 +01:00
committed by Nicola Corti
parent 3695258eed
commit 255bf8bb3e
24 changed files with 48 additions and 194 deletions
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<f5f8c15a68610c9453d4085626effee2>>
* @generated SignedSource<<a4a7c66f4603fc6a56018aba12c942ee>>
*/
/**
@@ -312,12 +312,6 @@ public object ReactNativeFeatureFlags {
@JvmStatic
public fun preparedTextCacheSize(): Double = accessor.preparedTextCacheSize()
/**
* Enables a new mechanism in ShadowTree to prevent problems caused by multiple threads trying to commit concurrently. If a thread tries to commit a few times unsuccessfully, it will acquire a lock and try again.
*/
@JvmStatic
public fun preventShadowTreeCommitExhaustionWithLocking(): Boolean = accessor.preventShadowTreeCommitExhaustionWithLocking()
/**
* Enables storing js caller stack when creating promise in native module. This is useful in case of Promise rejection and tracing the cause.
*/
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<773ddcede573164ba82db671341ddc3f>>
* @generated SignedSource<<9b6d83d6ea0acbc13bce19d869699079>>
*/
/**
@@ -67,7 +67,6 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null
private var preparedTextCacheSizeCache: Double? = null
private var preventShadowTreeCommitExhaustionWithLockingCache: Boolean? = null
private var traceTurboModulePromiseRejectionsOnAndroidCache: Boolean? = null
private var updateRuntimeShadowNodeReferencesOnCommitCache: Boolean? = null
private var useAlwaysAvailableJSErrorHandlingCache: Boolean? = null
@@ -503,15 +502,6 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
return cached
}
override fun preventShadowTreeCommitExhaustionWithLocking(): Boolean {
var cached = preventShadowTreeCommitExhaustionWithLockingCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.preventShadowTreeCommitExhaustionWithLocking()
preventShadowTreeCommitExhaustionWithLockingCache = cached
}
return cached
}
override fun traceTurboModulePromiseRejectionsOnAndroid(): Boolean {
var cached = traceTurboModulePromiseRejectionsOnAndroidCache
if (cached == null) {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<96fca46813d841eb7f4d043010513999>>
* @generated SignedSource<<75760457dea789ab0951d3a22be3341c>>
*/
/**
@@ -122,8 +122,6 @@ public object ReactNativeFeatureFlagsCxxInterop {
@DoNotStrip @JvmStatic public external fun preparedTextCacheSize(): Double
@DoNotStrip @JvmStatic public external fun preventShadowTreeCommitExhaustionWithLocking(): Boolean
@DoNotStrip @JvmStatic public external fun traceTurboModulePromiseRejectionsOnAndroid(): Boolean
@DoNotStrip @JvmStatic public external fun updateRuntimeShadowNodeReferencesOnCommit(): Boolean
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<8ebd61411e0e0ac8c8b307cf803f1206>>
* @generated SignedSource<<48fa8921cc2947a713974c9926e1d806>>
*/
/**
@@ -117,8 +117,6 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
override fun preparedTextCacheSize(): Double = 200.0
override fun preventShadowTreeCommitExhaustionWithLocking(): Boolean = false
override fun traceTurboModulePromiseRejectionsOnAndroid(): Boolean = false
override fun updateRuntimeShadowNodeReferencesOnCommit(): Boolean = false
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<a7e62fa950e2716e664e7f6d30d4c941>>
* @generated SignedSource<<356261385b837def94ac5a4ca7ffd05d>>
*/
/**
@@ -71,7 +71,6 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
private var hideOffscreenVirtualViewsOnIOSCache: Boolean? = null
private var preparedTextCacheSizeCache: Double? = null
private var preventShadowTreeCommitExhaustionWithLockingCache: Boolean? = null
private var traceTurboModulePromiseRejectionsOnAndroidCache: Boolean? = null
private var updateRuntimeShadowNodeReferencesOnCommitCache: Boolean? = null
private var useAlwaysAvailableJSErrorHandlingCache: Boolean? = null
@@ -554,16 +553,6 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
return cached
}
override fun preventShadowTreeCommitExhaustionWithLocking(): Boolean {
var cached = preventShadowTreeCommitExhaustionWithLockingCache
if (cached == null) {
cached = currentProvider.preventShadowTreeCommitExhaustionWithLocking()
accessedFeatureFlags.add("preventShadowTreeCommitExhaustionWithLocking")
preventShadowTreeCommitExhaustionWithLockingCache = cached
}
return cached
}
override fun traceTurboModulePromiseRejectionsOnAndroid(): Boolean {
var cached = traceTurboModulePromiseRejectionsOnAndroidCache
if (cached == null) {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<93aab733661b558c1701b728c18b3d00>>
* @generated SignedSource<<c8b19934d19d6b4514a0395edecb1330>>
*/
/**
@@ -23,5 +23,5 @@ public open class ReactNativeFeatureFlagsOverrides_RNOSS_Experimental_Android :
// We could use JNI to get the defaults from C++,
// but that is more expensive than just duplicating the defaults here.
override fun preventShadowTreeCommitExhaustionWithLocking(): Boolean = true
}
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<f3b9aa1ed32aa3e013e16d4abb10b9cf>>
* @generated SignedSource<<8abf9bfb81265ae0c840457eb6c199bd>>
*/
/**
@@ -117,8 +117,6 @@ public interface ReactNativeFeatureFlagsProvider {
@DoNotStrip public fun preparedTextCacheSize(): Double
@DoNotStrip public fun preventShadowTreeCommitExhaustionWithLocking(): Boolean
@DoNotStrip public fun traceTurboModulePromiseRejectionsOnAndroid(): Boolean
@DoNotStrip public fun updateRuntimeShadowNodeReferencesOnCommit(): Boolean
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<7fac1c2c0c3ce131442319925e4231dc>>
* @generated SignedSource<<5effd7d4ac8034424144ea68c82b61a7>>
*/
/**
@@ -321,12 +321,6 @@ class ReactNativeFeatureFlagsJavaProvider
return method(javaProvider_);
}
bool preventShadowTreeCommitExhaustionWithLocking() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("preventShadowTreeCommitExhaustionWithLocking");
return method(javaProvider_);
}
bool traceTurboModulePromiseRejectionsOnAndroid() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("traceTurboModulePromiseRejectionsOnAndroid");
@@ -632,11 +626,6 @@ double JReactNativeFeatureFlagsCxxInterop::preparedTextCacheSize(
return ReactNativeFeatureFlags::preparedTextCacheSize();
}
bool JReactNativeFeatureFlagsCxxInterop::preventShadowTreeCommitExhaustionWithLocking(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::preventShadowTreeCommitExhaustionWithLocking();
}
bool JReactNativeFeatureFlagsCxxInterop::traceTurboModulePromiseRejectionsOnAndroid(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::traceTurboModulePromiseRejectionsOnAndroid();
@@ -864,9 +853,6 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
makeNativeMethod(
"preparedTextCacheSize",
JReactNativeFeatureFlagsCxxInterop::preparedTextCacheSize),
makeNativeMethod(
"preventShadowTreeCommitExhaustionWithLocking",
JReactNativeFeatureFlagsCxxInterop::preventShadowTreeCommitExhaustionWithLocking),
makeNativeMethod(
"traceTurboModulePromiseRejectionsOnAndroid",
JReactNativeFeatureFlagsCxxInterop::traceTurboModulePromiseRejectionsOnAndroid),
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<07daae0284829d56b7eaa330b1973e02>>
* @generated SignedSource<<f7bf09b9287dc649901b99ca3f250c28>>
*/
/**
@@ -171,9 +171,6 @@ class JReactNativeFeatureFlagsCxxInterop
static double preparedTextCacheSize(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static bool preventShadowTreeCommitExhaustionWithLocking(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static bool traceTurboModulePromiseRejectionsOnAndroid(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<0179ba45718903d6fec6dcc19b0e1aaa>>
* @generated SignedSource<<20c25bf5541e37cd5c918684925726df>>
*/
/**
@@ -214,10 +214,6 @@ double ReactNativeFeatureFlags::preparedTextCacheSize() {
return getAccessor().preparedTextCacheSize();
}
bool ReactNativeFeatureFlags::preventShadowTreeCommitExhaustionWithLocking() {
return getAccessor().preventShadowTreeCommitExhaustionWithLocking();
}
bool ReactNativeFeatureFlags::traceTurboModulePromiseRejectionsOnAndroid() {
return getAccessor().traceTurboModulePromiseRejectionsOnAndroid();
}
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<5055890d2cb2fb46a940f8308f014f0b>>
* @generated SignedSource<<20809734183aa7bfd7aad9b8d01ea080>>
*/
/**
@@ -274,11 +274,6 @@ class ReactNativeFeatureFlags {
*/
RN_EXPORT static double preparedTextCacheSize();
/**
* Enables a new mechanism in ShadowTree to prevent problems caused by multiple threads trying to commit concurrently. If a thread tries to commit a few times unsuccessfully, it will acquire a lock and try again.
*/
RN_EXPORT static bool preventShadowTreeCommitExhaustionWithLocking();
/**
* Enables storing js caller stack when creating promise in native module. This is useful in case of Promise rejection and tracing the cause.
*/
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<ea72f787f16b0c96ad745e82067591a9>>
* @generated SignedSource<<59ec29e038344c52eaa10845efc5240b>>
*/
/**
@@ -875,24 +875,6 @@ double ReactNativeFeatureFlagsAccessor::preparedTextCacheSize() {
return flagValue.value();
}
bool ReactNativeFeatureFlagsAccessor::preventShadowTreeCommitExhaustionWithLocking() {
auto flagValue = preventShadowTreeCommitExhaustionWithLocking_.load();
if (!flagValue.has_value()) {
// This block is not exclusive but it is not necessary.
// If multiple threads try to initialize the feature flag, we would only
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(47, "preventShadowTreeCommitExhaustionWithLocking");
flagValue = currentProvider_->preventShadowTreeCommitExhaustionWithLocking();
preventShadowTreeCommitExhaustionWithLocking_ = flagValue;
}
return flagValue.value();
}
bool ReactNativeFeatureFlagsAccessor::traceTurboModulePromiseRejectionsOnAndroid() {
auto flagValue = traceTurboModulePromiseRejectionsOnAndroid_.load();
@@ -902,7 +884,7 @@ bool ReactNativeFeatureFlagsAccessor::traceTurboModulePromiseRejectionsOnAndroid
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(48, "traceTurboModulePromiseRejectionsOnAndroid");
markFlagAsAccessed(47, "traceTurboModulePromiseRejectionsOnAndroid");
flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid();
traceTurboModulePromiseRejectionsOnAndroid_ = flagValue;
@@ -920,7 +902,7 @@ bool ReactNativeFeatureFlagsAccessor::updateRuntimeShadowNodeReferencesOnCommit(
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(49, "updateRuntimeShadowNodeReferencesOnCommit");
markFlagAsAccessed(48, "updateRuntimeShadowNodeReferencesOnCommit");
flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommit();
updateRuntimeShadowNodeReferencesOnCommit_ = flagValue;
@@ -938,7 +920,7 @@ bool ReactNativeFeatureFlagsAccessor::useAlwaysAvailableJSErrorHandling() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(50, "useAlwaysAvailableJSErrorHandling");
markFlagAsAccessed(49, "useAlwaysAvailableJSErrorHandling");
flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling();
useAlwaysAvailableJSErrorHandling_ = flagValue;
@@ -956,7 +938,7 @@ bool ReactNativeFeatureFlagsAccessor::useFabricInterop() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(51, "useFabricInterop");
markFlagAsAccessed(50, "useFabricInterop");
flagValue = currentProvider_->useFabricInterop();
useFabricInterop_ = flagValue;
@@ -974,7 +956,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(52, "useNativeViewConfigsInBridgelessMode");
markFlagAsAccessed(51, "useNativeViewConfigsInBridgelessMode");
flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode();
useNativeViewConfigsInBridgelessMode_ = flagValue;
@@ -992,7 +974,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimizedEventBatchingOnAndroid() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(53, "useOptimizedEventBatchingOnAndroid");
markFlagAsAccessed(52, "useOptimizedEventBatchingOnAndroid");
flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid();
useOptimizedEventBatchingOnAndroid_ = flagValue;
@@ -1010,7 +992,7 @@ bool ReactNativeFeatureFlagsAccessor::useRawPropsJsiValue() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(54, "useRawPropsJsiValue");
markFlagAsAccessed(53, "useRawPropsJsiValue");
flagValue = currentProvider_->useRawPropsJsiValue();
useRawPropsJsiValue_ = flagValue;
@@ -1028,7 +1010,7 @@ bool ReactNativeFeatureFlagsAccessor::useShadowNodeStateOnClone() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(55, "useShadowNodeStateOnClone");
markFlagAsAccessed(54, "useShadowNodeStateOnClone");
flagValue = currentProvider_->useShadowNodeStateOnClone();
useShadowNodeStateOnClone_ = flagValue;
@@ -1046,7 +1028,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModuleInterop() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(56, "useTurboModuleInterop");
markFlagAsAccessed(55, "useTurboModuleInterop");
flagValue = currentProvider_->useTurboModuleInterop();
useTurboModuleInterop_ = flagValue;
@@ -1064,7 +1046,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModules() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(57, "useTurboModules");
markFlagAsAccessed(56, "useTurboModules");
flagValue = currentProvider_->useTurboModules();
useTurboModules_ = flagValue;
@@ -1082,7 +1064,7 @@ double ReactNativeFeatureFlagsAccessor::virtualViewPrerenderRatio() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(58, "virtualViewPrerenderRatio");
markFlagAsAccessed(57, "virtualViewPrerenderRatio");
flagValue = currentProvider_->virtualViewPrerenderRatio();
virtualViewPrerenderRatio_ = flagValue;
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<5ed90d5ed1a03a16f551cd1cf6cbdeb3>>
* @generated SignedSource<<043e1a56e7a302fbca38151b5d079616>>
*/
/**
@@ -79,7 +79,6 @@ class ReactNativeFeatureFlagsAccessor {
bool fuseboxNetworkInspectionEnabled();
bool hideOffscreenVirtualViewsOnIOS();
double preparedTextCacheSize();
bool preventShadowTreeCommitExhaustionWithLocking();
bool traceTurboModulePromiseRejectionsOnAndroid();
bool updateRuntimeShadowNodeReferencesOnCommit();
bool useAlwaysAvailableJSErrorHandling();
@@ -102,7 +101,7 @@ class ReactNativeFeatureFlagsAccessor {
std::unique_ptr<ReactNativeFeatureFlagsProvider> currentProvider_;
bool wasOverridden_;
std::array<std::atomic<const char*>, 59> accessedFeatureFlags_;
std::array<std::atomic<const char*>, 58> accessedFeatureFlags_;
std::atomic<std::optional<bool>> commonTestFlag_;
std::atomic<std::optional<bool>> animatedShouldSignalBatch_;
@@ -151,7 +150,6 @@ class ReactNativeFeatureFlagsAccessor {
std::atomic<std::optional<bool>> fuseboxNetworkInspectionEnabled_;
std::atomic<std::optional<bool>> hideOffscreenVirtualViewsOnIOS_;
std::atomic<std::optional<double>> preparedTextCacheSize_;
std::atomic<std::optional<bool>> preventShadowTreeCommitExhaustionWithLocking_;
std::atomic<std::optional<bool>> traceTurboModulePromiseRejectionsOnAndroid_;
std::atomic<std::optional<bool>> updateRuntimeShadowNodeReferencesOnCommit_;
std::atomic<std::optional<bool>> useAlwaysAvailableJSErrorHandling_;
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<d9fdce0b92313eff37d7146d25b80d4a>>
* @generated SignedSource<<7b5caffd8f748384aa32ed6e153ee9c1>>
*/
/**
@@ -215,10 +215,6 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
return 200.0;
}
bool preventShadowTreeCommitExhaustionWithLocking() override {
return false;
}
bool traceTurboModulePromiseRejectionsOnAndroid() override {
return false;
}
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<ae01d3b37b41ff2ef7fdc26977954b7e>>
* @generated SignedSource<<e78150be120e3fdf02f9420abce23bfc>>
*/
/**
@@ -468,15 +468,6 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef
return ReactNativeFeatureFlagsDefaults::preparedTextCacheSize();
}
bool preventShadowTreeCommitExhaustionWithLocking() override {
auto value = values_["preventShadowTreeCommitExhaustionWithLocking"];
if (!value.isNull()) {
return value.getBool();
}
return ReactNativeFeatureFlagsDefaults::preventShadowTreeCommitExhaustionWithLocking();
}
bool traceTurboModulePromiseRejectionsOnAndroid() override {
auto value = values_["traceTurboModulePromiseRejectionsOnAndroid"];
if (!value.isNull()) {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<16c5fdf431579bbfd454a28c06f28c41>>
* @generated SignedSource<<1de02178e1be302bb4b19501950b260a>>
*/
/**
@@ -27,9 +27,7 @@ class ReactNativeFeatureFlagsOverridesOSSExperimental : public ReactNativeFeatur
public:
ReactNativeFeatureFlagsOverridesOSSExperimental() = default;
bool preventShadowTreeCommitExhaustionWithLocking() override {
return true;
}
};
} // namespace facebook::react
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<bf06b42a9dfc43a3bfe4e8e59587ea71>>
* @generated SignedSource<<bdd21870bf567207ad837eb33ae4ca5b>>
*/
/**
@@ -72,7 +72,6 @@ class ReactNativeFeatureFlagsProvider {
virtual bool fuseboxNetworkInspectionEnabled() = 0;
virtual bool hideOffscreenVirtualViewsOnIOS() = 0;
virtual double preparedTextCacheSize() = 0;
virtual bool preventShadowTreeCommitExhaustionWithLocking() = 0;
virtual bool traceTurboModulePromiseRejectionsOnAndroid() = 0;
virtual bool updateRuntimeShadowNodeReferencesOnCommit() = 0;
virtual bool useAlwaysAvailableJSErrorHandling() = 0;
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<b6c1cb535484fe2a5ff839ca2a9ece46>>
* @generated SignedSource<<aebe2ba2618903a0ac2df06f18df8c75>>
*/
/**
@@ -279,11 +279,6 @@ double NativeReactNativeFeatureFlags::preparedTextCacheSize(
return ReactNativeFeatureFlags::preparedTextCacheSize();
}
bool NativeReactNativeFeatureFlags::preventShadowTreeCommitExhaustionWithLocking(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::preventShadowTreeCommitExhaustionWithLocking();
}
bool NativeReactNativeFeatureFlags::traceTurboModulePromiseRejectionsOnAndroid(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::traceTurboModulePromiseRejectionsOnAndroid();
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<03ab35c55476b69046e67235b66533a0>>
* @generated SignedSource<<f3336bad491a91abb3af7e8fcd7e5938>>
*/
/**
@@ -130,8 +130,6 @@ class NativeReactNativeFeatureFlags
double preparedTextCacheSize(jsi::Runtime& runtime);
bool preventShadowTreeCommitExhaustionWithLocking(jsi::Runtime& runtime);
bool traceTurboModulePromiseRejectionsOnAndroid(jsi::Runtime& runtime);
bool updateRuntimeShadowNodeReferencesOnCommit(jsi::Runtime& runtime);
@@ -25,10 +25,6 @@ namespace facebook::react {
using CommitStatus = ShadowTree::CommitStatus;
using CommitMode = ShadowTree::CommitMode;
namespace {
const int MAX_COMMIT_ATTEMPTS_BEFORE_LOCKING = 3;
}
/*
* Generates (possibly) a new tree where all nodes with non-obsolete `State`
* objects. If all `State` objects in the tree are not obsolete for the moment
@@ -245,39 +241,23 @@ CommitStatus ShadowTree::commit(
const CommitOptions& commitOptions) const {
[[maybe_unused]] int attempts = 0;
if (ReactNativeFeatureFlags::preventShadowTreeCommitExhaustionWithLocking()) {
while (attempts < MAX_COMMIT_ATTEMPTS_BEFORE_LOCKING) {
auto status = tryCommit(transaction, commitOptions);
if (status != CommitStatus::Failed) {
return status;
}
attempts++;
while (true) {
attempts++;
auto status = tryCommit(transaction, commitOptions);
if (status != CommitStatus::Failed) {
return status;
}
{
std::unique_lock lock(commitMutex_);
return tryCommit(transaction, commitOptions, true);
}
} else {
while (true) {
attempts++;
auto status = tryCommit(transaction, commitOptions);
if (status != CommitStatus::Failed) {
return status;
}
// After multiple attempts, we failed to commit the transaction.
// Something internally went terribly wrong.
react_native_assert(attempts < 1024);
}
// After multiple attempts, we failed to commit the transaction.
// Something internally went terribly wrong.
react_native_assert(attempts < 1024);
}
}
CommitStatus ShadowTree::tryCommit(
const ShadowTreeCommitTransaction& transaction,
const CommitOptions& commitOptions,
bool hasLocked) const {
const CommitOptions& commitOptions) const {
TraceSection s("ShadowTree::commit");
auto telemetry = TransactionTelemetry{};
@@ -289,10 +269,7 @@ CommitStatus ShadowTree::tryCommit(
{
// Reading `currentRevision_` in shared manner.
std::shared_lock lock(commitMutex_, std::defer_lock);
if (!hasLocked) {
lock.lock();
}
std::shared_lock lock(commitMutex_);
commitMode = commitMode_;
oldRevision = currentRevision_;
}
@@ -333,10 +310,7 @@ CommitStatus ShadowTree::tryCommit(
{
// Updating `currentRevision_` in unique manner if it hasn't changed.
std::unique_lock lock(commitMutex_, std::defer_lock);
if (!hasLocked) {
lock.lock();
}
std::unique_lock lock(commitMutex_);
if (currentRevision_.number != oldRevision.number) {
return CommitStatus::Failed;
@@ -111,8 +111,7 @@ class ShadowTree final {
*/
CommitStatus tryCommit(
const ShadowTreeCommitTransaction& transaction,
const CommitOptions& commitOptions,
bool hasLocked = false) const;
const CommitOptions& commitOptions) const;
/*
* Calls `tryCommit` in a loop until it finishes successfully.
@@ -543,17 +543,6 @@ const definitions: FeatureFlagDefinitions = {
},
ossReleaseStage: 'none',
},
preventShadowTreeCommitExhaustionWithLocking: {
defaultValue: false,
metadata: {
dateAdded: '2025-07-14',
description:
'Enables a new mechanism in ShadowTree to prevent problems caused by multiple threads trying to commit concurrently. If a thread tries to commit a few times unsuccessfully, it will acquire a lock and try again.',
expectedReleaseValue: true,
purpose: 'experimentation',
},
ossReleaseStage: 'experimental',
},
traceTurboModulePromiseRejectionsOnAndroid: {
defaultValue: false,
metadata: {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<595a51e39658c12aab12032f7b928615>>
* @generated SignedSource<<b75fccb46a36b07c692d890f0659f9a3>>
* @flow strict
* @noformat
*/
@@ -98,7 +98,6 @@ export type ReactNativeFeatureFlags = $ReadOnly<{
fuseboxNetworkInspectionEnabled: Getter<boolean>,
hideOffscreenVirtualViewsOnIOS: Getter<boolean>,
preparedTextCacheSize: Getter<number>,
preventShadowTreeCommitExhaustionWithLocking: Getter<boolean>,
traceTurboModulePromiseRejectionsOnAndroid: Getter<boolean>,
updateRuntimeShadowNodeReferencesOnCommit: Getter<boolean>,
useAlwaysAvailableJSErrorHandling: Getter<boolean>,
@@ -384,10 +383,6 @@ export const hideOffscreenVirtualViewsOnIOS: Getter<boolean> = createNativeFlagG
* Number cached PreparedLayouts in TextLayoutManager cache
*/
export const preparedTextCacheSize: Getter<number> = createNativeFlagGetter('preparedTextCacheSize', 200);
/**
* Enables a new mechanism in ShadowTree to prevent problems caused by multiple threads trying to commit concurrently. If a thread tries to commit a few times unsuccessfully, it will acquire a lock and try again.
*/
export const preventShadowTreeCommitExhaustionWithLocking: Getter<boolean> = createNativeFlagGetter('preventShadowTreeCommitExhaustionWithLocking', false);
/**
* Enables storing js caller stack when creating promise in native module. This is useful in case of Promise rejection and tracing the cause.
*/
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<9d6574da819c190bed0458559c66a089>>
* @generated SignedSource<<55c1f0223345b5680bbdd888a358f210>>
* @flow strict
* @noformat
*/
@@ -72,7 +72,6 @@ export interface Spec extends TurboModule {
+fuseboxNetworkInspectionEnabled?: () => boolean;
+hideOffscreenVirtualViewsOnIOS?: () => boolean;
+preparedTextCacheSize?: () => number;
+preventShadowTreeCommitExhaustionWithLocking?: () => boolean;
+traceTurboModulePromiseRejectionsOnAndroid?: () => boolean;
+updateRuntimeShadowNodeReferencesOnCommit?: () => boolean;
+useAlwaysAvailableJSErrorHandling?: () => boolean;