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 43eaaf037b064e..ceb969bb50a293 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<<82fac57322d589b28e7fca321f82d5e6>> + * @generated SignedSource<<794bf258fbb453ea71a39c5459316a24>> */ /** @@ -222,6 +222,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun traceTurboModulePromiseRejectionsOnAndroid(): Boolean = accessor.traceTurboModulePromiseRejectionsOnAndroid() + /** + * When enabled, runtime shadow node references will be updated during the commit. This allows running RSNRU from any thread without corrupting the renderer state. + */ + @JvmStatic + public fun updateRuntimeShadowNodeReferencesOnCommit(): Boolean = accessor.updateRuntimeShadowNodeReferencesOnCommit() + /** * In Bridgeless mode, use the always available javascript error reporting pipeline. */ @@ -258,6 +264,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun useRawPropsJsiValue(): Boolean = accessor.useRawPropsJsiValue() + /** + * Use the state stored on the source shadow node when cloning it instead of reading in the most recent state on the shadow node family. + */ + @JvmStatic + public fun useShadowNodeStateOnClone(): Boolean = accessor.useShadowNodeStateOnClone() + /** * In Bridgeless mode, should legacy NativeModules use the TurboModule system? */ 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 3ead573d09af4d..316d2640b52f51 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<<112e542686afa5657898a450543ec5a9>> + * @generated SignedSource<<43260e9f0b5774bdb3d60915bcd28ea3>> */ /** @@ -52,12 +52,14 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces private var fuseboxNetworkInspectionEnabledCache: Boolean? = null private var removeTurboModuleManagerDelegateMutexCache: Boolean? = null private var traceTurboModulePromiseRejectionsOnAndroidCache: Boolean? = null + private var updateRuntimeShadowNodeReferencesOnCommitCache: Boolean? = null private var useAlwaysAvailableJSErrorHandlingCache: Boolean? = null private var useEditTextStockAndroidFocusBehaviorCache: Boolean? = null private var useFabricInteropCache: Boolean? = null private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null private var useOptimizedEventBatchingOnAndroidCache: Boolean? = null private var useRawPropsJsiValueCache: Boolean? = null + private var useShadowNodeStateOnCloneCache: Boolean? = null private var useTurboModuleInteropCache: Boolean? = null private var useTurboModulesCache: Boolean? = null @@ -349,6 +351,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun updateRuntimeShadowNodeReferencesOnCommit(): Boolean { + var cached = updateRuntimeShadowNodeReferencesOnCommitCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.updateRuntimeShadowNodeReferencesOnCommit() + updateRuntimeShadowNodeReferencesOnCommitCache = cached + } + return cached + } + override fun useAlwaysAvailableJSErrorHandling(): Boolean { var cached = useAlwaysAvailableJSErrorHandlingCache if (cached == null) { @@ -403,6 +414,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun useShadowNodeStateOnClone(): Boolean { + var cached = useShadowNodeStateOnCloneCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.useShadowNodeStateOnClone() + useShadowNodeStateOnCloneCache = cached + } + return cached + } + override fun useTurboModuleInterop(): Boolean { var cached = useTurboModuleInteropCache 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 c0fc30fa98a307..ed86bb1eefc127 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<<1f3845a6aad6babd4404adfb433f4b38>> */ /** @@ -92,6 +92,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun traceTurboModulePromiseRejectionsOnAndroid(): Boolean + @DoNotStrip @JvmStatic public external fun updateRuntimeShadowNodeReferencesOnCommit(): Boolean + @DoNotStrip @JvmStatic public external fun useAlwaysAvailableJSErrorHandling(): Boolean @DoNotStrip @JvmStatic public external fun useEditTextStockAndroidFocusBehavior(): Boolean @@ -104,6 +106,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun useRawPropsJsiValue(): Boolean + @DoNotStrip @JvmStatic public external fun useShadowNodeStateOnClone(): Boolean + @DoNotStrip @JvmStatic public external fun useTurboModuleInterop(): Boolean @DoNotStrip @JvmStatic public external fun useTurboModules(): 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 49c6ed9fe3367e..11b374ed9367f4 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<<1c38f54724a573b954fd8aee1e41e73a>> + * @generated SignedSource<<6f24701d1581b744185caaee1ca5fc06>> */ /** @@ -87,6 +87,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun traceTurboModulePromiseRejectionsOnAndroid(): Boolean = false + override fun updateRuntimeShadowNodeReferencesOnCommit(): Boolean = false + override fun useAlwaysAvailableJSErrorHandling(): Boolean = false override fun useEditTextStockAndroidFocusBehavior(): Boolean = true @@ -99,6 +101,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun useRawPropsJsiValue(): Boolean = false + override fun useShadowNodeStateOnClone(): Boolean = false + override fun useTurboModuleInterop(): Boolean = false override fun useTurboModules(): 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 34d9c20df95988..103058b52ccd0c 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<<8988a69695658c92f013e736dec8f5fc>> */ /** @@ -56,12 +56,14 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc private var fuseboxNetworkInspectionEnabledCache: Boolean? = null private var removeTurboModuleManagerDelegateMutexCache: Boolean? = null private var traceTurboModulePromiseRejectionsOnAndroidCache: Boolean? = null + private var updateRuntimeShadowNodeReferencesOnCommitCache: Boolean? = null private var useAlwaysAvailableJSErrorHandlingCache: Boolean? = null private var useEditTextStockAndroidFocusBehaviorCache: Boolean? = null private var useFabricInteropCache: Boolean? = null private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null private var useOptimizedEventBatchingOnAndroidCache: Boolean? = null private var useRawPropsJsiValueCache: Boolean? = null + private var useShadowNodeStateOnCloneCache: Boolean? = null private var useTurboModuleInteropCache: Boolean? = null private var useTurboModulesCache: Boolean? = null @@ -385,6 +387,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc return cached } + override fun updateRuntimeShadowNodeReferencesOnCommit(): Boolean { + var cached = updateRuntimeShadowNodeReferencesOnCommitCache + if (cached == null) { + cached = currentProvider.updateRuntimeShadowNodeReferencesOnCommit() + accessedFeatureFlags.add("updateRuntimeShadowNodeReferencesOnCommit") + updateRuntimeShadowNodeReferencesOnCommitCache = cached + } + return cached + } + override fun useAlwaysAvailableJSErrorHandling(): Boolean { var cached = useAlwaysAvailableJSErrorHandlingCache if (cached == null) { @@ -445,6 +457,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc return cached } + override fun useShadowNodeStateOnClone(): Boolean { + var cached = useShadowNodeStateOnCloneCache + if (cached == null) { + cached = currentProvider.useShadowNodeStateOnClone() + accessedFeatureFlags.add("useShadowNodeStateOnClone") + useShadowNodeStateOnCloneCache = cached + } + return cached + } + override fun useTurboModuleInterop(): Boolean { var cached = useTurboModuleInteropCache 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 fbf090de296d0e..4061a69c9754cf 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<> + * @generated SignedSource<<646efad3c8769005e893ad63d78b8c6c>> */ /** @@ -87,6 +87,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun traceTurboModulePromiseRejectionsOnAndroid(): Boolean + @DoNotStrip public fun updateRuntimeShadowNodeReferencesOnCommit(): Boolean + @DoNotStrip public fun useAlwaysAvailableJSErrorHandling(): Boolean @DoNotStrip public fun useEditTextStockAndroidFocusBehavior(): Boolean @@ -99,6 +101,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun useRawPropsJsiValue(): Boolean + @DoNotStrip public fun useShadowNodeStateOnClone(): Boolean + @DoNotStrip public fun useTurboModuleInterop(): Boolean @DoNotStrip public fun useTurboModules(): Boolean 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 9f1531092d9e9e..dca014d2f45b9d 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<> + * @generated SignedSource<> */ /** @@ -231,6 +231,12 @@ class ReactNativeFeatureFlagsJavaProvider return method(javaProvider_); } + bool updateRuntimeShadowNodeReferencesOnCommit() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("updateRuntimeShadowNodeReferencesOnCommit"); + return method(javaProvider_); + } + bool useAlwaysAvailableJSErrorHandling() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("useAlwaysAvailableJSErrorHandling"); @@ -267,6 +273,12 @@ class ReactNativeFeatureFlagsJavaProvider return method(javaProvider_); } + bool useShadowNodeStateOnClone() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("useShadowNodeStateOnClone"); + return method(javaProvider_); + } + bool useTurboModuleInterop() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("useTurboModuleInterop"); @@ -443,6 +455,11 @@ bool JReactNativeFeatureFlagsCxxInterop::traceTurboModulePromiseRejectionsOnAndr return ReactNativeFeatureFlags::traceTurboModulePromiseRejectionsOnAndroid(); } +bool JReactNativeFeatureFlagsCxxInterop::updateRuntimeShadowNodeReferencesOnCommit( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::updateRuntimeShadowNodeReferencesOnCommit(); +} + bool JReactNativeFeatureFlagsCxxInterop::useAlwaysAvailableJSErrorHandling( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::useAlwaysAvailableJSErrorHandling(); @@ -473,6 +490,11 @@ bool JReactNativeFeatureFlagsCxxInterop::useRawPropsJsiValue( return ReactNativeFeatureFlags::useRawPropsJsiValue(); } +bool JReactNativeFeatureFlagsCxxInterop::useShadowNodeStateOnClone( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::useShadowNodeStateOnClone(); +} + bool JReactNativeFeatureFlagsCxxInterop::useTurboModuleInterop( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::useTurboModuleInterop(); @@ -610,6 +632,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "traceTurboModulePromiseRejectionsOnAndroid", JReactNativeFeatureFlagsCxxInterop::traceTurboModulePromiseRejectionsOnAndroid), + makeNativeMethod( + "updateRuntimeShadowNodeReferencesOnCommit", + JReactNativeFeatureFlagsCxxInterop::updateRuntimeShadowNodeReferencesOnCommit), makeNativeMethod( "useAlwaysAvailableJSErrorHandling", JReactNativeFeatureFlagsCxxInterop::useAlwaysAvailableJSErrorHandling), @@ -628,6 +653,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "useRawPropsJsiValue", JReactNativeFeatureFlagsCxxInterop::useRawPropsJsiValue), + makeNativeMethod( + "useShadowNodeStateOnClone", + JReactNativeFeatureFlagsCxxInterop::useShadowNodeStateOnClone), makeNativeMethod( "useTurboModuleInterop", JReactNativeFeatureFlagsCxxInterop::useTurboModuleInterop), 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 546a5e36cfd096..4ff3606460431b 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<<591f49d5a0b5368ecceb5ab054f4c0a5>> + * @generated SignedSource<<58c3ec4bdf7b171ea6203ed100116c50>> */ /** @@ -126,6 +126,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool traceTurboModulePromiseRejectionsOnAndroid( facebook::jni::alias_ref); + static bool updateRuntimeShadowNodeReferencesOnCommit( + facebook::jni::alias_ref); + static bool useAlwaysAvailableJSErrorHandling( facebook::jni::alias_ref); @@ -144,6 +147,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool useRawPropsJsiValue( facebook::jni::alias_ref); + static bool useShadowNodeStateOnClone( + facebook::jni::alias_ref); + static bool useTurboModuleInterop( 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 f7ac398a6cd00d..debf70d4fa16e8 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<<543d5f445f026f68976b1d4f8402f12e>> + * @generated SignedSource<<55680628f0480fce8c955fbde539ae47>> */ /** @@ -154,6 +154,10 @@ bool ReactNativeFeatureFlags::traceTurboModulePromiseRejectionsOnAndroid() { return getAccessor().traceTurboModulePromiseRejectionsOnAndroid(); } +bool ReactNativeFeatureFlags::updateRuntimeShadowNodeReferencesOnCommit() { + return getAccessor().updateRuntimeShadowNodeReferencesOnCommit(); +} + bool ReactNativeFeatureFlags::useAlwaysAvailableJSErrorHandling() { return getAccessor().useAlwaysAvailableJSErrorHandling(); } @@ -178,6 +182,10 @@ bool ReactNativeFeatureFlags::useRawPropsJsiValue() { return getAccessor().useRawPropsJsiValue(); } +bool ReactNativeFeatureFlags::useShadowNodeStateOnClone() { + return getAccessor().useShadowNodeStateOnClone(); +} + bool ReactNativeFeatureFlags::useTurboModuleInterop() { return getAccessor().useTurboModuleInterop(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index db2daeb7ef35df..a1e236c6f040b3 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<> + * @generated SignedSource<<136de88435026f3bfb2d785d1a12b707>> */ /** @@ -199,6 +199,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool traceTurboModulePromiseRejectionsOnAndroid(); + /** + * When enabled, runtime shadow node references will be updated during the commit. This allows running RSNRU from any thread without corrupting the renderer state. + */ + RN_EXPORT static bool updateRuntimeShadowNodeReferencesOnCommit(); + /** * In Bridgeless mode, use the always available javascript error reporting pipeline. */ @@ -229,6 +234,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool useRawPropsJsiValue(); + /** + * Use the state stored on the source shadow node when cloning it instead of reading in the most recent state on the shadow node family. + */ + RN_EXPORT static bool useShadowNodeStateOnClone(); + /** * In Bridgeless mode, should legacy NativeModules use the TurboModule system? */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index 185ab4aeb8ca7a..c1e45c6e64342f 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<<16ef8368ca6b8849407fe2b4543e6c79>> + * @generated SignedSource<<6f18b18b4aa1ef98f94bf4f595a59363>> */ /** @@ -605,6 +605,24 @@ bool ReactNativeFeatureFlagsAccessor::traceTurboModulePromiseRejectionsOnAndroid return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::updateRuntimeShadowNodeReferencesOnCommit() { + auto flagValue = updateRuntimeShadowNodeReferencesOnCommit_.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(32, "updateRuntimeShadowNodeReferencesOnCommit"); + + flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommit(); + updateRuntimeShadowNodeReferencesOnCommit_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::useAlwaysAvailableJSErrorHandling() { auto flagValue = useAlwaysAvailableJSErrorHandling_.load(); @@ -614,7 +632,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(32, "useAlwaysAvailableJSErrorHandling"); + markFlagAsAccessed(33, "useAlwaysAvailableJSErrorHandling"); flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling(); useAlwaysAvailableJSErrorHandling_ = flagValue; @@ -632,7 +650,7 @@ bool ReactNativeFeatureFlagsAccessor::useEditTextStockAndroidFocusBehavior() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(33, "useEditTextStockAndroidFocusBehavior"); + markFlagAsAccessed(34, "useEditTextStockAndroidFocusBehavior"); flagValue = currentProvider_->useEditTextStockAndroidFocusBehavior(); useEditTextStockAndroidFocusBehavior_ = flagValue; @@ -650,7 +668,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(34, "useFabricInterop"); + markFlagAsAccessed(35, "useFabricInterop"); flagValue = currentProvider_->useFabricInterop(); useFabricInterop_ = flagValue; @@ -668,7 +686,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(35, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(36, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -686,7 +704,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(36, "useOptimizedEventBatchingOnAndroid"); + markFlagAsAccessed(37, "useOptimizedEventBatchingOnAndroid"); flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid(); useOptimizedEventBatchingOnAndroid_ = flagValue; @@ -704,7 +722,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(37, "useRawPropsJsiValue"); + markFlagAsAccessed(38, "useRawPropsJsiValue"); flagValue = currentProvider_->useRawPropsJsiValue(); useRawPropsJsiValue_ = flagValue; @@ -713,6 +731,24 @@ bool ReactNativeFeatureFlagsAccessor::useRawPropsJsiValue() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::useShadowNodeStateOnClone() { + auto flagValue = useShadowNodeStateOnClone_.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(39, "useShadowNodeStateOnClone"); + + flagValue = currentProvider_->useShadowNodeStateOnClone(); + useShadowNodeStateOnClone_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::useTurboModuleInterop() { auto flagValue = useTurboModuleInterop_.load(); @@ -722,7 +758,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(38, "useTurboModuleInterop"); + markFlagAsAccessed(40, "useTurboModuleInterop"); flagValue = currentProvider_->useTurboModuleInterop(); useTurboModuleInterop_ = flagValue; @@ -740,7 +776,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(39, "useTurboModules"); + markFlagAsAccessed(41, "useTurboModules"); flagValue = currentProvider_->useTurboModules(); useTurboModules_ = flagValue; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index d2f16b7f33cb01..fdac1634b6b1f6 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<<2849b6b0b37b68825d9d9079a6ac5098>> */ /** @@ -64,12 +64,14 @@ class ReactNativeFeatureFlagsAccessor { bool fuseboxNetworkInspectionEnabled(); bool removeTurboModuleManagerDelegateMutex(); bool traceTurboModulePromiseRejectionsOnAndroid(); + bool updateRuntimeShadowNodeReferencesOnCommit(); bool useAlwaysAvailableJSErrorHandling(); bool useEditTextStockAndroidFocusBehavior(); bool useFabricInterop(); bool useNativeViewConfigsInBridgelessMode(); bool useOptimizedEventBatchingOnAndroid(); bool useRawPropsJsiValue(); + bool useShadowNodeStateOnClone(); bool useTurboModuleInterop(); bool useTurboModules(); @@ -83,7 +85,7 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 40> accessedFeatureFlags_; + std::array, 42> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> animatedShouldSignalBatch_; @@ -117,12 +119,14 @@ class ReactNativeFeatureFlagsAccessor { std::atomic> fuseboxNetworkInspectionEnabled_; std::atomic> removeTurboModuleManagerDelegateMutex_; std::atomic> traceTurboModulePromiseRejectionsOnAndroid_; + std::atomic> updateRuntimeShadowNodeReferencesOnCommit_; std::atomic> useAlwaysAvailableJSErrorHandling_; std::atomic> useEditTextStockAndroidFocusBehavior_; std::atomic> useFabricInterop_; std::atomic> useNativeViewConfigsInBridgelessMode_; std::atomic> useOptimizedEventBatchingOnAndroid_; std::atomic> useRawPropsJsiValue_; + std::atomic> useShadowNodeStateOnClone_; std::atomic> useTurboModuleInterop_; std::atomic> useTurboModules_; }; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index 7acb1d0f50d4b4..d21ab5a07fb654 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<<2ff9e2c1e9cc5c780777c0a80efcc74f>> + * @generated SignedSource<<377c3de6bcd7de45efa0d58e0de94fb1>> */ /** @@ -155,6 +155,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return false; } + bool updateRuntimeShadowNodeReferencesOnCommit() override { + return false; + } + bool useAlwaysAvailableJSErrorHandling() override { return false; } @@ -179,6 +183,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return false; } + bool useShadowNodeStateOnClone() override { + return false; + } + bool useTurboModuleInterop() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h index a941ab4c8686c3..30b2f2a511dbe3 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.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<> */ /** @@ -333,6 +333,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef return ReactNativeFeatureFlagsDefaults::traceTurboModulePromiseRejectionsOnAndroid(); } + bool updateRuntimeShadowNodeReferencesOnCommit() override { + auto value = values_["updateRuntimeShadowNodeReferencesOnCommit"]; + if (!value.isNull()) { + return value.getBool(); + } + + return ReactNativeFeatureFlagsDefaults::updateRuntimeShadowNodeReferencesOnCommit(); + } + bool useAlwaysAvailableJSErrorHandling() override { auto value = values_["useAlwaysAvailableJSErrorHandling"]; if (!value.isNull()) { @@ -387,6 +396,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef return ReactNativeFeatureFlagsDefaults::useRawPropsJsiValue(); } + bool useShadowNodeStateOnClone() override { + auto value = values_["useShadowNodeStateOnClone"]; + if (!value.isNull()) { + return value.getBool(); + } + + return ReactNativeFeatureFlagsDefaults::useShadowNodeStateOnClone(); + } + bool useTurboModuleInterop() override { auto value = values_["useTurboModuleInterop"]; if (!value.isNull()) { diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index 46ffcefb8a2d04..820bde5360c579 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<<2a276a80c05bbe104f2f8f1fef10eb3d>> + * @generated SignedSource<<9dc34d10f6fcfe475b851db7db573015>> */ /** @@ -57,12 +57,14 @@ class ReactNativeFeatureFlagsProvider { virtual bool fuseboxNetworkInspectionEnabled() = 0; virtual bool removeTurboModuleManagerDelegateMutex() = 0; virtual bool traceTurboModulePromiseRejectionsOnAndroid() = 0; + virtual bool updateRuntimeShadowNodeReferencesOnCommit() = 0; virtual bool useAlwaysAvailableJSErrorHandling() = 0; virtual bool useEditTextStockAndroidFocusBehavior() = 0; virtual bool useFabricInterop() = 0; virtual bool useNativeViewConfigsInBridgelessMode() = 0; virtual bool useOptimizedEventBatchingOnAndroid() = 0; virtual bool useRawPropsJsiValue() = 0; + virtual bool useShadowNodeStateOnClone() = 0; virtual bool useTurboModuleInterop() = 0; virtual bool useTurboModules() = 0; }; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index 282d2cb7d9eef3..477859899c657f 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<<35fca1602825c8a7b2e551388e0064cc>> */ /** @@ -204,6 +204,11 @@ bool NativeReactNativeFeatureFlags::traceTurboModulePromiseRejectionsOnAndroid( return ReactNativeFeatureFlags::traceTurboModulePromiseRejectionsOnAndroid(); } +bool NativeReactNativeFeatureFlags::updateRuntimeShadowNodeReferencesOnCommit( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::updateRuntimeShadowNodeReferencesOnCommit(); +} + bool NativeReactNativeFeatureFlags::useAlwaysAvailableJSErrorHandling( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::useAlwaysAvailableJSErrorHandling(); @@ -234,6 +239,11 @@ bool NativeReactNativeFeatureFlags::useRawPropsJsiValue( return ReactNativeFeatureFlags::useRawPropsJsiValue(); } +bool NativeReactNativeFeatureFlags::useShadowNodeStateOnClone( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::useShadowNodeStateOnClone(); +} + bool NativeReactNativeFeatureFlags::useTurboModuleInterop( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::useTurboModuleInterop(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index 54b7e143f8f0ef..bfce77552d5f27 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<<176dd9398c3de7438ff6962cd3415dc8>> */ /** @@ -101,6 +101,8 @@ class NativeReactNativeFeatureFlags bool traceTurboModulePromiseRejectionsOnAndroid(jsi::Runtime& runtime); + bool updateRuntimeShadowNodeReferencesOnCommit(jsi::Runtime& runtime); + bool useAlwaysAvailableJSErrorHandling(jsi::Runtime& runtime); bool useEditTextStockAndroidFocusBehavior(jsi::Runtime& runtime); @@ -113,6 +115,8 @@ class NativeReactNativeFeatureFlags bool useRawPropsJsiValue(jsi::Runtime& runtime); + bool useShadowNodeStateOnClone(jsi::Runtime& runtime); + bool useTurboModuleInterop(jsi::Runtime& runtime); bool useTurboModules(jsi::Runtime& runtime); diff --git a/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.cpp index 4d637853f6ae00..196391bd8c7301 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/ShadowNode.cpp @@ -112,7 +112,9 @@ ShadowNode::ShadowNode( fragment.children ? fragment.children : sourceShadowNode.children_), state_( fragment.state ? fragment.state - : sourceShadowNode.getMostRecentState()), + : (ReactNativeFeatureFlags::useShadowNodeStateOnClone() + ? sourceShadowNode.state_ + : sourceShadowNode.getMostRecentState())), orderIndex_(sourceShadowNode.orderIndex_), family_(sourceShadowNode.family_), traits_(sourceShadowNode.traits_) { diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index 178471f59dfd0e..562444e54abd9f 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -386,6 +386,17 @@ const definitions: FeatureFlagDefinitions = { }, ossReleaseStage: 'none', }, + updateRuntimeShadowNodeReferencesOnCommit: { + defaultValue: false, + metadata: { + dateAdded: '2025-04-15', + description: + 'When enabled, runtime shadow node references will be updated during the commit. This allows running RSNRU from any thread without corrupting the renderer state.', + expectedReleaseValue: true, + purpose: 'experimentation', + }, + ossReleaseStage: 'none', + }, useAlwaysAvailableJSErrorHandling: { defaultValue: false, metadata: { @@ -449,6 +460,17 @@ const definitions: FeatureFlagDefinitions = { }, ossReleaseStage: 'none', }, + useShadowNodeStateOnClone: { + defaultValue: false, + metadata: { + dateAdded: '2025-04-16', + description: + 'Use the state stored on the source shadow node when cloning it instead of reading in the most recent state on the shadow node family.', + expectedReleaseValue: true, + purpose: 'experimentation', + }, + ossReleaseStage: 'none', + }, useTurboModuleInterop: { defaultValue: false, metadata: { diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index d7f0e4f21f1235..893043680c22b6 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<<56e220fb853a266ebb52b97e980669e8>> + * @generated SignedSource<<23e97cba20fdf4afc991cbae70c57b1f>> * @flow strict */ @@ -78,12 +78,14 @@ export type ReactNativeFeatureFlags = $ReadOnly<{ fuseboxNetworkInspectionEnabled: Getter, removeTurboModuleManagerDelegateMutex: Getter, traceTurboModulePromiseRejectionsOnAndroid: Getter, + updateRuntimeShadowNodeReferencesOnCommit: Getter, useAlwaysAvailableJSErrorHandling: Getter, useEditTextStockAndroidFocusBehavior: Getter, useFabricInterop: Getter, useNativeViewConfigsInBridgelessMode: Getter, useOptimizedEventBatchingOnAndroid: Getter, useRawPropsJsiValue: Getter, + useShadowNodeStateOnClone: Getter, useTurboModuleInterop: Getter, useTurboModules: Getter, }>; @@ -280,6 +282,10 @@ export const removeTurboModuleManagerDelegateMutex: Getter = createNati * Enables storing js caller stack when creating promise in native module. This is useful in case of Promise rejection and tracing the cause. */ export const traceTurboModulePromiseRejectionsOnAndroid: Getter = createNativeFlagGetter('traceTurboModulePromiseRejectionsOnAndroid', false); +/** + * When enabled, runtime shadow node references will be updated during the commit. This allows running RSNRU from any thread without corrupting the renderer state. + */ +export const updateRuntimeShadowNodeReferencesOnCommit: Getter = createNativeFlagGetter('updateRuntimeShadowNodeReferencesOnCommit', false); /** * In Bridgeless mode, use the always available javascript error reporting pipeline. */ @@ -304,6 +310,10 @@ export const useOptimizedEventBatchingOnAndroid: Getter = createNativeF * Instead of using folly::dynamic as internal representation in RawProps and RawValue, use jsi::Value */ export const useRawPropsJsiValue: Getter = createNativeFlagGetter('useRawPropsJsiValue', false); +/** + * Use the state stored on the source shadow node when cloning it instead of reading in the most recent state on the shadow node family. + */ +export const useShadowNodeStateOnClone: Getter = createNativeFlagGetter('useShadowNodeStateOnClone', false); /** * In Bridgeless mode, should legacy NativeModules use the TurboModule system? */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index 7ad029050365e2..a5587d3874a09d 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<> + * @generated SignedSource<<1933fe52e53c0af3d46ea46233ef9e02>> * @flow strict */ @@ -56,12 +56,14 @@ export interface Spec extends TurboModule { +fuseboxNetworkInspectionEnabled?: () => boolean; +removeTurboModuleManagerDelegateMutex?: () => boolean; +traceTurboModulePromiseRejectionsOnAndroid?: () => boolean; + +updateRuntimeShadowNodeReferencesOnCommit?: () => boolean; +useAlwaysAvailableJSErrorHandling?: () => boolean; +useEditTextStockAndroidFocusBehavior?: () => boolean; +useFabricInterop?: () => boolean; +useNativeViewConfigsInBridgelessMode?: () => boolean; +useOptimizedEventBatchingOnAndroid?: () => boolean; +useRawPropsJsiValue?: () => boolean; + +useShadowNodeStateOnClone?: () => boolean; +useTurboModuleInterop?: () => boolean; +useTurboModules?: () => boolean; }