From 08d972d4cdf7c998a9a3a3570fe86a8e25a6d13c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Thu, 30 May 2024 08:19:25 -0700 Subject: [PATCH] Allow recursive calls to schedulerShouldRenderTransactions without deadlocks (#44725) Summary: Changelog: [internal] ## Context We're currently testing synchronous state updates in Fabric (committing shadow trees for state updates synchronously in the thread where they were dispatched, instead of always scheduling it in the JS thread). In these experiments we saw a problem caused by a recent change in the Android mounting layer (done to fix a problem with the Event Loop) where we were doing the mount operations inside a mutex lock. The problem is that we didn't have recursive commit+mount operations (because we were dispatching state updates in the JS thread) but now that we do we get a deadlock here. {F1659804385} These recursive commit+mount operations happen because it's possible to trigger state updates while we mount changes in the host platform (e.g.: we create the scroll view and we update the state to set the content offset). Those state updates trigger more mount operations, which deadlock in the mentioned place. ## Changes This fixes the described issue by restricting the lock only to access the list of pending operations, but not to apply them. In the current implementation, `mountingManager->executeMount` is protected by the lock, whereas in the new version it isn't (so it can be safely called recursively). The synchronization of the mount operations is done directly at the mounting layer on Android. Differential Revision: D57968936 --- .../featureflags/ReactNativeFeatureFlags.kt | 8 ++- .../ReactNativeFeatureFlagsCxxAccessor.kt | 12 +++- .../ReactNativeFeatureFlagsCxxInterop.kt | 4 +- .../ReactNativeFeatureFlagsDefaults.kt | 4 +- .../ReactNativeFeatureFlagsLocalAccessor.kt | 13 ++++- .../ReactNativeFeatureFlagsProvider.kt | 4 +- .../src/main/jni/react/fabric/Binding.cpp | 25 +++++++-- .../JReactNativeFeatureFlagsCxxInterop.cpp | 16 +++++- .../JReactNativeFeatureFlagsCxxInterop.h | 5 +- .../featureflags/ReactNativeFeatureFlags.cpp | 6 +- .../featureflags/ReactNativeFeatureFlags.h | 7 ++- .../ReactNativeFeatureFlagsAccessor.cpp | 56 ++++++++++++------- .../ReactNativeFeatureFlagsAccessor.h | 6 +- .../ReactNativeFeatureFlagsDefaults.h | 6 +- .../ReactNativeFeatureFlagsProvider.h | 3 +- .../NativeReactNativeFeatureFlags.cpp | 7 ++- .../NativeReactNativeFeatureFlags.h | 4 +- .../ReactNativeFeatureFlags.config.js | 5 ++ .../featureflags/ReactNativeFeatureFlags.js | 7 ++- .../specs/NativeReactNativeFeatureFlags.js | 3 +- 20 files changed, 160 insertions(+), 41 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt index 55215a12376339..48e065fd87b3df 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt @@ -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<<84f45a19bf93a62da7ce904a2682fc51>> + * @generated SignedSource<<4e30b8a42dfe7e041ecb30a386b54e50>> */ /** @@ -40,6 +40,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun allowCollapsableChildren(): Boolean = accessor.allowCollapsableChildren() + /** + * Adds support for recursively processing commits that mount synchronously (Android only). + */ + @JvmStatic + public fun allowRecursiveCommitsWithSynchronousMountOnAndroid(): Boolean = accessor.allowRecursiveCommitsWithSynchronousMountOnAndroid() + /** * When enabled, the RuntimeScheduler processing the event loop will batch all rendering updates and dispatch them together at the end of each iteration of the loop. */ diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt index a239ea008eea62..d4411cb4465beb 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt @@ -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<<2f84a5455d747e14324f7b79cbbdc763>> + * @generated SignedSource<<944fabed27a371ce2e1a86e367312c1f>> */ /** @@ -22,6 +22,7 @@ package com.facebook.react.internal.featureflags public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccessor { private var commonTestFlagCache: Boolean? = null private var allowCollapsableChildrenCache: Boolean? = null + private var allowRecursiveCommitsWithSynchronousMountOnAndroidCache: Boolean? = null private var batchRenderingUpdatesInEventLoopCache: Boolean? = null private var destroyFabricSurfacesInReactInstanceManagerCache: Boolean? = null private var enableBackgroundExecutorCache: Boolean? = null @@ -59,6 +60,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso return cached } + override fun allowRecursiveCommitsWithSynchronousMountOnAndroid(): Boolean { + var cached = allowRecursiveCommitsWithSynchronousMountOnAndroidCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.allowRecursiveCommitsWithSynchronousMountOnAndroid() + allowRecursiveCommitsWithSynchronousMountOnAndroidCache = cached + } + return cached + } + override fun batchRenderingUpdatesInEventLoop(): Boolean { var cached = batchRenderingUpdatesInEventLoopCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt index baa0a7304e17d4..32c41138a40f61 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt @@ -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<> + * @generated SignedSource<> */ /** @@ -32,6 +32,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun allowCollapsableChildren(): Boolean + @DoNotStrip @JvmStatic public external fun allowRecursiveCommitsWithSynchronousMountOnAndroid(): Boolean + @DoNotStrip @JvmStatic public external fun batchRenderingUpdatesInEventLoop(): Boolean @DoNotStrip @JvmStatic public external fun destroyFabricSurfacesInReactInstanceManager(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt index bc7acde645fac8..5c2f253babd658 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt @@ -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<<1ea3b574063dca0256494361423ce63e>> + * @generated SignedSource<> */ /** @@ -27,6 +27,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun allowCollapsableChildren(): Boolean = true + override fun allowRecursiveCommitsWithSynchronousMountOnAndroid(): Boolean = false + override fun batchRenderingUpdatesInEventLoop(): Boolean = false override fun destroyFabricSurfacesInReactInstanceManager(): Boolean = false diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt index 713fa0ce5c58e1..0a7fd0c8df5b69 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt @@ -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<> + * @generated SignedSource<<3b94757d58e6adb2bccf4ddfb86e2080>> */ /** @@ -26,6 +26,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces private var commonTestFlagCache: Boolean? = null private var allowCollapsableChildrenCache: Boolean? = null + private var allowRecursiveCommitsWithSynchronousMountOnAndroidCache: Boolean? = null private var batchRenderingUpdatesInEventLoopCache: Boolean? = null private var destroyFabricSurfacesInReactInstanceManagerCache: Boolean? = null private var enableBackgroundExecutorCache: Boolean? = null @@ -65,6 +66,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun allowRecursiveCommitsWithSynchronousMountOnAndroid(): Boolean { + var cached = allowRecursiveCommitsWithSynchronousMountOnAndroidCache + if (cached == null) { + cached = currentProvider.allowRecursiveCommitsWithSynchronousMountOnAndroid() + accessedFeatureFlags.add("allowRecursiveCommitsWithSynchronousMountOnAndroid") + allowRecursiveCommitsWithSynchronousMountOnAndroidCache = cached + } + return cached + } + override fun batchRenderingUpdatesInEventLoop(): Boolean { var cached = batchRenderingUpdatesInEventLoopCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt index 22d5675bf43f76..6a197d336ec71f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt @@ -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<<7a63b1fc14ccc86efb0929452755744d>> + * @generated SignedSource<<68ec2c046868a2cb1d2d88e4fdd9d993>> */ /** @@ -27,6 +27,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun allowCollapsableChildren(): Boolean + @DoNotStrip public fun allowRecursiveCommitsWithSynchronousMountOnAndroid(): Boolean + @DoNotStrip public fun batchRenderingUpdatesInEventLoop(): Boolean @DoNotStrip public fun destroyFabricSurfacesInReactInstanceManager(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.cpp index e8aec3fb34a486..1c029ab86e6e68 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/Binding.cpp @@ -487,11 +487,28 @@ void Binding::schedulerShouldRenderTransactions( return; } - std::unique_lock lock(pendingTransactionsMutex_); - for (auto& transaction : pendingTransactions_) { - mountingManager->executeMount(transaction); + if (ReactNativeFeatureFlags:: + allowRecursiveCommitsWithSynchronousMountOnAndroid()) { + std::vector pendingTransactions; + + { + // Retain the lock to access the pending transactions but not to execute + // the mount operations because that method can call into this method + // again. + std::unique_lock lock(pendingTransactionsMutex_); + pendingTransactions_.swap(pendingTransactions); + } + + for (auto& transaction : pendingTransactions) { + mountingManager->executeMount(transaction); + } + } else { + std::unique_lock lock(pendingTransactionsMutex_); + for (auto& transaction : pendingTransactions_) { + mountingManager->executeMount(transaction); + } + pendingTransactions_.clear(); } - pendingTransactions_.clear(); } void Binding::schedulerDidRequestPreliminaryViewAllocation( diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp index 859b4dfedea0eb..4d13354e408773 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp @@ -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<<82d20aa409496b17df21a077088894a6>> + * @generated SignedSource<<318ea35c5b58c968d7026dbe547200e4>> */ /** @@ -51,6 +51,12 @@ class ReactNativeFeatureFlagsProviderHolder return method(javaProvider_); } + bool allowRecursiveCommitsWithSynchronousMountOnAndroid() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("allowRecursiveCommitsWithSynchronousMountOnAndroid"); + return method(javaProvider_); + } + bool batchRenderingUpdatesInEventLoop() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("batchRenderingUpdatesInEventLoop"); @@ -173,6 +179,11 @@ bool JReactNativeFeatureFlagsCxxInterop::allowCollapsableChildren( return ReactNativeFeatureFlags::allowCollapsableChildren(); } +bool JReactNativeFeatureFlagsCxxInterop::allowRecursiveCommitsWithSynchronousMountOnAndroid( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::allowRecursiveCommitsWithSynchronousMountOnAndroid(); +} + bool JReactNativeFeatureFlagsCxxInterop::batchRenderingUpdatesInEventLoop( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::batchRenderingUpdatesInEventLoop(); @@ -286,6 +297,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "allowCollapsableChildren", JReactNativeFeatureFlagsCxxInterop::allowCollapsableChildren), + makeNativeMethod( + "allowRecursiveCommitsWithSynchronousMountOnAndroid", + JReactNativeFeatureFlagsCxxInterop::allowRecursiveCommitsWithSynchronousMountOnAndroid), makeNativeMethod( "batchRenderingUpdatesInEventLoop", JReactNativeFeatureFlagsCxxInterop::batchRenderingUpdatesInEventLoop), diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h index 108d20254702ba..608ab6d64aaf31 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h @@ -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<<08463d4f487df81332c79c8e85b4dac8>> + * @generated SignedSource<<4d557dc4399d46888205165ee7ae4ab2>> */ /** @@ -36,6 +36,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool allowCollapsableChildren( facebook::jni::alias_ref); + static bool allowRecursiveCommitsWithSynchronousMountOnAndroid( + facebook::jni::alias_ref); + static bool batchRenderingUpdatesInEventLoop( facebook::jni::alias_ref); diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp index 36e6f3f4ab3402..156b1c1a80be0e 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp @@ -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<> + * @generated SignedSource<<2a748a0a1b92cb0514fec83668ed8b0f>> */ /** @@ -29,6 +29,10 @@ bool ReactNativeFeatureFlags::allowCollapsableChildren() { return getAccessor().allowCollapsableChildren(); } +bool ReactNativeFeatureFlags::allowRecursiveCommitsWithSynchronousMountOnAndroid() { + return getAccessor().allowRecursiveCommitsWithSynchronousMountOnAndroid(); +} + bool ReactNativeFeatureFlags::batchRenderingUpdatesInEventLoop() { return getAccessor().batchRenderingUpdatesInEventLoop(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index 536cf1c6870ac4..595b0fcd15960a 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h @@ -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<<705dba656bfb228227399bcda638c404>> + * @generated SignedSource<> */ /** @@ -47,6 +47,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool allowCollapsableChildren(); + /** + * Adds support for recursively processing commits that mount synchronously (Android only). + */ + RN_EXPORT static bool allowRecursiveCommitsWithSynchronousMountOnAndroid(); + /** * When enabled, the RuntimeScheduler processing the event loop will batch all rendering updates and dispatch them together at the end of each iteration of the loop. */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index 6f629799524b5d..4187f8b87efff9 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp @@ -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<<53617e29d537989ca3ac0f314a278e4b>> + * @generated SignedSource<<3e5cb385f51ebc9f53010a901ccbb6a2>> */ /** @@ -65,6 +65,24 @@ bool ReactNativeFeatureFlagsAccessor::allowCollapsableChildren() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::allowRecursiveCommitsWithSynchronousMountOnAndroid() { + auto flagValue = allowRecursiveCommitsWithSynchronousMountOnAndroid_.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(2, "allowRecursiveCommitsWithSynchronousMountOnAndroid"); + + flagValue = currentProvider_->allowRecursiveCommitsWithSynchronousMountOnAndroid(); + allowRecursiveCommitsWithSynchronousMountOnAndroid_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::batchRenderingUpdatesInEventLoop() { auto flagValue = batchRenderingUpdatesInEventLoop_.load(); @@ -74,7 +92,7 @@ bool ReactNativeFeatureFlagsAccessor::batchRenderingUpdatesInEventLoop() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(2, "batchRenderingUpdatesInEventLoop"); + markFlagAsAccessed(3, "batchRenderingUpdatesInEventLoop"); flagValue = currentProvider_->batchRenderingUpdatesInEventLoop(); batchRenderingUpdatesInEventLoop_ = flagValue; @@ -92,7 +110,7 @@ bool ReactNativeFeatureFlagsAccessor::destroyFabricSurfacesInReactInstanceManage // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(3, "destroyFabricSurfacesInReactInstanceManager"); + markFlagAsAccessed(4, "destroyFabricSurfacesInReactInstanceManager"); flagValue = currentProvider_->destroyFabricSurfacesInReactInstanceManager(); destroyFabricSurfacesInReactInstanceManager_ = flagValue; @@ -110,7 +128,7 @@ bool ReactNativeFeatureFlagsAccessor::enableBackgroundExecutor() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(4, "enableBackgroundExecutor"); + markFlagAsAccessed(5, "enableBackgroundExecutor"); flagValue = currentProvider_->enableBackgroundExecutor(); enableBackgroundExecutor_ = flagValue; @@ -128,7 +146,7 @@ bool ReactNativeFeatureFlagsAccessor::enableCleanTextInputYogaNode() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(5, "enableCleanTextInputYogaNode"); + markFlagAsAccessed(6, "enableCleanTextInputYogaNode"); flagValue = currentProvider_->enableCleanTextInputYogaNode(); enableCleanTextInputYogaNode_ = flagValue; @@ -146,7 +164,7 @@ bool ReactNativeFeatureFlagsAccessor::enableGranularShadowTreeStateReconciliatio // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(6, "enableGranularShadowTreeStateReconciliation"); + markFlagAsAccessed(7, "enableGranularShadowTreeStateReconciliation"); flagValue = currentProvider_->enableGranularShadowTreeStateReconciliation(); enableGranularShadowTreeStateReconciliation_ = flagValue; @@ -164,7 +182,7 @@ bool ReactNativeFeatureFlagsAccessor::enableMicrotasks() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(7, "enableMicrotasks"); + markFlagAsAccessed(8, "enableMicrotasks"); flagValue = currentProvider_->enableMicrotasks(); enableMicrotasks_ = flagValue; @@ -182,7 +200,7 @@ bool ReactNativeFeatureFlagsAccessor::enableSynchronousStateUpdates() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(8, "enableSynchronousStateUpdates"); + markFlagAsAccessed(9, "enableSynchronousStateUpdates"); flagValue = currentProvider_->enableSynchronousStateUpdates(); enableSynchronousStateUpdates_ = flagValue; @@ -200,7 +218,7 @@ bool ReactNativeFeatureFlagsAccessor::enableUIConsistency() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(9, "enableUIConsistency"); + markFlagAsAccessed(10, "enableUIConsistency"); flagValue = currentProvider_->enableUIConsistency(); enableUIConsistency_ = flagValue; @@ -218,7 +236,7 @@ bool ReactNativeFeatureFlagsAccessor::fixStoppedSurfaceRemoveDeleteTreeUIFrameCa // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(10, "fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak"); + markFlagAsAccessed(11, "fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak"); flagValue = currentProvider_->fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak(); fixStoppedSurfaceRemoveDeleteTreeUIFrameCallbackLeak_ = flagValue; @@ -236,7 +254,7 @@ bool ReactNativeFeatureFlagsAccessor::forceBatchingMountItemsOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(11, "forceBatchingMountItemsOnAndroid"); + markFlagAsAccessed(12, "forceBatchingMountItemsOnAndroid"); flagValue = currentProvider_->forceBatchingMountItemsOnAndroid(); forceBatchingMountItemsOnAndroid_ = flagValue; @@ -254,7 +272,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxEnabledDebug() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(12, "fuseboxEnabledDebug"); + markFlagAsAccessed(13, "fuseboxEnabledDebug"); flagValue = currentProvider_->fuseboxEnabledDebug(); fuseboxEnabledDebug_ = flagValue; @@ -272,7 +290,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxEnabledRelease() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(13, "fuseboxEnabledRelease"); + markFlagAsAccessed(14, "fuseboxEnabledRelease"); flagValue = currentProvider_->fuseboxEnabledRelease(); fuseboxEnabledRelease_ = flagValue; @@ -290,7 +308,7 @@ bool ReactNativeFeatureFlagsAccessor::lazyAnimationCallbacks() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(14, "lazyAnimationCallbacks"); + markFlagAsAccessed(15, "lazyAnimationCallbacks"); flagValue = currentProvider_->lazyAnimationCallbacks(); lazyAnimationCallbacks_ = flagValue; @@ -308,7 +326,7 @@ bool ReactNativeFeatureFlagsAccessor::preventDoubleTextMeasure() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(15, "preventDoubleTextMeasure"); + markFlagAsAccessed(16, "preventDoubleTextMeasure"); flagValue = currentProvider_->preventDoubleTextMeasure(); preventDoubleTextMeasure_ = flagValue; @@ -326,7 +344,7 @@ bool ReactNativeFeatureFlagsAccessor::setAndroidLayoutDirection() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(16, "setAndroidLayoutDirection"); + markFlagAsAccessed(17, "setAndroidLayoutDirection"); flagValue = currentProvider_->setAndroidLayoutDirection(); setAndroidLayoutDirection_ = flagValue; @@ -344,7 +362,7 @@ bool ReactNativeFeatureFlagsAccessor::useModernRuntimeScheduler() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(17, "useModernRuntimeScheduler"); + markFlagAsAccessed(18, "useModernRuntimeScheduler"); flagValue = currentProvider_->useModernRuntimeScheduler(); useModernRuntimeScheduler_ = flagValue; @@ -362,7 +380,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(18, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(19, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -380,7 +398,7 @@ bool ReactNativeFeatureFlagsAccessor::useStateAlignmentMechanism() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(19, "useStateAlignmentMechanism"); + markFlagAsAccessed(20, "useStateAlignmentMechanism"); flagValue = currentProvider_->useStateAlignmentMechanism(); useStateAlignmentMechanism_ = flagValue; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index 737edf512bced9..e5d3b1eca900c6 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h @@ -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<> + * @generated SignedSource<> */ /** @@ -33,6 +33,7 @@ class ReactNativeFeatureFlagsAccessor { bool commonTestFlag(); bool allowCollapsableChildren(); + bool allowRecursiveCommitsWithSynchronousMountOnAndroid(); bool batchRenderingUpdatesInEventLoop(); bool destroyFabricSurfacesInReactInstanceManager(); bool enableBackgroundExecutor(); @@ -61,10 +62,11 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 20> accessedFeatureFlags_; + std::array, 21> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> allowCollapsableChildren_; + std::atomic> allowRecursiveCommitsWithSynchronousMountOnAndroid_; std::atomic> batchRenderingUpdatesInEventLoop_; std::atomic> destroyFabricSurfacesInReactInstanceManager_; std::atomic> enableBackgroundExecutor_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index be4a861b46e17d..85a5fd0bef385b 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h @@ -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<> + * @generated SignedSource<<5c78cdf7676d56996ea174f08bf4b8a6>> */ /** @@ -35,6 +35,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return true; } + bool allowRecursiveCommitsWithSynchronousMountOnAndroid() override { + return false; + } + bool batchRenderingUpdatesInEventLoop() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index 2056aee1d4e37c..8bb300bce21d53 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h @@ -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<> + * @generated SignedSource<> */ /** @@ -27,6 +27,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool commonTestFlag() = 0; virtual bool allowCollapsableChildren() = 0; + virtual bool allowRecursiveCommitsWithSynchronousMountOnAndroid() = 0; virtual bool batchRenderingUpdatesInEventLoop() = 0; virtual bool destroyFabricSurfacesInReactInstanceManager() = 0; virtual bool enableBackgroundExecutor() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index dec93c10b9a8ba..b64fa4d22e2432 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp @@ -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<> + * @generated SignedSource<<4c02b68cc3b46ec214fe4552f136c5f0>> */ /** @@ -47,6 +47,11 @@ bool NativeReactNativeFeatureFlags::allowCollapsableChildren( return ReactNativeFeatureFlags::allowCollapsableChildren(); } +bool NativeReactNativeFeatureFlags::allowRecursiveCommitsWithSynchronousMountOnAndroid( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::allowRecursiveCommitsWithSynchronousMountOnAndroid(); +} + bool NativeReactNativeFeatureFlags::batchRenderingUpdatesInEventLoop( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::batchRenderingUpdatesInEventLoop(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index 788007a224b599..55bd107044eac8 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h @@ -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<> + * @generated SignedSource<> */ /** @@ -39,6 +39,8 @@ class NativeReactNativeFeatureFlags bool allowCollapsableChildren(jsi::Runtime& runtime); + bool allowRecursiveCommitsWithSynchronousMountOnAndroid(jsi::Runtime& runtime); + bool batchRenderingUpdatesInEventLoop(jsi::Runtime& runtime); bool destroyFabricSurfacesInReactInstanceManager(jsi::Runtime& runtime); diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index 3ef416eab5d75d..0e972cc677fe08 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -44,6 +44,11 @@ const definitions: FeatureFlagDefinitions = { description: 'Enables the differentiator to understand the "collapsableChildren" prop', }, + allowRecursiveCommitsWithSynchronousMountOnAndroid: { + defaultValue: false, + description: + 'Adds support for recursively processing commits that mount synchronously (Android only).', + }, batchRenderingUpdatesInEventLoop: { defaultValue: false, description: diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index 8991cdf4fd3b31..9d8befdc35f2b7 100644 --- a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js @@ -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<<0a8bc71d703e92e1aaba25203e0211b3>> + * @generated SignedSource<<1cf3f0841a0523baddea551747c425ca>> * @flow strict-local */ @@ -42,6 +42,7 @@ export type ReactNativeFeatureFlags = { ...ReactNativeFeatureFlagsJsOnly, commonTestFlag: Getter, allowCollapsableChildren: Getter, + allowRecursiveCommitsWithSynchronousMountOnAndroid: Getter, batchRenderingUpdatesInEventLoop: Getter, destroyFabricSurfacesInReactInstanceManager: Getter, enableBackgroundExecutor: Getter, @@ -110,6 +111,10 @@ export const commonTestFlag: Getter = createNativeFlagGetter('commonTes * Enables the differentiator to understand the "collapsableChildren" prop */ export const allowCollapsableChildren: Getter = createNativeFlagGetter('allowCollapsableChildren', true); +/** + * Adds support for recursively processing commits that mount synchronously (Android only). + */ +export const allowRecursiveCommitsWithSynchronousMountOnAndroid: Getter = createNativeFlagGetter('allowRecursiveCommitsWithSynchronousMountOnAndroid', false); /** * When enabled, the RuntimeScheduler processing the event loop will batch all rendering updates and dispatch them together at the end of each iteration of the loop. */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index 3818226c0daed5..3d26ffbe380318 100644 --- a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js @@ -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<<13b6d24c994e1ac758d2a76f759f5363>> + * @generated SignedSource<<613d748b087fde71cc07a7cd5acf888e>> * @flow strict-local */ @@ -25,6 +25,7 @@ import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboMod export interface Spec extends TurboModule { +commonTestFlag?: () => boolean; +allowCollapsableChildren?: () => boolean; + +allowRecursiveCommitsWithSynchronousMountOnAndroid?: () => boolean; +batchRenderingUpdatesInEventLoop?: () => boolean; +destroyFabricSurfacesInReactInstanceManager?: () => boolean; +enableBackgroundExecutor?: () => boolean;