diff --git a/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm b/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm index 4ca48c3b70ef..09f19e488262 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm @@ -27,7 +27,6 @@ #import #import #import -#import #import #import 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 5024fe15a313..8a3a0f464bf9 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<> + * @generated SignedSource<> */ /** @@ -114,6 +114,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun enableBridgelessArchitecture(): Boolean = accessor.enableBridgelessArchitecture() + /** + * Route async CallInvoker work through the ReactInstance buffered runtime executor, so it is ordered against callable module calls and cannot run before the JS bundle has finished evaluating. invokeSync is unaffected. + */ + @JvmStatic + public fun enableBufferedCallInvoker(): Boolean = accessor.enableBufferedCallInvoker() + /** * Enable prop iterator setter-style construction of Props in C++ (this flag is not used in Java). */ 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 03b90ae5e4ed..eeef92fa9bdb 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<<0bfeba3d07af6fade47b24974a80a592>> + * @generated SignedSource<<68aefd0293540d56f57e8badc0de04c8>> */ /** @@ -34,6 +34,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces private var enableAccumulatedUpdatesInRawPropsAndroidCache: Boolean? = null private var enableAndroidTextMeasurementOptimizationsCache: Boolean? = null private var enableBridgelessArchitectureCache: Boolean? = null + private var enableBufferedCallInvokerCache: Boolean? = null private var enableCppPropsIteratorSetterCache: Boolean? = null private var enableCustomFocusSearchOnClippedElementsAndroidCache: Boolean? = null private var enableDestroyShadowTreeRevisionAsyncCache: Boolean? = null @@ -232,6 +233,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun enableBufferedCallInvoker(): Boolean { + var cached = enableBufferedCallInvokerCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.enableBufferedCallInvoker() + enableBufferedCallInvokerCache = cached + } + return cached + } + override fun enableCppPropsIteratorSetter(): Boolean { var cached = enableCppPropsIteratorSetterCache 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 ad874487ab7a..5858d3e1cf1b 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<<247f721796621af8615014477518bcd9>> */ /** @@ -56,6 +56,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun enableBridgelessArchitecture(): Boolean + @DoNotStrip @JvmStatic public external fun enableBufferedCallInvoker(): Boolean + @DoNotStrip @JvmStatic public external fun enableCppPropsIteratorSetter(): Boolean @DoNotStrip @JvmStatic public external fun enableCustomFocusSearchOnClippedElementsAndroid(): 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 0ca4d5524bf9..cbddf085960a 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<> + * @generated SignedSource<<33071257f9c96a8664c9af429e387061>> */ /** @@ -51,6 +51,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun enableBridgelessArchitecture(): Boolean = true + override fun enableBufferedCallInvoker(): Boolean = true + override fun enableCppPropsIteratorSetter(): Boolean = false override fun enableCustomFocusSearchOnClippedElementsAndroid(): Boolean = true 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 dab5705e7e45..2c4b30b0e025 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<<3605df96fad767e3ec3957d7305ef926>> + * @generated SignedSource<> */ /** @@ -38,6 +38,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc private var enableAccumulatedUpdatesInRawPropsAndroidCache: Boolean? = null private var enableAndroidTextMeasurementOptimizationsCache: Boolean? = null private var enableBridgelessArchitectureCache: Boolean? = null + private var enableBufferedCallInvokerCache: Boolean? = null private var enableCppPropsIteratorSetterCache: Boolean? = null private var enableCustomFocusSearchOnClippedElementsAndroidCache: Boolean? = null private var enableDestroyShadowTreeRevisionAsyncCache: Boolean? = null @@ -250,6 +251,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc return cached } + override fun enableBufferedCallInvoker(): Boolean { + var cached = enableBufferedCallInvokerCache + if (cached == null) { + cached = currentProvider.enableBufferedCallInvoker() + accessedFeatureFlags.add("enableBufferedCallInvoker") + enableBufferedCallInvokerCache = cached + } + return cached + } + override fun enableCppPropsIteratorSetter(): Boolean { var cached = enableCppPropsIteratorSetterCache 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 366da3d45758..d7d75f50493b 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<<100e31bd98a30aba4abef10f168638fc>> + * @generated SignedSource<<915bf918212b9898319de61d4cadaa13>> */ /** @@ -51,6 +51,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun enableBridgelessArchitecture(): Boolean + @DoNotStrip public fun enableBufferedCallInvoker(): Boolean + @DoNotStrip public fun enableCppPropsIteratorSetter(): Boolean @DoNotStrip public fun enableCustomFocusSearchOnClippedElementsAndroid(): 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 8f8f7cd3a062..baa669d6b96b 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<<177c5cc7f6e970a2d4454c32d7f777ef>> */ /** @@ -123,6 +123,12 @@ class ReactNativeFeatureFlagsJavaProvider return method(javaProvider_); } + bool enableBufferedCallInvoker() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("enableBufferedCallInvoker"); + return method(javaProvider_); + } + bool enableCppPropsIteratorSetter() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("enableCppPropsIteratorSetter"); @@ -623,6 +629,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableBridgelessArchitecture( return ReactNativeFeatureFlags::enableBridgelessArchitecture(); } +bool JReactNativeFeatureFlagsCxxInterop::enableBufferedCallInvoker( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::enableBufferedCallInvoker(); +} + bool JReactNativeFeatureFlagsCxxInterop::enableCppPropsIteratorSetter( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::enableCppPropsIteratorSetter(); @@ -1051,6 +1062,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "enableBridgelessArchitecture", JReactNativeFeatureFlagsCxxInterop::enableBridgelessArchitecture), + makeNativeMethod( + "enableBufferedCallInvoker", + JReactNativeFeatureFlagsCxxInterop::enableBufferedCallInvoker), makeNativeMethod( "enableCppPropsIteratorSetter", JReactNativeFeatureFlagsCxxInterop::enableCppPropsIteratorSetter), 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 71b3da865135..73a8b8bfe5c3 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<<145b12c4a208db86c7bfdfed56cf433f>> + * @generated SignedSource<> */ /** @@ -72,6 +72,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool enableBridgelessArchitecture( facebook::jni::alias_ref); + static bool enableBufferedCallInvoker( + facebook::jni::alias_ref); + static bool enableCppPropsIteratorSetter( facebook::jni::alias_ref); diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.cpp index b6d7e64a82f4..e79a30393b42 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -89,10 +88,11 @@ JReactInstance::JReactInstance( auto unbufferedRuntimeExecutor = instance_->getUnbufferedRuntimeExecutor(); // Set up the JS and native modules call invokers (for TurboModules) - auto jsInvoker = std::make_unique( - instance_->getRuntimeScheduler()); + // Shares the instance's BufferedRuntimeExecutor so async calls from native + // are ordered against callFunctionOnModule and cannot run before the bundle + // has evaluated. invokeSync still goes straight to the scheduler. jsCallInvokerHolder_ = jni::make_global( - CallInvokerHolder::newObjectCxxArgs(std::move(jsInvoker))); + CallInvokerHolder::newObjectCxxArgs(instance_->createJSCallInvoker())); auto nativeMethodCallInvoker = std::make_unique( sharedNativeMessageQueueThread); diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp index 338b21c5a5ff..e2adeca46391 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<<9c1052fdfafd3f0ef6bcdaa740cf25ec>> + * @generated SignedSource<<7b726d7483bb35062b79e582323f0d7e>> */ /** @@ -82,6 +82,10 @@ bool ReactNativeFeatureFlags::enableBridgelessArchitecture() { return getAccessor().enableBridgelessArchitecture(); } +bool ReactNativeFeatureFlags::enableBufferedCallInvoker() { + return getAccessor().enableBufferedCallInvoker(); +} + bool ReactNativeFeatureFlags::enableCppPropsIteratorSetter() { return getAccessor().enableCppPropsIteratorSetter(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index 9ae679bc6177..49079da65ebf 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<<414b7a90eeecd2abe9849955131fb122>> + * @generated SignedSource<<1e9009301b79f977132c4fa5599aebdd>> */ /** @@ -111,6 +111,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool enableBridgelessArchitecture(); + /** + * Route async CallInvoker work through the ReactInstance buffered runtime executor, so it is ordered against callable module calls and cannot run before the JS bundle has finished evaluating. invokeSync is unaffected. + */ + RN_EXPORT static bool enableBufferedCallInvoker(); + /** * Enable prop iterator setter-style construction of Props in C++ (this flag is not used in Java). */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index f0ba8df3dd6c..24db6caafcd3 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<<58600d43eecb5c6593a0edbac4f13ac6>> + * @generated SignedSource<<7b2f18c94d995b2108f91248fdfecb0c>> */ /** @@ -281,6 +281,24 @@ bool ReactNativeFeatureFlagsAccessor::enableBridgelessArchitecture() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::enableBufferedCallInvoker() { + auto flagValue = enableBufferedCallInvoker_.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(14, "enableBufferedCallInvoker"); + + flagValue = currentProvider_->enableBufferedCallInvoker(); + enableBufferedCallInvoker_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::enableCppPropsIteratorSetter() { auto flagValue = enableCppPropsIteratorSetter_.load(); @@ -290,7 +308,7 @@ bool ReactNativeFeatureFlagsAccessor::enableCppPropsIteratorSetter() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(14, "enableCppPropsIteratorSetter"); + markFlagAsAccessed(15, "enableCppPropsIteratorSetter"); flagValue = currentProvider_->enableCppPropsIteratorSetter(); enableCppPropsIteratorSetter_ = flagValue; @@ -308,7 +326,7 @@ bool ReactNativeFeatureFlagsAccessor::enableCustomFocusSearchOnClippedElementsAn // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(15, "enableCustomFocusSearchOnClippedElementsAndroid"); + markFlagAsAccessed(16, "enableCustomFocusSearchOnClippedElementsAndroid"); flagValue = currentProvider_->enableCustomFocusSearchOnClippedElementsAndroid(); enableCustomFocusSearchOnClippedElementsAndroid_ = flagValue; @@ -326,7 +344,7 @@ bool ReactNativeFeatureFlagsAccessor::enableDestroyShadowTreeRevisionAsync() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(16, "enableDestroyShadowTreeRevisionAsync"); + markFlagAsAccessed(17, "enableDestroyShadowTreeRevisionAsync"); flagValue = currentProvider_->enableDestroyShadowTreeRevisionAsync(); enableDestroyShadowTreeRevisionAsync_ = flagValue; @@ -344,7 +362,7 @@ bool ReactNativeFeatureFlagsAccessor::enableDoubleMeasurementFixAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(17, "enableDoubleMeasurementFixAndroid"); + markFlagAsAccessed(18, "enableDoubleMeasurementFixAndroid"); flagValue = currentProvider_->enableDoubleMeasurementFixAndroid(); enableDoubleMeasurementFixAndroid_ = flagValue; @@ -362,7 +380,7 @@ bool ReactNativeFeatureFlagsAccessor::enableEagerRootViewAttachment() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(18, "enableEagerRootViewAttachment"); + markFlagAsAccessed(19, "enableEagerRootViewAttachment"); flagValue = currentProvider_->enableEagerRootViewAttachment(); enableEagerRootViewAttachment_ = flagValue; @@ -380,7 +398,7 @@ bool ReactNativeFeatureFlagsAccessor::enableExclusivePropsUpdateAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(19, "enableExclusivePropsUpdateAndroid"); + markFlagAsAccessed(20, "enableExclusivePropsUpdateAndroid"); flagValue = currentProvider_->enableExclusivePropsUpdateAndroid(); enableExclusivePropsUpdateAndroid_ = flagValue; @@ -398,7 +416,7 @@ bool ReactNativeFeatureFlagsAccessor::enableFabricCommitBranching() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(20, "enableFabricCommitBranching"); + markFlagAsAccessed(21, "enableFabricCommitBranching"); flagValue = currentProvider_->enableFabricCommitBranching(); enableFabricCommitBranching_ = flagValue; @@ -416,7 +434,7 @@ bool ReactNativeFeatureFlagsAccessor::enableFabricLogs() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(21, "enableFabricLogs"); + markFlagAsAccessed(22, "enableFabricLogs"); flagValue = currentProvider_->enableFabricLogs(); enableFabricLogs_ = flagValue; @@ -434,7 +452,7 @@ bool ReactNativeFeatureFlagsAccessor::enableFlexboxAutoMinSizeInStrictMode() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(22, "enableFlexboxAutoMinSizeInStrictMode"); + markFlagAsAccessed(23, "enableFlexboxAutoMinSizeInStrictMode"); flagValue = currentProvider_->enableFlexboxAutoMinSizeInStrictMode(); enableFlexboxAutoMinSizeInStrictMode_ = flagValue; @@ -452,7 +470,7 @@ bool ReactNativeFeatureFlagsAccessor::enableFontScaleChangesUpdatingLayout() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(23, "enableFontScaleChangesUpdatingLayout"); + markFlagAsAccessed(24, "enableFontScaleChangesUpdatingLayout"); flagValue = currentProvider_->enableFontScaleChangesUpdatingLayout(); enableFontScaleChangesUpdatingLayout_ = flagValue; @@ -470,7 +488,7 @@ bool ReactNativeFeatureFlagsAccessor::enableIOSCompressedTextFrameAdjustment() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(24, "enableIOSCompressedTextFrameAdjustment"); + markFlagAsAccessed(25, "enableIOSCompressedTextFrameAdjustment"); flagValue = currentProvider_->enableIOSCompressedTextFrameAdjustment(); enableIOSCompressedTextFrameAdjustment_ = flagValue; @@ -488,7 +506,7 @@ bool ReactNativeFeatureFlagsAccessor::enableIOSTextBaselineOffsetPerLine() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(25, "enableIOSTextBaselineOffsetPerLine"); + markFlagAsAccessed(26, "enableIOSTextBaselineOffsetPerLine"); flagValue = currentProvider_->enableIOSTextBaselineOffsetPerLine(); enableIOSTextBaselineOffsetPerLine_ = flagValue; @@ -506,7 +524,7 @@ bool ReactNativeFeatureFlagsAccessor::enableIOSViewClipToPaddingBox() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(26, "enableIOSViewClipToPaddingBox"); + markFlagAsAccessed(27, "enableIOSViewClipToPaddingBox"); flagValue = currentProvider_->enableIOSViewClipToPaddingBox(); enableIOSViewClipToPaddingBox_ = flagValue; @@ -524,7 +542,7 @@ bool ReactNativeFeatureFlagsAccessor::enableImagePrefetchingAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(27, "enableImagePrefetchingAndroid"); + markFlagAsAccessed(28, "enableImagePrefetchingAndroid"); flagValue = currentProvider_->enableImagePrefetchingAndroid(); enableImagePrefetchingAndroid_ = flagValue; @@ -542,7 +560,7 @@ bool ReactNativeFeatureFlagsAccessor::enableImageTransparentTintColor() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(28, "enableImageTransparentTintColor"); + markFlagAsAccessed(29, "enableImageTransparentTintColor"); flagValue = currentProvider_->enableImageTransparentTintColor(); enableImageTransparentTintColor_ = flagValue; @@ -560,7 +578,7 @@ bool ReactNativeFeatureFlagsAccessor::enableImmediateUpdateModeForContentOffsetC // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(29, "enableImmediateUpdateModeForContentOffsetChanges"); + markFlagAsAccessed(30, "enableImmediateUpdateModeForContentOffsetChanges"); flagValue = currentProvider_->enableImmediateUpdateModeForContentOffsetChanges(); enableImmediateUpdateModeForContentOffsetChanges_ = flagValue; @@ -578,7 +596,7 @@ bool ReactNativeFeatureFlagsAccessor::enableImperativeFocus() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(30, "enableImperativeFocus"); + markFlagAsAccessed(31, "enableImperativeFocus"); flagValue = currentProvider_->enableImperativeFocus(); enableImperativeFocus_ = flagValue; @@ -596,7 +614,7 @@ bool ReactNativeFeatureFlagsAccessor::enableInteropViewManagerClassLookUpOptimiz // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(31, "enableInteropViewManagerClassLookUpOptimizationIOS"); + markFlagAsAccessed(32, "enableInteropViewManagerClassLookUpOptimizationIOS"); flagValue = currentProvider_->enableInteropViewManagerClassLookUpOptimizationIOS(); enableInteropViewManagerClassLookUpOptimizationIOS_ = flagValue; @@ -614,7 +632,7 @@ bool ReactNativeFeatureFlagsAccessor::enableIntersectionObserverByDefault() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(32, "enableIntersectionObserverByDefault"); + markFlagAsAccessed(33, "enableIntersectionObserverByDefault"); flagValue = currentProvider_->enableIntersectionObserverByDefault(); enableIntersectionObserverByDefault_ = flagValue; @@ -632,7 +650,7 @@ bool ReactNativeFeatureFlagsAccessor::enableKeyEvents() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(33, "enableKeyEvents"); + markFlagAsAccessed(34, "enableKeyEvents"); flagValue = currentProvider_->enableKeyEvents(); enableKeyEvents_ = flagValue; @@ -650,7 +668,7 @@ bool ReactNativeFeatureFlagsAccessor::enableLayoutAnimationsOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(34, "enableLayoutAnimationsOnAndroid"); + markFlagAsAccessed(35, "enableLayoutAnimationsOnAndroid"); flagValue = currentProvider_->enableLayoutAnimationsOnAndroid(); enableLayoutAnimationsOnAndroid_ = flagValue; @@ -668,7 +686,7 @@ bool ReactNativeFeatureFlagsAccessor::enableLayoutAnimationsOnIOS() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(35, "enableLayoutAnimationsOnIOS"); + markFlagAsAccessed(36, "enableLayoutAnimationsOnIOS"); flagValue = currentProvider_->enableLayoutAnimationsOnIOS(); enableLayoutAnimationsOnIOS_ = flagValue; @@ -686,7 +704,7 @@ bool ReactNativeFeatureFlagsAccessor::enableModuleArgumentNSNullConversionIOS() // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(36, "enableModuleArgumentNSNullConversionIOS"); + markFlagAsAccessed(37, "enableModuleArgumentNSNullConversionIOS"); flagValue = currentProvider_->enableModuleArgumentNSNullConversionIOS(); enableModuleArgumentNSNullConversionIOS_ = flagValue; @@ -704,7 +722,7 @@ bool ReactNativeFeatureFlagsAccessor::enableMountingCoordinatorPullModelAndroid( // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(37, "enableMountingCoordinatorPullModelAndroid"); + markFlagAsAccessed(38, "enableMountingCoordinatorPullModelAndroid"); flagValue = currentProvider_->enableMountingCoordinatorPullModelAndroid(); enableMountingCoordinatorPullModelAndroid_ = flagValue; @@ -722,7 +740,7 @@ bool ReactNativeFeatureFlagsAccessor::enableMutationObserverByDefault() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(38, "enableMutationObserverByDefault"); + markFlagAsAccessed(39, "enableMutationObserverByDefault"); flagValue = currentProvider_->enableMutationObserverByDefault(); enableMutationObserverByDefault_ = flagValue; @@ -740,7 +758,7 @@ bool ReactNativeFeatureFlagsAccessor::enableNativeCSSParsing() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(39, "enableNativeCSSParsing"); + markFlagAsAccessed(40, "enableNativeCSSParsing"); flagValue = currentProvider_->enableNativeCSSParsing(); enableNativeCSSParsing_ = flagValue; @@ -758,7 +776,7 @@ bool ReactNativeFeatureFlagsAccessor::enablePreparedTextLayout() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(40, "enablePreparedTextLayout"); + markFlagAsAccessed(41, "enablePreparedTextLayout"); flagValue = currentProvider_->enablePreparedTextLayout(); enablePreparedTextLayout_ = flagValue; @@ -776,7 +794,7 @@ bool ReactNativeFeatureFlagsAccessor::enablePropsUpdateReconciliationAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(41, "enablePropsUpdateReconciliationAndroid"); + markFlagAsAccessed(42, "enablePropsUpdateReconciliationAndroid"); flagValue = currentProvider_->enablePropsUpdateReconciliationAndroid(); enablePropsUpdateReconciliationAndroid_ = flagValue; @@ -794,7 +812,7 @@ bool ReactNativeFeatureFlagsAccessor::enableResizeObserverByDefault() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(42, "enableResizeObserverByDefault"); + markFlagAsAccessed(43, "enableResizeObserverByDefault"); flagValue = currentProvider_->enableResizeObserverByDefault(); enableResizeObserverByDefault_ = flagValue; @@ -812,7 +830,7 @@ bool ReactNativeFeatureFlagsAccessor::enableSwiftUIBasedFilters() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(43, "enableSwiftUIBasedFilters"); + markFlagAsAccessed(44, "enableSwiftUIBasedFilters"); flagValue = currentProvider_->enableSwiftUIBasedFilters(); enableSwiftUIBasedFilters_ = flagValue; @@ -830,7 +848,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewCulling() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(44, "enableViewCulling"); + markFlagAsAccessed(45, "enableViewCulling"); flagValue = currentProvider_->enableViewCulling(); enableViewCulling_ = flagValue; @@ -848,7 +866,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecycling() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(45, "enableViewRecycling"); + markFlagAsAccessed(46, "enableViewRecycling"); flagValue = currentProvider_->enableViewRecycling(); enableViewRecycling_ = flagValue; @@ -866,7 +884,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForImage() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(46, "enableViewRecyclingForImage"); + markFlagAsAccessed(47, "enableViewRecyclingForImage"); flagValue = currentProvider_->enableViewRecyclingForImage(); enableViewRecyclingForImage_ = flagValue; @@ -884,7 +902,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForScrollView() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(47, "enableViewRecyclingForScrollView"); + markFlagAsAccessed(48, "enableViewRecyclingForScrollView"); flagValue = currentProvider_->enableViewRecyclingForScrollView(); enableViewRecyclingForScrollView_ = flagValue; @@ -902,7 +920,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForText() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(48, "enableViewRecyclingForText"); + markFlagAsAccessed(49, "enableViewRecyclingForText"); flagValue = currentProvider_->enableViewRecyclingForText(); enableViewRecyclingForText_ = flagValue; @@ -920,7 +938,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForView() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(49, "enableViewRecyclingForView"); + markFlagAsAccessed(50, "enableViewRecyclingForView"); flagValue = currentProvider_->enableViewRecyclingForView(); enableViewRecyclingForView_ = flagValue; @@ -938,7 +956,7 @@ bool ReactNativeFeatureFlagsAccessor::enableVirtualViewContainerStateExperimenta // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(50, "enableVirtualViewContainerStateExperimental"); + markFlagAsAccessed(51, "enableVirtualViewContainerStateExperimental"); flagValue = currentProvider_->enableVirtualViewContainerStateExperimental(); enableVirtualViewContainerStateExperimental_ = flagValue; @@ -956,7 +974,7 @@ bool ReactNativeFeatureFlagsAccessor::fixDifferentiatorParentTagForUnflattenCase // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(51, "fixDifferentiatorParentTagForUnflattenCase"); + markFlagAsAccessed(52, "fixDifferentiatorParentTagForUnflattenCase"); flagValue = currentProvider_->fixDifferentiatorParentTagForUnflattenCase(); fixDifferentiatorParentTagForUnflattenCase_ = flagValue; @@ -974,7 +992,7 @@ bool ReactNativeFeatureFlagsAccessor::fixMappingOfEventPrioritiesBetweenFabricAn // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(52, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); + markFlagAsAccessed(53, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); flagValue = currentProvider_->fixMappingOfEventPrioritiesBetweenFabricAndReact(); fixMappingOfEventPrioritiesBetweenFabricAndReact_ = flagValue; @@ -992,7 +1010,7 @@ bool ReactNativeFeatureFlagsAccessor::fixYogaFlexBasisFitContentInMainAxis() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(53, "fixYogaFlexBasisFitContentInMainAxis"); + markFlagAsAccessed(54, "fixYogaFlexBasisFitContentInMainAxis"); flagValue = currentProvider_->fixYogaFlexBasisFitContentInMainAxis(); fixYogaFlexBasisFitContentInMainAxis_ = flagValue; @@ -1010,7 +1028,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxAssertSingleHostState() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(54, "fuseboxAssertSingleHostState"); + markFlagAsAccessed(55, "fuseboxAssertSingleHostState"); flagValue = currentProvider_->fuseboxAssertSingleHostState(); fuseboxAssertSingleHostState_ = flagValue; @@ -1028,7 +1046,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(55, "fuseboxEnabledRelease"); + markFlagAsAccessed(56, "fuseboxEnabledRelease"); flagValue = currentProvider_->fuseboxEnabledRelease(); fuseboxEnabledRelease_ = flagValue; @@ -1046,7 +1064,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxFrameRecordingEnabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(56, "fuseboxFrameRecordingEnabled"); + markFlagAsAccessed(57, "fuseboxFrameRecordingEnabled"); flagValue = currentProvider_->fuseboxFrameRecordingEnabled(); fuseboxFrameRecordingEnabled_ = flagValue; @@ -1064,7 +1082,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxScreenshotCaptureEnabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(57, "fuseboxScreenshotCaptureEnabled"); + markFlagAsAccessed(58, "fuseboxScreenshotCaptureEnabled"); flagValue = currentProvider_->fuseboxScreenshotCaptureEnabled(); fuseboxScreenshotCaptureEnabled_ = flagValue; @@ -1082,7 +1100,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxWebSocketEventsEnabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(58, "fuseboxWebSocketEventsEnabled"); + markFlagAsAccessed(59, "fuseboxWebSocketEventsEnabled"); flagValue = currentProvider_->fuseboxWebSocketEventsEnabled(); fuseboxWebSocketEventsEnabled_ = flagValue; @@ -1100,7 +1118,7 @@ bool ReactNativeFeatureFlagsAccessor::optimizedAnimatedPropUpdates() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(59, "optimizedAnimatedPropUpdates"); + markFlagAsAccessed(60, "optimizedAnimatedPropUpdates"); flagValue = currentProvider_->optimizedAnimatedPropUpdates(); optimizedAnimatedPropUpdates_ = flagValue; @@ -1118,7 +1136,7 @@ bool ReactNativeFeatureFlagsAccessor::overrideBySynchronousMountPropsAtMountingA // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(60, "overrideBySynchronousMountPropsAtMountingAndroid"); + markFlagAsAccessed(61, "overrideBySynchronousMountPropsAtMountingAndroid"); flagValue = currentProvider_->overrideBySynchronousMountPropsAtMountingAndroid(); overrideBySynchronousMountPropsAtMountingAndroid_ = flagValue; @@ -1136,7 +1154,7 @@ bool ReactNativeFeatureFlagsAccessor::perfIssuesEnabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(61, "perfIssuesEnabled"); + markFlagAsAccessed(62, "perfIssuesEnabled"); flagValue = currentProvider_->perfIssuesEnabled(); perfIssuesEnabled_ = flagValue; @@ -1154,7 +1172,7 @@ bool ReactNativeFeatureFlagsAccessor::perfMonitorV2Enabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(62, "perfMonitorV2Enabled"); + markFlagAsAccessed(63, "perfMonitorV2Enabled"); flagValue = currentProvider_->perfMonitorV2Enabled(); perfMonitorV2Enabled_ = flagValue; @@ -1172,7 +1190,7 @@ double ReactNativeFeatureFlagsAccessor::preparedTextCacheSize() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(63, "preparedTextCacheSize"); + markFlagAsAccessed(64, "preparedTextCacheSize"); flagValue = currentProvider_->preparedTextCacheSize(); preparedTextCacheSize_ = flagValue; @@ -1190,7 +1208,7 @@ bool ReactNativeFeatureFlagsAccessor::preventShadowTreeCommitExhaustion() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(64, "preventShadowTreeCommitExhaustion"); + markFlagAsAccessed(65, "preventShadowTreeCommitExhaustion"); flagValue = currentProvider_->preventShadowTreeCommitExhaustion(); preventShadowTreeCommitExhaustion_ = flagValue; @@ -1208,7 +1226,7 @@ bool ReactNativeFeatureFlagsAccessor::redBoxV2Android() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(65, "redBoxV2Android"); + markFlagAsAccessed(66, "redBoxV2Android"); flagValue = currentProvider_->redBoxV2Android(); redBoxV2Android_ = flagValue; @@ -1226,7 +1244,7 @@ bool ReactNativeFeatureFlagsAccessor::redBoxV2IOS() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(66, "redBoxV2IOS"); + markFlagAsAccessed(67, "redBoxV2IOS"); flagValue = currentProvider_->redBoxV2IOS(); redBoxV2IOS_ = flagValue; @@ -1244,7 +1262,7 @@ bool ReactNativeFeatureFlagsAccessor::shouldPressibilityUseW3CPointerEventsForHo // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(67, "shouldPressibilityUseW3CPointerEventsForHover"); + markFlagAsAccessed(68, "shouldPressibilityUseW3CPointerEventsForHover"); flagValue = currentProvider_->shouldPressibilityUseW3CPointerEventsForHover(); shouldPressibilityUseW3CPointerEventsForHover_ = flagValue; @@ -1262,7 +1280,7 @@ bool ReactNativeFeatureFlagsAccessor::shouldTriggerResponderTransferOnScrollAndr // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(68, "shouldTriggerResponderTransferOnScrollAndroid"); + markFlagAsAccessed(69, "shouldTriggerResponderTransferOnScrollAndroid"); flagValue = currentProvider_->shouldTriggerResponderTransferOnScrollAndroid(); shouldTriggerResponderTransferOnScrollAndroid_ = flagValue; @@ -1280,7 +1298,7 @@ bool ReactNativeFeatureFlagsAccessor::skipActivityIdentityAssertionOnHostPause() // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(69, "skipActivityIdentityAssertionOnHostPause"); + markFlagAsAccessed(70, "skipActivityIdentityAssertionOnHostPause"); flagValue = currentProvider_->skipActivityIdentityAssertionOnHostPause(); skipActivityIdentityAssertionOnHostPause_ = flagValue; @@ -1298,7 +1316,7 @@ bool ReactNativeFeatureFlagsAccessor::syncAndroidClipBoundsWithOverflow() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(70, "syncAndroidClipBoundsWithOverflow"); + markFlagAsAccessed(71, "syncAndroidClipBoundsWithOverflow"); flagValue = currentProvider_->syncAndroidClipBoundsWithOverflow(); syncAndroidClipBoundsWithOverflow_ = flagValue; @@ -1316,7 +1334,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(71, "traceTurboModulePromiseRejectionsOnAndroid"); + markFlagAsAccessed(72, "traceTurboModulePromiseRejectionsOnAndroid"); flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid(); traceTurboModulePromiseRejectionsOnAndroid_ = flagValue; @@ -1334,7 +1352,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(72, "updateRuntimeShadowNodeReferencesOnCommit"); + markFlagAsAccessed(73, "updateRuntimeShadowNodeReferencesOnCommit"); flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommit(); updateRuntimeShadowNodeReferencesOnCommit_ = flagValue; @@ -1352,7 +1370,7 @@ bool ReactNativeFeatureFlagsAccessor::updateRuntimeShadowNodeReferencesOnCommitT // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(73, "updateRuntimeShadowNodeReferencesOnCommitThread"); + markFlagAsAccessed(74, "updateRuntimeShadowNodeReferencesOnCommitThread"); flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommitThread(); updateRuntimeShadowNodeReferencesOnCommitThread_ = flagValue; @@ -1370,7 +1388,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(74, "useAlwaysAvailableJSErrorHandling"); + markFlagAsAccessed(75, "useAlwaysAvailableJSErrorHandling"); flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling(); useAlwaysAvailableJSErrorHandling_ = flagValue; @@ -1388,7 +1406,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(75, "useFabricInterop"); + markFlagAsAccessed(76, "useFabricInterop"); flagValue = currentProvider_->useFabricInterop(); useFabricInterop_ = flagValue; @@ -1406,7 +1424,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(76, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(77, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -1424,7 +1442,7 @@ bool ReactNativeFeatureFlagsAccessor::useNestedScrollViewAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(77, "useNestedScrollViewAndroid"); + markFlagAsAccessed(78, "useNestedScrollViewAndroid"); flagValue = currentProvider_->useNestedScrollViewAndroid(); useNestedScrollViewAndroid_ = flagValue; @@ -1442,7 +1460,7 @@ bool ReactNativeFeatureFlagsAccessor::useSharedAnimatedBackend() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(78, "useSharedAnimatedBackend"); + markFlagAsAccessed(79, "useSharedAnimatedBackend"); flagValue = currentProvider_->useSharedAnimatedBackend(); useSharedAnimatedBackend_ = flagValue; @@ -1460,7 +1478,7 @@ bool ReactNativeFeatureFlagsAccessor::useTraitHiddenOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(79, "useTraitHiddenOnAndroid"); + markFlagAsAccessed(80, "useTraitHiddenOnAndroid"); flagValue = currentProvider_->useTraitHiddenOnAndroid(); useTraitHiddenOnAndroid_ = flagValue; @@ -1478,7 +1496,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(80, "useTurboModuleInterop"); + markFlagAsAccessed(81, "useTurboModuleInterop"); flagValue = currentProvider_->useTurboModuleInterop(); useTurboModuleInterop_ = flagValue; @@ -1496,7 +1514,7 @@ double ReactNativeFeatureFlagsAccessor::viewCullingOutsetRatio() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(81, "viewCullingOutsetRatio"); + markFlagAsAccessed(82, "viewCullingOutsetRatio"); flagValue = currentProvider_->viewCullingOutsetRatio(); viewCullingOutsetRatio_ = flagValue; @@ -1514,7 +1532,7 @@ bool ReactNativeFeatureFlagsAccessor::viewTransitionEnabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(82, "viewTransitionEnabled"); + markFlagAsAccessed(83, "viewTransitionEnabled"); flagValue = currentProvider_->viewTransitionEnabled(); viewTransitionEnabled_ = flagValue; @@ -1532,7 +1550,7 @@ bool ReactNativeFeatureFlagsAccessor::viewTransitionUseHardwareBitmapAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(83, "viewTransitionUseHardwareBitmapAndroid"); + markFlagAsAccessed(84, "viewTransitionUseHardwareBitmapAndroid"); flagValue = currentProvider_->viewTransitionUseHardwareBitmapAndroid(); viewTransitionUseHardwareBitmapAndroid_ = flagValue; @@ -1550,7 +1568,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(84, "virtualViewPrerenderRatio"); + markFlagAsAccessed(85, "virtualViewPrerenderRatio"); flagValue = currentProvider_->virtualViewPrerenderRatio(); virtualViewPrerenderRatio_ = flagValue; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index 179a6cafc5a7..c0716136aeb7 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<> */ /** @@ -48,6 +48,7 @@ class ReactNativeFeatureFlagsAccessor { bool enableAccumulatedUpdatesInRawPropsAndroid(); bool enableAndroidTextMeasurementOptimizations(); bool enableBridgelessArchitecture(); + bool enableBufferedCallInvoker(); bool enableCppPropsIteratorSetter(); bool enableCustomFocusSearchOnClippedElementsAndroid(); bool enableDestroyShadowTreeRevisionAsync(); @@ -130,7 +131,7 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 85> accessedFeatureFlags_; + std::array, 86> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> cdpInteractionMetricsEnabled_; @@ -146,6 +147,7 @@ class ReactNativeFeatureFlagsAccessor { std::atomic> enableAccumulatedUpdatesInRawPropsAndroid_; std::atomic> enableAndroidTextMeasurementOptimizations_; std::atomic> enableBridgelessArchitecture_; + std::atomic> enableBufferedCallInvoker_; std::atomic> enableCppPropsIteratorSetter_; std::atomic> enableCustomFocusSearchOnClippedElementsAndroid_; std::atomic> enableDestroyShadowTreeRevisionAsync_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index 7949c5b62064..0b167dc52b96 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<<9e798b7ae2a2f26097359ca37fa99d04>> + * @generated SignedSource<<2a5f641d6506566cc26cb76f62300bbb>> */ /** @@ -85,6 +85,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return true; } + bool enableBufferedCallInvoker() override { + return true; + } + bool enableCppPropsIteratorSetter() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h index eb90dd2d5145..a296d81dd673 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<<3429660cde44d793af0e86ff425b1094>> + * @generated SignedSource<<570eb4a5cab112e5f8ea0b4fb1fa205c>> */ /** @@ -173,6 +173,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef return ReactNativeFeatureFlagsDefaults::enableBridgelessArchitecture(); } + bool enableBufferedCallInvoker() override { + auto value = values_["enableBufferedCallInvoker"]; + if (!value.isNull()) { + return value.getBool(); + } + + return ReactNativeFeatureFlagsDefaults::enableBufferedCallInvoker(); + } + bool enableCppPropsIteratorSetter() override { auto value = values_["enableCppPropsIteratorSetter"]; if (!value.isNull()) { diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index d4da63764a89..1fe8ae4c5de5 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<<281f4bad9056734eec71185a3fdd6483>> + * @generated SignedSource<<0bbf1352906bbe1642cab3d2b92173e6>> */ /** @@ -41,6 +41,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool enableAccumulatedUpdatesInRawPropsAndroid() = 0; virtual bool enableAndroidTextMeasurementOptimizations() = 0; virtual bool enableBridgelessArchitecture() = 0; + virtual bool enableBufferedCallInvoker() = 0; virtual bool enableCppPropsIteratorSetter() = 0; virtual bool enableCustomFocusSearchOnClippedElementsAndroid() = 0; virtual bool enableDestroyShadowTreeRevisionAsync() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index bdd78c775a5e..fe848aff41dc 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<<54cf6211f3dbfc379c6058cbc9d9af07>> + * @generated SignedSource<<7505981b27be5298787edef4d80527e8>> */ /** @@ -114,6 +114,11 @@ bool NativeReactNativeFeatureFlags::enableBridgelessArchitecture( return ReactNativeFeatureFlags::enableBridgelessArchitecture(); } +bool NativeReactNativeFeatureFlags::enableBufferedCallInvoker( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::enableBufferedCallInvoker(); +} + bool NativeReactNativeFeatureFlags::enableCppPropsIteratorSetter( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::enableCppPropsIteratorSetter(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index c3be1b5fba54..33154de77629 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<<2c30d3942ab1183a99091db3566c020d>> + * @generated SignedSource<> */ /** @@ -66,6 +66,8 @@ class NativeReactNativeFeatureFlags bool enableBridgelessArchitecture(jsi::Runtime& runtime); + bool enableBufferedCallInvoker(jsi::Runtime& runtime); + bool enableCppPropsIteratorSetter(jsi::Runtime& runtime); bool enableCustomFocusSearchOnClippedElementsAndroid(jsi::Runtime& runtime); diff --git a/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeSchedulerCallInvoker.h b/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeSchedulerCallInvoker.h index daa7420b81af..f10c06b7ca0a 100644 --- a/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeSchedulerCallInvoker.h +++ b/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeSchedulerCallInvoker.h @@ -19,7 +19,9 @@ class RuntimeScheduler; * Exposes RuntimeScheduler to native modules. All calls invoked on JavaScript * queue from native modules will be funneled through RuntimeScheduler. */ -class RuntimeSchedulerCallInvoker : public CallInvoker { +class [[deprecated( + "Use ReactInstance::createJSCallInvoker(), which shares the instance's buffered runtime executor so async calls are ordered against callable module calls")]] +RuntimeSchedulerCallInvoker : public CallInvoker { public: RuntimeSchedulerCallInvoker(std::weak_ptr runtimeScheduler); diff --git a/packages/react-native/ReactCommon/react/runtime/BufferedRuntimeExecutor.cpp b/packages/react-native/ReactCommon/react/runtime/BufferedRuntimeExecutor.cpp index db6dc089b6eb..63c293f38ceb 100644 --- a/packages/react-native/ReactCommon/react/runtime/BufferedRuntimeExecutor.cpp +++ b/packages/react-native/ReactCommon/react/runtime/BufferedRuntimeExecutor.cpp @@ -7,18 +7,22 @@ #include "BufferedRuntimeExecutor.h" +#include +#include + namespace facebook::react { -BufferedRuntimeExecutor::BufferedRuntimeExecutor( - RuntimeExecutor runtimeExecutor) - : runtimeExecutor_(std::move(runtimeExecutor)), +BufferedRuntimeExecutor::BufferedRuntimeExecutor(Executor executor) + : executor_(std::move(executor)), isBufferingEnabled_(true), lastIndex_(0) {} -void BufferedRuntimeExecutor::execute(Work&& callback) { +void BufferedRuntimeExecutor::execute( + SchedulerPriority priority, + Work&& callback) { if (!isBufferingEnabled_) { - // Fast path: Schedule directly to RuntimeExecutor, without locking - runtimeExecutor_(std::move(callback)); + // Fast path: Schedule directly to the executor, without locking + executor_(priority, std::move(callback)); return; } @@ -30,14 +34,31 @@ void BufferedRuntimeExecutor::execute(Work&& callback) { uint64_t newIndex = lastIndex_++; std::scoped_lock guard(lock_); if (isBufferingEnabled_) { - queue_.push({.index_ = newIndex, .work_ = std::move(callback)}); + queue_.push_back( + {.index_ = newIndex, + .work_ = std::move(callback), + .priority_ = priority}); return; } // Force flush the queue to maintain the execution order. unsafeFlush(); - runtimeExecutor_(std::move(callback)); + executor_(priority, std::move(callback)); +} + +RuntimeExecutor BufferedRuntimeExecutor::asRuntimeExecutor() { + return [self = shared_from_this()](Work&& callback) { + self->execute(SchedulerPriority::ImmediatePriority, std::move(callback)); + }; +} + +RuntimeExecutor BufferedRuntimeExecutor::asWeakRuntimeExecutor() { + return [weakSelf = weak_from_this()](Work&& callback) { + if (auto self = weakSelf.lock()) { + self->execute(SchedulerPriority::ImmediatePriority, std::move(callback)); + } + }; } void BufferedRuntimeExecutor::flush() { @@ -47,11 +68,20 @@ void BufferedRuntimeExecutor::flush() { } void BufferedRuntimeExecutor::unsafeFlush() { - while (!queue_.empty()) { - const BufferedWork& bufferedWork = queue_.top(); - Work work = bufferedWork.work_; - runtimeExecutor_(std::move(work)); - queue_.pop(); + // Indices are handed out before the lock is taken, so arrival order can + // differ from submission order. Sorting once here restores it, and costs less + // than a heap did: nothing sifts on the way in, and each callback is moved + // out rather than copied. + auto batch = std::move(queue_); + queue_.clear(); + std::sort( + batch.begin(), + batch.end(), + [](const BufferedWork& lhs, const BufferedWork& rhs) { + return lhs.index_ < rhs.index_; + }); + for (auto& bufferedWork : batch) { + executor_(bufferedWork.priority_, std::move(bufferedWork.work_)); } } diff --git a/packages/react-native/ReactCommon/react/runtime/BufferedRuntimeExecutor.h b/packages/react-native/ReactCommon/react/runtime/BufferedRuntimeExecutor.h index 274015587fde..8134804eb1ec 100644 --- a/packages/react-native/ReactCommon/react/runtime/BufferedRuntimeExecutor.h +++ b/packages/react-native/ReactCommon/react/runtime/BufferedRuntimeExecutor.h @@ -8,32 +8,47 @@ #pragma once #include +#include #include #include +#include #include -#include +#include namespace facebook::react { -class BufferedRuntimeExecutor { +class BufferedRuntimeExecutor : public std::enable_shared_from_this { public: using Work = std::function; - // A utility structure to track pending work in the order of when they arrive. - struct BufferedWork { - uint64_t index_; - Work work_; - bool operator<(const BufferedWork &rhs) const - { - // Higher index has lower priority, so this inverted comparison puts - // the smaller index on top of the queue. - return index_ > rhs.index_; - } - }; + // Drains one piece of buffered work, priority may be ignored + using Executor = std::function; + + BufferedRuntimeExecutor(Executor executor); + + void execute(Work &&callback) + { + execute(SchedulerPriority::ImmediatePriority, std::move(callback)); + } - BufferedRuntimeExecutor(RuntimeExecutor runtimeExecutor); + /** + * Buffers [callback] alongside work submitted through the other overload, + * preserving submission order between them, and dispatches it at [priority] + * once flushed. + */ + void execute(SchedulerPriority priority, Work &&callback); - void execute(Work &&callback); + /** + * RuntimeExecutor, keeping this class alive for as long as the result is + * held. + */ + RuntimeExecutor asRuntimeExecutor(); + + /** + * RuntimeExecutor, keeping a weak reference to this class, so it does not + * keep the runtime alive unnecessarily. + */ + RuntimeExecutor asWeakRuntimeExecutor(); // Flush buffered JS calls and then diable JS buffering void flush(); @@ -42,11 +57,18 @@ class BufferedRuntimeExecutor { // Perform flushing without locking mechanism void unsafeFlush(); - RuntimeExecutor runtimeExecutor_; + // A utility structure to track pending work in the order of when they arrive. + struct BufferedWork { + uint64_t index_; + Work work_; + SchedulerPriority priority_; + }; + + Executor executor_; std::atomic isBufferingEnabled_; std::mutex lock_; std::atomic lastIndex_; - std::priority_queue queue_; + std::vector queue_; }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/runtime/CallInvokerImpl.cpp b/packages/react-native/ReactCommon/react/runtime/CallInvokerImpl.cpp new file mode 100644 index 000000000000..6de26f5b18ff --- /dev/null +++ b/packages/react-native/ReactCommon/react/runtime/CallInvokerImpl.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "CallInvokerImpl.h" + +#include + +namespace facebook::react { + +CallInvokerImpl::CallInvokerImpl( + std::shared_ptr bufferedRuntimeExecutor, + std::weak_ptr runtimeScheduler) + : bufferedRuntimeExecutor_(std::move(bufferedRuntimeExecutor)), + runtimeScheduler_(std::move(runtimeScheduler)) {} + +void CallInvokerImpl::invokeAsync(CallFunc&& func) noexcept { + // Held for the duration of the call: `BufferedRuntimeExecutor` reaches the + // scheduler through a raw pointer, which is only safe while the instance that + // owns it is alive. A CallInvoker outlives its instance routinely — a caller + // can hold one across a reload — so the weak reference is what keeps this + // from dispatching into a destroyed scheduler. Dropping the work matches what + // `RuntimeSchedulerCallInvoker` does once its scheduler is gone. + if (auto runtimeScheduler = runtimeScheduler_.lock()) { + // No priority given, so this takes the executor's default — matching what + // `RuntimeSchedulerCallInvoker` did via `scheduleWork`. + bufferedRuntimeExecutor_->execute(std::move(func)); + } +} + +void CallInvokerImpl::invokeAsync( + SchedulerPriority priority, + CallFunc&& func) noexcept { + if (auto runtimeScheduler = runtimeScheduler_.lock()) { + bufferedRuntimeExecutor_->execute(priority, std::move(func)); + } +} + +void CallInvokerImpl::invokeSync(CallFunc&& func) { + if (auto runtimeScheduler = runtimeScheduler_.lock()) { + runtimeScheduler->executeNowOnTheSameThread(std::move(func)); + } +} + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/runtime/CallInvokerImpl.h b/packages/react-native/ReactCommon/react/runtime/CallInvokerImpl.h new file mode 100644 index 000000000000..f4b44505ac1b --- /dev/null +++ b/packages/react-native/ReactCommon/react/runtime/CallInvokerImpl.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include +#include +#include +#include + +#include + +namespace facebook::react { + +/** + * The bridgeless CallInvoker. Shares the instance's BufferedRuntimeExecutor, so async + * calls from native are ordered against `callFunctionOnModule` and the rest of + * the work that executor carries, and none of it runs before the main bundle + * has finished evaluating. + * + * Without this, the two channels reach the same RuntimeScheduler queue by + * different routes — the CallInvoker straight to `scheduleTask`, module calls + * through the buffer — so native code that issues both cannot rely on the order + * it issued them in. + * + * `invokeSync` is deliberately not buffered: a synchronous call cannot wait for + * a flush that only happens once the bundle has run, so it goes directly to the + * scheduler as before. + */ +class CallInvokerImpl : public CallInvoker { + public: + CallInvokerImpl( + std::shared_ptr bufferedRuntimeExecutor, + std::weak_ptr runtimeScheduler); + + void invokeAsync(CallFunc &&func) noexcept override; + + void invokeAsync(SchedulerPriority priority, CallFunc &&func) noexcept override; + + void invokeSync(CallFunc &&func) override; + + private: + std::shared_ptr bufferedRuntimeExecutor_; + std::weak_ptr runtimeScheduler_; +}; + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp b/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp index 288bde9d70f6..0e97a62fd2c8 100644 --- a/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp +++ b/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -42,7 +43,6 @@ std::shared_ptr createRuntimeScheduler( // FIXME: Move creation of PerformanceEntryReporter to here and // guarantee that its lifetime is the same as the runtime. PerformanceEntryReporter::getInstance().get()); - return scheduler; } @@ -112,34 +112,30 @@ ReactInstance::ReactInstance( if (parentInspectorTarget_ != nullptr) { auto executor = parentInspectorTarget_->executorFromThis(); + // This buffer sits *below* the RuntimeScheduler — it is what feeds it — so + // there is nothing here that could act on a priority, and passing one + // through would have nowhere to go. Its only caller is + // `runtimeExecutorThatExecutesAfterInspectorSetup` below, a plain + // RuntimeExecutor, so in practice everything arrives at the default. auto bufferedRuntimeExecutorThatWaitsForInspectorSetup = - std::make_shared(runtimeExecutor); - auto runtimeExecutorThatExecutesAfterInspectorSetup = - [bufferedRuntimeExecutorThatWaitsForInspectorSetup]( - std::function&& callback) { - bufferedRuntimeExecutorThatWaitsForInspectorSetup->execute( - std::move(callback)); - }; + std::make_shared( + [runtimeExecutor]( + SchedulerPriority /*priority*/, + std::function&& callback) { + runtimeExecutor(std::move(callback)); + }); runtimeScheduler_ = createRuntimeScheduler( - runtimeExecutorThatExecutesAfterInspectorSetup, + bufferedRuntimeExecutorThatWaitsForInspectorSetup->asRuntimeExecutor(), [jsErrorHandler = jsErrorHandler_]( jsi::Runtime& runtime, jsi::JSError& error) { jsErrorHandler->handleError(runtime, error, true); }); - auto runtimeExecutorThatGoesThroughRuntimeScheduler = - [runtimeScheduler = runtimeScheduler_.get()]( - std::function&& callback) { - runtimeScheduler->scheduleWork(std::move(callback)); - }; - // This code can execute from any thread, so we need to make sure we set up // the inspector logic in the right one. The callback executes immediately // if we are already in the right thread. - executor([this, - runtimeExecutorThatGoesThroughRuntimeScheduler, - bufferedRuntimeExecutorThatWaitsForInspectorSetup]( + executor([this, bufferedRuntimeExecutorThatWaitsForInspectorSetup]( jsinspector_modern::HostTarget& hostTarget) { // Callbacks scheduled through the page target executor are generally // not guaranteed to run (e.g.: if the page target is destroyed) @@ -150,8 +146,7 @@ ReactInstance::ReactInstance( // creation task to finish before starting the destruction. inspectorTarget_ = &hostTarget.registerInstance(*this); runtimeInspectorTarget_ = &inspectorTarget_->registerRuntime( - runtime_->getRuntimeTargetDelegate(), - runtimeExecutorThatGoesThroughRuntimeScheduler); + runtime_->getRuntimeTargetDelegate(), getUnbufferedRuntimeExecutor()); bufferedRuntimeExecutorThatWaitsForInspectorSetup->flush(); }); } else { @@ -168,10 +163,14 @@ ReactInstance::ReactInstance( setHermesEventLoopControl(runtime, runtimeScheduler); }); + // Note that bufferedRuntimeExecutor_ only has a raw pointer to + // RuntimeScheduler It should always be retained weakly, as it should be + // destroyed when the runtime is. bufferedRuntimeExecutor_ = std::make_shared( [runtimeScheduler = runtimeScheduler_.get()]( + SchedulerPriority priority, std::function&& callback) { - runtimeScheduler->scheduleWork(std::move(callback)); + runtimeScheduler->scheduleTask(priority, std::move(callback)); }); } ReactInstance::~ReactInstance() noexcept { @@ -200,7 +199,8 @@ void ReactInstance::unregisterFromInspector() { RuntimeExecutor ReactInstance::getUnbufferedRuntimeExecutor() noexcept { return [runtimeScheduler = runtimeScheduler_.get()]( std::function&& callback) { - runtimeScheduler->scheduleWork(std::move(callback)); + runtimeScheduler->scheduleTask( + SchedulerPriority::ImmediatePriority, std::move(callback)); }; } @@ -209,14 +209,7 @@ RuntimeExecutor ReactInstance::getUnbufferedRuntimeExecutor() noexcept { // getUnbufferedRuntimeExecutor() instead if you do not need the main JS // bundle to have finished. e.g. setting global variables into JS runtime. RuntimeExecutor ReactInstance::getBufferedRuntimeExecutor() noexcept { - return [weakBufferedRuntimeExecutor_ = - std::weak_ptr(bufferedRuntimeExecutor_)]( - std::function&& callback) { - if (auto strongBufferedRuntimeExecutor_ = - weakBufferedRuntimeExecutor_.lock()) { - strongBufferedRuntimeExecutor_->execute(std::move(callback)); - } - }; + return bufferedRuntimeExecutor_->asWeakRuntimeExecutor(); } // TODO(T184010230): Should the RuntimeScheduler returned from this method be @@ -226,6 +219,19 @@ ReactInstance::getRuntimeScheduler() noexcept { return runtimeScheduler_; } +std::shared_ptr ReactInstance::createJSCallInvoker() noexcept { + if (ReactNativeFeatureFlags::enableBufferedCallInvoker()) { + return std::make_shared( + bufferedRuntimeExecutor_, runtimeScheduler_); + } + // The flag-off path, and the last use of the deprecated invoker. It goes when + // `enableBufferedCallInvoker` is cleaned up. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return std::make_shared(runtimeScheduler_); +#pragma clang diagnostic pop +} + namespace { // Copied from JSIExecutor.cpp @@ -319,12 +325,6 @@ void ReactInstance::callFunctionOnModule( const std::string& moduleName, const std::string& methodName, folly::dynamic&& args) { - if (bufferedRuntimeExecutor_ == nullptr) { - LOG(ERROR) - << "Calling callFunctionOnModule with null BufferedRuntimeExecutor"; - return; - } - bufferedRuntimeExecutor_->execute([this, moduleName = moduleName, methodName = methodName, diff --git a/packages/react-native/ReactCommon/react/runtime/ReactInstance.h b/packages/react-native/ReactCommon/react/runtime/ReactInstance.h index b850d0fac316..24d5d5d17e9e 100644 --- a/packages/react-native/ReactCommon/react/runtime/ReactInstance.h +++ b/packages/react-native/ReactCommon/react/runtime/ReactInstance.h @@ -7,6 +7,7 @@ #pragma once +#include #include #include #include @@ -15,6 +16,7 @@ #include #include #include +#include #include #include @@ -42,6 +44,16 @@ class ReactInstance final : private jsinspector_modern::InstanceTargetDelegate { std::shared_ptr getRuntimeScheduler() noexcept; + /** + * The CallInvoker platforms should hand to TurboModules and other native + * callers. Behind `enableBufferedCallInvoker` this shares the instance's + * BufferedRuntimeExecutor, so async calls are ordered against + * `callFunctionOnModule` and do not run before the main bundle has finished + * evaluating; otherwise it is the unbuffered RuntimeScheduler-backed invoker. + * See CallInvokerImpl. + */ + std::shared_ptr createJSCallInvoker() noexcept; + struct JSRuntimeFlags { bool isProfiling = false; const std::string runtimeDiagnosticFlags = {}; diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm index 036551395323..de522b07d035 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm @@ -41,7 +41,6 @@ #import #import #import -#import #import #import #import @@ -333,7 +332,7 @@ - (void)_start RuntimeExecutor bufferedRuntimeExecutor = _reactInstance->getBufferedRuntimeExecutor(); timerManager->setRuntimeExecutor(bufferedRuntimeExecutor); - auto jsCallInvoker = make_shared(_reactInstance->getRuntimeScheduler()); + auto jsCallInvoker = _reactInstance->createJSCallInvoker(); RCTBridgeProxy *bridgeProxy = [[RCTBridgeProxy alloc] initWithViewRegistry:_bridgeModuleDecorator.viewRegistry_DEPRECATED moduleRegistry:_bridgeModuleDecorator.moduleRegistry diff --git a/packages/react-native/ReactCommon/react/runtime/tests/cxx/BufferedRuntimeExecutorTest.cpp b/packages/react-native/ReactCommon/react/runtime/tests/cxx/BufferedRuntimeExecutorTest.cpp new file mode 100644 index 000000000000..c05ff581b162 --- /dev/null +++ b/packages/react-native/ReactCommon/react/runtime/tests/cxx/BufferedRuntimeExecutorTest.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include + +#include +#include + +namespace facebook::react { + +namespace { + +/** + * Records what the executor was handed, without a runtime: these tests are + * about what is dispatched, in what order and at what priority, not about + * running it. + */ +struct RecordingExecutor { + std::vector priorities; + + BufferedRuntimeExecutor::Executor executor() { + return [this]( + SchedulerPriority priority, + std::function&& /*callback*/) { + priorities.push_back(priority); + }; + } +}; + +void noopWork(jsi::Runtime& /* unused */) {} + +} // namespace + +TEST(BufferedRuntimeExecutorTest, BuffersUntilFlushed) { + RecordingExecutor recorder; + auto bufferedExecutor = + std::make_shared(recorder.executor()); + + bufferedExecutor->execute(noopWork); + bufferedExecutor->execute(SchedulerPriority::LowPriority, noopWork); + + EXPECT_TRUE(recorder.priorities.empty()); + + bufferedExecutor->flush(); + + EXPECT_EQ(recorder.priorities.size(), 2u); +} + +TEST(BufferedRuntimeExecutorTest, PreservesSubmissionOrderAcrossBothOverloads) { + RecordingExecutor recorder; + auto bufferedExecutor = + std::make_shared(recorder.executor()); + + // The point of the shared buffer: work submitted with and without a priority + // is one ordered stream, so a caller that issues a module call and then a + // CallInvoker task gets them in that order. + bufferedExecutor->execute(noopWork); + bufferedExecutor->execute(SchedulerPriority::LowPriority, noopWork); + bufferedExecutor->execute(noopWork); + + bufferedExecutor->flush(); + + // The unprioritised overload reports as Immediate, which is what the modern + // scheduler's `scheduleWork` gave it before this class carried priorities. + ASSERT_EQ(recorder.priorities.size(), 3u); + EXPECT_EQ(recorder.priorities[0], SchedulerPriority::ImmediatePriority); + EXPECT_EQ(recorder.priorities[1], SchedulerPriority::LowPriority); + EXPECT_EQ(recorder.priorities[2], SchedulerPriority::ImmediatePriority); +} + +TEST(BufferedRuntimeExecutorTest, CarriesPriorityThroughTheBuffer) { + RecordingExecutor recorder; + auto bufferedExecutor = + std::make_shared(recorder.executor()); + + bufferedExecutor->execute(SchedulerPriority::LowPriority, noopWork); + bufferedExecutor->execute(SchedulerPriority::ImmediatePriority, noopWork); + bufferedExecutor->flush(); + + ASSERT_EQ(recorder.priorities.size(), 2u); + EXPECT_EQ(recorder.priorities[0], SchedulerPriority::LowPriority); + EXPECT_EQ(recorder.priorities[1], SchedulerPriority::ImmediatePriority); +} + +TEST(BufferedRuntimeExecutorTest, PassesThroughOnceFlushed) { + RecordingExecutor recorder; + BufferedRuntimeExecutor bufferedExecutor(recorder.executor()); + bufferedExecutor.flush(); + + bufferedExecutor.execute(noopWork); + bufferedExecutor.execute(SchedulerPriority::IdlePriority, noopWork); + + ASSERT_EQ(recorder.priorities.size(), 2u); + EXPECT_EQ(recorder.priorities[0], SchedulerPriority::ImmediatePriority); + EXPECT_EQ(recorder.priorities[1], SchedulerPriority::IdlePriority); +} + +} // namespace facebook::react diff --git a/packages/react-native/ReactCxxPlatform/react/runtime/ReactHost.cpp b/packages/react-native/ReactCxxPlatform/react/runtime/ReactHost.cpp index eb6e5f1fe5f0..2ef17cbfb33b 100644 --- a/packages/react-native/ReactCxxPlatform/react/runtime/ReactHost.cpp +++ b/packages/react-native/ReactCxxPlatform/react/runtime/ReactHost.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -248,8 +247,10 @@ void ReactHost::createReactInstance() { reactInstanceData_->mountingManager->setUIManager(scheduler_->getUIManager()); - auto jsInvoker = std::make_shared( - reactInstance_->getRuntimeScheduler()); + // Behind `enableBufferedCallInvoker` this shares the instance's buffered + // runtime executor, so async calls are ordered against callable module calls + // and cannot run before the bundle has evaluated. + auto jsInvoker = reactInstance_->createJSCallInvoker(); if (inspector_ != nullptr) { inspector_->connectDebugger(devServerHelper_->getInspectorUrl()); diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index ded56d146886..2166f296602a 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -200,6 +200,16 @@ const definitions: FeatureFlagDefinitions = { }, ossReleaseStage: 'stable', }, + enableBufferedCallInvoker: { + defaultValue: true, + metadata: { + description: + 'Route async CallInvoker work through the ReactInstance buffered runtime executor, so it is ordered against callable module calls and cannot run before the JS bundle has finished evaluating. invokeSync is unaffected.', + expectedReleaseValue: true, + purpose: 'release', + }, + ossReleaseStage: 'none', + }, enableCppPropsIteratorSetter: { defaultValue: false, metadata: { diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index c62bad74d895..e9e97cc712a9 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<<0774261e9f27a2df5005e11317556f83>> + * @generated SignedSource<> * @flow strict * @noformat */ @@ -63,6 +63,7 @@ export type ReactNativeFeatureFlags = Readonly<{ enableAccumulatedUpdatesInRawPropsAndroid: Getter, enableAndroidTextMeasurementOptimizations: Getter, enableBridgelessArchitecture: Getter, + enableBufferedCallInvoker: Getter, enableCppPropsIteratorSetter: Getter, enableCustomFocusSearchOnClippedElementsAndroid: Getter, enableDestroyShadowTreeRevisionAsync: Getter, @@ -266,6 +267,10 @@ export const enableAndroidTextMeasurementOptimizations: Getter = create * Feature flag to enable the new bridgeless architecture. */ export const enableBridgelessArchitecture: Getter = createNativeFlagGetter('enableBridgelessArchitecture', true); +/** + * Route async CallInvoker work through the ReactInstance buffered runtime executor, so it is ordered against callable module calls and cannot run before the JS bundle has finished evaluating. invokeSync is unaffected. + */ +export const enableBufferedCallInvoker: Getter = createNativeFlagGetter('enableBufferedCallInvoker', true); /** * Enable prop iterator setter-style construction of Props in C++ (this flag is not used in Java). */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index 7d646a6a59df..32be0cf9d394 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<> * @flow strict * @noformat */ @@ -39,6 +39,7 @@ export interface Spec extends TurboModule { readonly enableAccumulatedUpdatesInRawPropsAndroid?: () => boolean; readonly enableAndroidTextMeasurementOptimizations?: () => boolean; readonly enableBridgelessArchitecture?: () => boolean; + readonly enableBufferedCallInvoker?: () => boolean; readonly enableCppPropsIteratorSetter?: () => boolean; readonly enableCustomFocusSearchOnClippedElementsAndroid?: () => boolean; readonly enableDestroyShadowTreeRevisionAsync?: () => boolean; diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api index 9ec346522d04..542ca8a73524 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api @@ -1901,19 +1901,17 @@ class facebook::react::BridgelessNativeMethodCallInvoker : public facebook::reac public virtual void invokeSync(const std::string& methodName, facebook::react::NativeMethodCallFunc&& func) override; } -class facebook::react::BufferedRuntimeExecutor { - public BufferedRuntimeExecutor(facebook::react::RuntimeExecutor runtimeExecutor); +class facebook::react::BufferedRuntimeExecutor : public std::enable_shared_from_this { + public BufferedRuntimeExecutor(facebook::react::BufferedRuntimeExecutor::Executor executor); + public facebook::react::RuntimeExecutor asRuntimeExecutor(); + public facebook::react::RuntimeExecutor asWeakRuntimeExecutor(); + public using Executor = std::function; public using Work = std::function; public void execute(facebook::react::BufferedRuntimeExecutor::Work&& callback); + public void execute(facebook::react::SchedulerPriority priority, facebook::react::BufferedRuntimeExecutor::Work&& callback); public void flush(); } -struct facebook::react::BufferedRuntimeExecutor::BufferedWork { - public bool operator<(const facebook::react::BufferedRuntimeExecutor::BufferedWork& rhs) const; - public facebook::react::BufferedRuntimeExecutor::Work work_; - public uint64_t index_; -} - class facebook::react::CSSSyntaxParser { public constexpr CSSSyntaxParser(const facebook::react::CSSSyntaxParser&) = default; public constexpr CSSSyntaxParser(facebook::react::CSSSyntaxParser&&) = default; @@ -1977,6 +1975,13 @@ class facebook::react::CallInvokerHolder : public jni::HybridClass getCallInvoker(); } +class facebook::react::CallInvokerImpl : public facebook::react::CallInvoker { + public CallInvokerImpl(std::shared_ptr bufferedRuntimeExecutor, std::weak_ptr runtimeScheduler); + public virtual void invokeAsync(facebook::react::CallFunc&& func) noexcept override; + public virtual void invokeAsync(facebook::react::SchedulerPriority priority, facebook::react::CallFunc&& func) noexcept override; + public virtual void invokeSync(facebook::react::CallFunc&& func) override; +} + class facebook::react::CallbackWrapper : public facebook::react::LongLivedObject { public facebook::jsi::Function& callback() noexcept; public facebook::jsi::Runtime& runtime() noexcept; @@ -4317,6 +4322,7 @@ class facebook::react::ReactInstance { public facebook::react::ReactInstance& operator=(facebook::react::ReactInstance&&) = delete; public facebook::react::RuntimeExecutor getBufferedRuntimeExecutor() noexcept; public facebook::react::RuntimeExecutor getUnbufferedRuntimeExecutor() noexcept; + public std::shared_ptr createJSCallInvoker() noexcept; public std::shared_ptr getRuntimeScheduler() noexcept; public using BindingsInstallFunc = std::function; public void callFunctionOnModule(const std::string& moduleName, const std::string& methodName, folly::dynamic&& args); diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api index 8982c7ac2684..9753482cc1c9 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api @@ -1895,19 +1895,17 @@ class facebook::react::BridgelessNativeMethodCallInvoker : public facebook::reac public virtual void invokeSync(const std::string& methodName, facebook::react::NativeMethodCallFunc&& func) override; } -class facebook::react::BufferedRuntimeExecutor { - public BufferedRuntimeExecutor(facebook::react::RuntimeExecutor runtimeExecutor); +class facebook::react::BufferedRuntimeExecutor : public std::enable_shared_from_this { + public BufferedRuntimeExecutor(facebook::react::BufferedRuntimeExecutor::Executor executor); + public facebook::react::RuntimeExecutor asRuntimeExecutor(); + public facebook::react::RuntimeExecutor asWeakRuntimeExecutor(); + public using Executor = std::function; public using Work = std::function; public void execute(facebook::react::BufferedRuntimeExecutor::Work&& callback); + public void execute(facebook::react::SchedulerPriority priority, facebook::react::BufferedRuntimeExecutor::Work&& callback); public void flush(); } -struct facebook::react::BufferedRuntimeExecutor::BufferedWork { - public bool operator<(const facebook::react::BufferedRuntimeExecutor::BufferedWork& rhs) const; - public facebook::react::BufferedRuntimeExecutor::Work work_; - public uint64_t index_; -} - class facebook::react::CSSSyntaxParser { public constexpr CSSSyntaxParser(const facebook::react::CSSSyntaxParser&) = default; public constexpr CSSSyntaxParser(facebook::react::CSSSyntaxParser&&) = default; @@ -1971,6 +1969,13 @@ class facebook::react::CallInvokerHolder : public jni::HybridClass getCallInvoker(); } +class facebook::react::CallInvokerImpl : public facebook::react::CallInvoker { + public CallInvokerImpl(std::shared_ptr bufferedRuntimeExecutor, std::weak_ptr runtimeScheduler); + public virtual void invokeAsync(facebook::react::CallFunc&& func) noexcept override; + public virtual void invokeAsync(facebook::react::SchedulerPriority priority, facebook::react::CallFunc&& func) noexcept override; + public virtual void invokeSync(facebook::react::CallFunc&& func) override; +} + class facebook::react::CallbackWrapper : public facebook::react::LongLivedObject { public facebook::jsi::Function& callback() noexcept; public facebook::jsi::Runtime& runtime() noexcept; @@ -4161,6 +4166,7 @@ class facebook::react::ReactInstance { public facebook::react::ReactInstance& operator=(facebook::react::ReactInstance&&) = delete; public facebook::react::RuntimeExecutor getBufferedRuntimeExecutor() noexcept; public facebook::react::RuntimeExecutor getUnbufferedRuntimeExecutor() noexcept; + public std::shared_ptr createJSCallInvoker() noexcept; public std::shared_ptr getRuntimeScheduler() noexcept; public using BindingsInstallFunc = std::function; public void callFunctionOnModule(const std::string& moduleName, const std::string& methodName, folly::dynamic&& args); diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api index f8c5b0af4c9a..d8c87169bf0b 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api @@ -1899,19 +1899,17 @@ class facebook::react::BridgelessNativeMethodCallInvoker : public facebook::reac public virtual void invokeSync(const std::string& methodName, facebook::react::NativeMethodCallFunc&& func) override; } -class facebook::react::BufferedRuntimeExecutor { - public BufferedRuntimeExecutor(facebook::react::RuntimeExecutor runtimeExecutor); +class facebook::react::BufferedRuntimeExecutor : public std::enable_shared_from_this { + public BufferedRuntimeExecutor(facebook::react::BufferedRuntimeExecutor::Executor executor); + public facebook::react::RuntimeExecutor asRuntimeExecutor(); + public facebook::react::RuntimeExecutor asWeakRuntimeExecutor(); + public using Executor = std::function; public using Work = std::function; public void execute(facebook::react::BufferedRuntimeExecutor::Work&& callback); + public void execute(facebook::react::SchedulerPriority priority, facebook::react::BufferedRuntimeExecutor::Work&& callback); public void flush(); } -struct facebook::react::BufferedRuntimeExecutor::BufferedWork { - public bool operator<(const facebook::react::BufferedRuntimeExecutor::BufferedWork& rhs) const; - public facebook::react::BufferedRuntimeExecutor::Work work_; - public uint64_t index_; -} - class facebook::react::CSSSyntaxParser { public constexpr CSSSyntaxParser(const facebook::react::CSSSyntaxParser&) = default; public constexpr CSSSyntaxParser(facebook::react::CSSSyntaxParser&&) = default; @@ -1975,6 +1973,13 @@ class facebook::react::CallInvokerHolder : public jni::HybridClass getCallInvoker(); } +class facebook::react::CallInvokerImpl : public facebook::react::CallInvoker { + public CallInvokerImpl(std::shared_ptr bufferedRuntimeExecutor, std::weak_ptr runtimeScheduler); + public virtual void invokeAsync(facebook::react::CallFunc&& func) noexcept override; + public virtual void invokeAsync(facebook::react::SchedulerPriority priority, facebook::react::CallFunc&& func) noexcept override; + public virtual void invokeSync(facebook::react::CallFunc&& func) override; +} + class facebook::react::CallbackWrapper : public facebook::react::LongLivedObject { public facebook::jsi::Function& callback() noexcept; public facebook::jsi::Runtime& runtime() noexcept; @@ -4314,6 +4319,7 @@ class facebook::react::ReactInstance { public facebook::react::ReactInstance& operator=(facebook::react::ReactInstance&&) = delete; public facebook::react::RuntimeExecutor getBufferedRuntimeExecutor() noexcept; public facebook::react::RuntimeExecutor getUnbufferedRuntimeExecutor() noexcept; + public std::shared_ptr createJSCallInvoker() noexcept; public std::shared_ptr getRuntimeScheduler() noexcept; public using BindingsInstallFunc = std::function; public void callFunctionOnModule(const std::string& moduleName, const std::string& methodName, folly::dynamic&& args); diff --git a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api index 0ef036bb8f2f..0ec17c2d1a22 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api @@ -4484,19 +4484,17 @@ class facebook::react::BridgelessNativeMethodCallInvoker : public facebook::reac public virtual void invokeSync(const std::string& methodName, facebook::react::NativeMethodCallFunc&& func) override; } -class facebook::react::BufferedRuntimeExecutor { - public BufferedRuntimeExecutor(facebook::react::RuntimeExecutor runtimeExecutor); +class facebook::react::BufferedRuntimeExecutor : public std::enable_shared_from_this { + public BufferedRuntimeExecutor(facebook::react::BufferedRuntimeExecutor::Executor executor); + public facebook::react::RuntimeExecutor asRuntimeExecutor(); + public facebook::react::RuntimeExecutor asWeakRuntimeExecutor(); + public using Executor = std::function; public using Work = std::function; public void execute(facebook::react::BufferedRuntimeExecutor::Work&& callback); + public void execute(facebook::react::SchedulerPriority priority, facebook::react::BufferedRuntimeExecutor::Work&& callback); public void flush(); } -struct facebook::react::BufferedRuntimeExecutor::BufferedWork { - public bool operator<(const facebook::react::BufferedRuntimeExecutor::BufferedWork& rhs) const; - public facebook::react::BufferedRuntimeExecutor::Work work_; - public uint64_t index_; -} - class facebook::react::CSSSyntaxParser { public constexpr CSSSyntaxParser(const facebook::react::CSSSyntaxParser&) = default; public constexpr CSSSyntaxParser(facebook::react::CSSSyntaxParser&&) = default; @@ -4555,6 +4553,13 @@ class facebook::react::CallInvoker { public virtual ~CallInvoker() = default; } +class facebook::react::CallInvokerImpl : public facebook::react::CallInvoker { + public CallInvokerImpl(std::shared_ptr bufferedRuntimeExecutor, std::weak_ptr runtimeScheduler); + public virtual void invokeAsync(facebook::react::CallFunc&& func) noexcept override; + public virtual void invokeAsync(facebook::react::SchedulerPriority priority, facebook::react::CallFunc&& func) noexcept override; + public virtual void invokeSync(facebook::react::CallFunc&& func) override; +} + class facebook::react::CallbackWrapper : public facebook::react::LongLivedObject { public facebook::jsi::Function& callback() noexcept; public facebook::jsi::Runtime& runtime() noexcept; @@ -6525,6 +6530,7 @@ class facebook::react::ReactInstance { public facebook::react::ReactInstance& operator=(facebook::react::ReactInstance&&) = delete; public facebook::react::RuntimeExecutor getBufferedRuntimeExecutor() noexcept; public facebook::react::RuntimeExecutor getUnbufferedRuntimeExecutor() noexcept; + public std::shared_ptr createJSCallInvoker() noexcept; public std::shared_ptr getRuntimeScheduler() noexcept; public using BindingsInstallFunc = std::function; public void callFunctionOnModule(const std::string& moduleName, const std::string& methodName, folly::dynamic&& args); diff --git a/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api index 42dba9b418e7..336a28d20653 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api @@ -4471,19 +4471,17 @@ class facebook::react::BridgelessNativeMethodCallInvoker : public facebook::reac public virtual void invokeSync(const std::string& methodName, facebook::react::NativeMethodCallFunc&& func) override; } -class facebook::react::BufferedRuntimeExecutor { - public BufferedRuntimeExecutor(facebook::react::RuntimeExecutor runtimeExecutor); +class facebook::react::BufferedRuntimeExecutor : public std::enable_shared_from_this { + public BufferedRuntimeExecutor(facebook::react::BufferedRuntimeExecutor::Executor executor); + public facebook::react::RuntimeExecutor asRuntimeExecutor(); + public facebook::react::RuntimeExecutor asWeakRuntimeExecutor(); + public using Executor = std::function; public using Work = std::function; public void execute(facebook::react::BufferedRuntimeExecutor::Work&& callback); + public void execute(facebook::react::SchedulerPriority priority, facebook::react::BufferedRuntimeExecutor::Work&& callback); public void flush(); } -struct facebook::react::BufferedRuntimeExecutor::BufferedWork { - public bool operator<(const facebook::react::BufferedRuntimeExecutor::BufferedWork& rhs) const; - public facebook::react::BufferedRuntimeExecutor::Work work_; - public uint64_t index_; -} - class facebook::react::CSSSyntaxParser { public constexpr CSSSyntaxParser(const facebook::react::CSSSyntaxParser&) = default; public constexpr CSSSyntaxParser(facebook::react::CSSSyntaxParser&&) = default; @@ -4542,6 +4540,13 @@ class facebook::react::CallInvoker { public virtual ~CallInvoker() = default; } +class facebook::react::CallInvokerImpl : public facebook::react::CallInvoker { + public CallInvokerImpl(std::shared_ptr bufferedRuntimeExecutor, std::weak_ptr runtimeScheduler); + public virtual void invokeAsync(facebook::react::CallFunc&& func) noexcept override; + public virtual void invokeAsync(facebook::react::SchedulerPriority priority, facebook::react::CallFunc&& func) noexcept override; + public virtual void invokeSync(facebook::react::CallFunc&& func) override; +} + class facebook::react::CallbackWrapper : public facebook::react::LongLivedObject { public facebook::jsi::Function& callback() noexcept; public facebook::jsi::Runtime& runtime() noexcept; @@ -6401,6 +6406,7 @@ class facebook::react::ReactInstance { public facebook::react::ReactInstance& operator=(facebook::react::ReactInstance&&) = delete; public facebook::react::RuntimeExecutor getBufferedRuntimeExecutor() noexcept; public facebook::react::RuntimeExecutor getUnbufferedRuntimeExecutor() noexcept; + public std::shared_ptr createJSCallInvoker() noexcept; public std::shared_ptr getRuntimeScheduler() noexcept; public using BindingsInstallFunc = std::function; public void callFunctionOnModule(const std::string& moduleName, const std::string& methodName, folly::dynamic&& args); diff --git a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api index e74932816f6f..c45b53d6fea6 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api @@ -4482,19 +4482,17 @@ class facebook::react::BridgelessNativeMethodCallInvoker : public facebook::reac public virtual void invokeSync(const std::string& methodName, facebook::react::NativeMethodCallFunc&& func) override; } -class facebook::react::BufferedRuntimeExecutor { - public BufferedRuntimeExecutor(facebook::react::RuntimeExecutor runtimeExecutor); +class facebook::react::BufferedRuntimeExecutor : public std::enable_shared_from_this { + public BufferedRuntimeExecutor(facebook::react::BufferedRuntimeExecutor::Executor executor); + public facebook::react::RuntimeExecutor asRuntimeExecutor(); + public facebook::react::RuntimeExecutor asWeakRuntimeExecutor(); + public using Executor = std::function; public using Work = std::function; public void execute(facebook::react::BufferedRuntimeExecutor::Work&& callback); + public void execute(facebook::react::SchedulerPriority priority, facebook::react::BufferedRuntimeExecutor::Work&& callback); public void flush(); } -struct facebook::react::BufferedRuntimeExecutor::BufferedWork { - public bool operator<(const facebook::react::BufferedRuntimeExecutor::BufferedWork& rhs) const; - public facebook::react::BufferedRuntimeExecutor::Work work_; - public uint64_t index_; -} - class facebook::react::CSSSyntaxParser { public constexpr CSSSyntaxParser(const facebook::react::CSSSyntaxParser&) = default; public constexpr CSSSyntaxParser(facebook::react::CSSSyntaxParser&&) = default; @@ -4553,6 +4551,13 @@ class facebook::react::CallInvoker { public virtual ~CallInvoker() = default; } +class facebook::react::CallInvokerImpl : public facebook::react::CallInvoker { + public CallInvokerImpl(std::shared_ptr bufferedRuntimeExecutor, std::weak_ptr runtimeScheduler); + public virtual void invokeAsync(facebook::react::CallFunc&& func) noexcept override; + public virtual void invokeAsync(facebook::react::SchedulerPriority priority, facebook::react::CallFunc&& func) noexcept override; + public virtual void invokeSync(facebook::react::CallFunc&& func) override; +} + class facebook::react::CallbackWrapper : public facebook::react::LongLivedObject { public facebook::jsi::Function& callback() noexcept; public facebook::jsi::Runtime& runtime() noexcept; @@ -6522,6 +6527,7 @@ class facebook::react::ReactInstance { public facebook::react::ReactInstance& operator=(facebook::react::ReactInstance&&) = delete; public facebook::react::RuntimeExecutor getBufferedRuntimeExecutor() noexcept; public facebook::react::RuntimeExecutor getUnbufferedRuntimeExecutor() noexcept; + public std::shared_ptr createJSCallInvoker() noexcept; public std::shared_ptr getRuntimeScheduler() noexcept; public using BindingsInstallFunc = std::function; public void callFunctionOnModule(const std::string& moduleName, const std::string& methodName, folly::dynamic&& args); diff --git a/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api index 236a7ea1dba0..1236d7769e4d 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api @@ -1207,19 +1207,17 @@ class facebook::react::BridgelessNativeMethodCallInvoker : public facebook::reac public virtual void invokeSync(const std::string& methodName, facebook::react::NativeMethodCallFunc&& func) override; } -class facebook::react::BufferedRuntimeExecutor { - public BufferedRuntimeExecutor(facebook::react::RuntimeExecutor runtimeExecutor); +class facebook::react::BufferedRuntimeExecutor : public std::enable_shared_from_this { + public BufferedRuntimeExecutor(facebook::react::BufferedRuntimeExecutor::Executor executor); + public facebook::react::RuntimeExecutor asRuntimeExecutor(); + public facebook::react::RuntimeExecutor asWeakRuntimeExecutor(); + public using Executor = std::function; public using Work = std::function; public void execute(facebook::react::BufferedRuntimeExecutor::Work&& callback); + public void execute(facebook::react::SchedulerPriority priority, facebook::react::BufferedRuntimeExecutor::Work&& callback); public void flush(); } -struct facebook::react::BufferedRuntimeExecutor::BufferedWork { - public bool operator<(const facebook::react::BufferedRuntimeExecutor::BufferedWork& rhs) const; - public facebook::react::BufferedRuntimeExecutor::Work work_; - public uint64_t index_; -} - class facebook::react::CSSSyntaxParser { public constexpr CSSSyntaxParser(const facebook::react::CSSSyntaxParser&) = default; public constexpr CSSSyntaxParser(facebook::react::CSSSyntaxParser&&) = default; @@ -1278,6 +1276,13 @@ class facebook::react::CallInvoker { public virtual ~CallInvoker() = default; } +class facebook::react::CallInvokerImpl : public facebook::react::CallInvoker { + public CallInvokerImpl(std::shared_ptr bufferedRuntimeExecutor, std::weak_ptr runtimeScheduler); + public virtual void invokeAsync(facebook::react::CallFunc&& func) noexcept override; + public virtual void invokeAsync(facebook::react::SchedulerPriority priority, facebook::react::CallFunc&& func) noexcept override; + public virtual void invokeSync(facebook::react::CallFunc&& func) override; +} + class facebook::react::CallbackWrapper : public facebook::react::LongLivedObject { public facebook::jsi::Function& callback() noexcept; public facebook::jsi::Runtime& runtime() noexcept; @@ -2881,6 +2886,7 @@ class facebook::react::ReactInstance { public facebook::react::ReactInstance& operator=(facebook::react::ReactInstance&&) = delete; public facebook::react::RuntimeExecutor getBufferedRuntimeExecutor() noexcept; public facebook::react::RuntimeExecutor getUnbufferedRuntimeExecutor() noexcept; + public std::shared_ptr createJSCallInvoker() noexcept; public std::shared_ptr getRuntimeScheduler() noexcept; public using BindingsInstallFunc = std::function; public void callFunctionOnModule(const std::string& moduleName, const std::string& methodName, folly::dynamic&& args); diff --git a/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api index 3ae1080cbfbd..07934f45858e 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api @@ -1202,19 +1202,17 @@ class facebook::react::BridgelessNativeMethodCallInvoker : public facebook::reac public virtual void invokeSync(const std::string& methodName, facebook::react::NativeMethodCallFunc&& func) override; } -class facebook::react::BufferedRuntimeExecutor { - public BufferedRuntimeExecutor(facebook::react::RuntimeExecutor runtimeExecutor); +class facebook::react::BufferedRuntimeExecutor : public std::enable_shared_from_this { + public BufferedRuntimeExecutor(facebook::react::BufferedRuntimeExecutor::Executor executor); + public facebook::react::RuntimeExecutor asRuntimeExecutor(); + public facebook::react::RuntimeExecutor asWeakRuntimeExecutor(); + public using Executor = std::function; public using Work = std::function; public void execute(facebook::react::BufferedRuntimeExecutor::Work&& callback); + public void execute(facebook::react::SchedulerPriority priority, facebook::react::BufferedRuntimeExecutor::Work&& callback); public void flush(); } -struct facebook::react::BufferedRuntimeExecutor::BufferedWork { - public bool operator<(const facebook::react::BufferedRuntimeExecutor::BufferedWork& rhs) const; - public facebook::react::BufferedRuntimeExecutor::Work work_; - public uint64_t index_; -} - class facebook::react::CSSSyntaxParser { public constexpr CSSSyntaxParser(const facebook::react::CSSSyntaxParser&) = default; public constexpr CSSSyntaxParser(facebook::react::CSSSyntaxParser&&) = default; @@ -1273,6 +1271,13 @@ class facebook::react::CallInvoker { public virtual ~CallInvoker() = default; } +class facebook::react::CallInvokerImpl : public facebook::react::CallInvoker { + public CallInvokerImpl(std::shared_ptr bufferedRuntimeExecutor, std::weak_ptr runtimeScheduler); + public virtual void invokeAsync(facebook::react::CallFunc&& func) noexcept override; + public virtual void invokeAsync(facebook::react::SchedulerPriority priority, facebook::react::CallFunc&& func) noexcept override; + public virtual void invokeSync(facebook::react::CallFunc&& func) override; +} + class facebook::react::CallbackWrapper : public facebook::react::LongLivedObject { public facebook::jsi::Function& callback() noexcept; public facebook::jsi::Runtime& runtime() noexcept; @@ -2765,6 +2770,7 @@ class facebook::react::ReactInstance { public facebook::react::ReactInstance& operator=(facebook::react::ReactInstance&&) = delete; public facebook::react::RuntimeExecutor getBufferedRuntimeExecutor() noexcept; public facebook::react::RuntimeExecutor getUnbufferedRuntimeExecutor() noexcept; + public std::shared_ptr createJSCallInvoker() noexcept; public std::shared_ptr getRuntimeScheduler() noexcept; public using BindingsInstallFunc = std::function; public void callFunctionOnModule(const std::string& moduleName, const std::string& methodName, folly::dynamic&& args); diff --git a/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api index 00ad636e3938..c03ab6327326 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api @@ -1205,19 +1205,17 @@ class facebook::react::BridgelessNativeMethodCallInvoker : public facebook::reac public virtual void invokeSync(const std::string& methodName, facebook::react::NativeMethodCallFunc&& func) override; } -class facebook::react::BufferedRuntimeExecutor { - public BufferedRuntimeExecutor(facebook::react::RuntimeExecutor runtimeExecutor); +class facebook::react::BufferedRuntimeExecutor : public std::enable_shared_from_this { + public BufferedRuntimeExecutor(facebook::react::BufferedRuntimeExecutor::Executor executor); + public facebook::react::RuntimeExecutor asRuntimeExecutor(); + public facebook::react::RuntimeExecutor asWeakRuntimeExecutor(); + public using Executor = std::function; public using Work = std::function; public void execute(facebook::react::BufferedRuntimeExecutor::Work&& callback); + public void execute(facebook::react::SchedulerPriority priority, facebook::react::BufferedRuntimeExecutor::Work&& callback); public void flush(); } -struct facebook::react::BufferedRuntimeExecutor::BufferedWork { - public bool operator<(const facebook::react::BufferedRuntimeExecutor::BufferedWork& rhs) const; - public facebook::react::BufferedRuntimeExecutor::Work work_; - public uint64_t index_; -} - class facebook::react::CSSSyntaxParser { public constexpr CSSSyntaxParser(const facebook::react::CSSSyntaxParser&) = default; public constexpr CSSSyntaxParser(facebook::react::CSSSyntaxParser&&) = default; @@ -1276,6 +1274,13 @@ class facebook::react::CallInvoker { public virtual ~CallInvoker() = default; } +class facebook::react::CallInvokerImpl : public facebook::react::CallInvoker { + public CallInvokerImpl(std::shared_ptr bufferedRuntimeExecutor, std::weak_ptr runtimeScheduler); + public virtual void invokeAsync(facebook::react::CallFunc&& func) noexcept override; + public virtual void invokeAsync(facebook::react::SchedulerPriority priority, facebook::react::CallFunc&& func) noexcept override; + public virtual void invokeSync(facebook::react::CallFunc&& func) override; +} + class facebook::react::CallbackWrapper : public facebook::react::LongLivedObject { public facebook::jsi::Function& callback() noexcept; public facebook::jsi::Runtime& runtime() noexcept; @@ -2878,6 +2883,7 @@ class facebook::react::ReactInstance { public facebook::react::ReactInstance& operator=(facebook::react::ReactInstance&&) = delete; public facebook::react::RuntimeExecutor getBufferedRuntimeExecutor() noexcept; public facebook::react::RuntimeExecutor getUnbufferedRuntimeExecutor() noexcept; + public std::shared_ptr createJSCallInvoker() noexcept; public std::shared_ptr getRuntimeScheduler() noexcept; public using BindingsInstallFunc = std::function; public void callFunctionOnModule(const std::string& moduleName, const std::string& methodName, folly::dynamic&& args);