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 915452d68c6d..f7b5991d5af9 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<<4342ccb696b4123b9d463a31c024b9bc>> + * @generated SignedSource<<4b2133f0c7c9b0a7ef37e9b928faad64>> */ /** @@ -300,6 +300,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun enableSwiftUIBasedFilters(): Boolean = accessor.enableSwiftUIBasedFilters() + /** + * When enabled, TurboModule methods with void return type will be invoked synchronously on the JS thread instead of being dispatched asynchronously. Only applies to pure TurboModules, not interop modules. + */ + @JvmStatic + public fun enableSyncVoidMethods(): Boolean = accessor.enableSyncVoidMethods() + /** * Enables View Culling: as soon as a view goes off screen, it can be reused anywhere in the UI and pieced together with other items to create new UI elements. */ 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 67418b09d388..f30d0ffa77c7 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<> + * @generated SignedSource<<65e4bd35f7b92d56d1b26176b8c08b90>> */ /** @@ -65,6 +65,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces private var enablePropsUpdateReconciliationAndroidCache: Boolean? = null private var enableSchedulerDelegateInvalidationCache: Boolean? = null private var enableSwiftUIBasedFiltersCache: Boolean? = null + private var enableSyncVoidMethodsCache: Boolean? = null private var enableViewCullingCache: Boolean? = null private var enableViewRecyclingCache: Boolean? = null private var enableViewRecyclingForImageCache: Boolean? = null @@ -518,6 +519,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun enableSyncVoidMethods(): Boolean { + var cached = enableSyncVoidMethodsCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.enableSyncVoidMethods() + enableSyncVoidMethodsCache = cached + } + return cached + } + override fun enableViewCulling(): Boolean { var cached = enableViewCullingCache 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 03d977975431..cbc80f7fe13f 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<<81989dbed82df7bd963d8023c595ff44>> + * @generated SignedSource<<9cc7f5ffd7c0951db9bbf397e96aa83d>> */ /** @@ -118,6 +118,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun enableSwiftUIBasedFilters(): Boolean + @DoNotStrip @JvmStatic public external fun enableSyncVoidMethods(): Boolean + @DoNotStrip @JvmStatic public external fun enableViewCulling(): Boolean @DoNotStrip @JvmStatic public external fun enableViewRecycling(): 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 7372f7a0f02c..5e540a35097b 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<<93e83fb3dc9577acd9678803321e0fe1>> + * @generated SignedSource<<2efb60076f46168bacb0cf064cc574b9>> */ /** @@ -113,6 +113,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun enableSwiftUIBasedFilters(): Boolean = false + override fun enableSyncVoidMethods(): Boolean = false + override fun enableViewCulling(): Boolean = false override fun enableViewRecycling(): Boolean = false diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt index e3ce2af265cb..0363f6c4c080 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<<9d07e8adeee69583b788069649306d8e>> + * @generated SignedSource<<9481147f7c9af5ba0c2c3c3f609f7050>> */ /** @@ -69,6 +69,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc private var enablePropsUpdateReconciliationAndroidCache: Boolean? = null private var enableSchedulerDelegateInvalidationCache: Boolean? = null private var enableSwiftUIBasedFiltersCache: Boolean? = null + private var enableSyncVoidMethodsCache: Boolean? = null private var enableViewCullingCache: Boolean? = null private var enableViewRecyclingCache: Boolean? = null private var enableViewRecyclingForImageCache: Boolean? = null @@ -567,6 +568,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc return cached } + override fun enableSyncVoidMethods(): Boolean { + var cached = enableSyncVoidMethodsCache + if (cached == null) { + cached = currentProvider.enableSyncVoidMethods() + accessedFeatureFlags.add("enableSyncVoidMethods") + enableSyncVoidMethodsCache = cached + } + return cached + } + override fun enableViewCulling(): Boolean { var cached = enableViewCullingCache 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 80d6f6753adf..af1544f2c36b 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -113,6 +113,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun enableSwiftUIBasedFilters(): Boolean + @DoNotStrip public fun enableSyncVoidMethods(): Boolean + @DoNotStrip public fun enableViewCulling(): Boolean @DoNotStrip public fun enableViewRecycling(): 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 e26011a48dba..7c45dc47c7a3 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<<32c8c18771d6690f50d60dbc8e3d07e2>> + * @generated SignedSource<> */ /** @@ -309,6 +309,12 @@ class ReactNativeFeatureFlagsJavaProvider return method(javaProvider_); } + bool enableSyncVoidMethods() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("enableSyncVoidMethods"); + return method(javaProvider_); + } + bool enableViewCulling() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("enableViewCulling"); @@ -820,6 +826,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableSwiftUIBasedFilters( return ReactNativeFeatureFlags::enableSwiftUIBasedFilters(); } +bool JReactNativeFeatureFlagsCxxInterop::enableSyncVoidMethods( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::enableSyncVoidMethods(); +} + bool JReactNativeFeatureFlagsCxxInterop::enableViewCulling( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::enableViewCulling(); @@ -1221,6 +1232,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "enableSwiftUIBasedFilters", JReactNativeFeatureFlagsCxxInterop::enableSwiftUIBasedFilters), + makeNativeMethod( + "enableSyncVoidMethods", + JReactNativeFeatureFlagsCxxInterop::enableSyncVoidMethods), makeNativeMethod( "enableViewCulling", JReactNativeFeatureFlagsCxxInterop::enableViewCulling), 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 f554936fd895..1e2c46baa20f 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<> + * @generated SignedSource<> */ /** @@ -165,6 +165,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool enableSwiftUIBasedFilters( facebook::jni::alias_ref); + static bool enableSyncVoidMethods( + facebook::jni::alias_ref); + static bool enableViewCulling( facebook::jni::alias_ref); diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp index 4641821c3ace..197dbc0fd04e 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<<483ac339c0d636c85f4639c60982c504>> + * @generated SignedSource<> */ /** @@ -206,6 +206,10 @@ bool ReactNativeFeatureFlags::enableSwiftUIBasedFilters() { return getAccessor().enableSwiftUIBasedFilters(); } +bool ReactNativeFeatureFlags::enableSyncVoidMethods() { + return getAccessor().enableSyncVoidMethods(); +} + bool ReactNativeFeatureFlags::enableViewCulling() { return getAccessor().enableViewCulling(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index d80a9d81ad51..e96e9339e381 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<<771a335070649f38cb559a95d80947aa>> + * @generated SignedSource<<7d77e761aea48d71ac2f19195bbedced>> */ /** @@ -264,6 +264,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool enableSwiftUIBasedFilters(); + /** + * When enabled, TurboModule methods with void return type will be invoked synchronously on the JS thread instead of being dispatched asynchronously. Only applies to pure TurboModules, not interop modules. + */ + RN_EXPORT static bool enableSyncVoidMethods(); + /** * Enables View Culling: as soon as a view goes off screen, it can be reused anywhere in the UI and pieced together with other items to create new UI elements. */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index f23341972fc2..3a2efc8d1783 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<<5054704ec35884395b7b3668169a8871>> + * @generated SignedSource<<098170a5caff8a4f9ff287f874332040>> */ /** @@ -839,6 +839,24 @@ bool ReactNativeFeatureFlagsAccessor::enableSwiftUIBasedFilters() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::enableSyncVoidMethods() { + auto flagValue = enableSyncVoidMethods_.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(45, "enableSyncVoidMethods"); + + flagValue = currentProvider_->enableSyncVoidMethods(); + enableSyncVoidMethods_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::enableViewCulling() { auto flagValue = enableViewCulling_.load(); @@ -848,7 +866,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(45, "enableViewCulling"); + markFlagAsAccessed(46, "enableViewCulling"); flagValue = currentProvider_->enableViewCulling(); enableViewCulling_ = flagValue; @@ -866,7 +884,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(46, "enableViewRecycling"); + markFlagAsAccessed(47, "enableViewRecycling"); flagValue = currentProvider_->enableViewRecycling(); enableViewRecycling_ = flagValue; @@ -884,7 +902,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(47, "enableViewRecyclingForImage"); + markFlagAsAccessed(48, "enableViewRecyclingForImage"); flagValue = currentProvider_->enableViewRecyclingForImage(); enableViewRecyclingForImage_ = flagValue; @@ -902,7 +920,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(48, "enableViewRecyclingForScrollView"); + markFlagAsAccessed(49, "enableViewRecyclingForScrollView"); flagValue = currentProvider_->enableViewRecyclingForScrollView(); enableViewRecyclingForScrollView_ = flagValue; @@ -920,7 +938,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(49, "enableViewRecyclingForText"); + markFlagAsAccessed(50, "enableViewRecyclingForText"); flagValue = currentProvider_->enableViewRecyclingForText(); enableViewRecyclingForText_ = flagValue; @@ -938,7 +956,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(50, "enableViewRecyclingForView"); + markFlagAsAccessed(51, "enableViewRecyclingForView"); flagValue = currentProvider_->enableViewRecyclingForView(); enableViewRecyclingForView_ = flagValue; @@ -956,7 +974,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(51, "enableVirtualViewContainerStateExperimental"); + markFlagAsAccessed(52, "enableVirtualViewContainerStateExperimental"); flagValue = currentProvider_->enableVirtualViewContainerStateExperimental(); enableVirtualViewContainerStateExperimental_ = flagValue; @@ -974,7 +992,7 @@ bool ReactNativeFeatureFlagsAccessor::enableVirtualViewDebugFeatures() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(52, "enableVirtualViewDebugFeatures"); + markFlagAsAccessed(53, "enableVirtualViewDebugFeatures"); flagValue = currentProvider_->enableVirtualViewDebugFeatures(); enableVirtualViewDebugFeatures_ = flagValue; @@ -992,7 +1010,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(53, "fixDifferentiatorParentTagForUnflattenCase"); + markFlagAsAccessed(54, "fixDifferentiatorParentTagForUnflattenCase"); flagValue = currentProvider_->fixDifferentiatorParentTagForUnflattenCase(); fixDifferentiatorParentTagForUnflattenCase_ = flagValue; @@ -1010,7 +1028,7 @@ bool ReactNativeFeatureFlagsAccessor::fixFindShadowNodeByTagRaceCondition() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(54, "fixFindShadowNodeByTagRaceCondition"); + markFlagAsAccessed(55, "fixFindShadowNodeByTagRaceCondition"); flagValue = currentProvider_->fixFindShadowNodeByTagRaceCondition(); fixFindShadowNodeByTagRaceCondition_ = flagValue; @@ -1028,7 +1046,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(55, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); + markFlagAsAccessed(56, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); flagValue = currentProvider_->fixMappingOfEventPrioritiesBetweenFabricAndReact(); fixMappingOfEventPrioritiesBetweenFabricAndReact_ = flagValue; @@ -1046,7 +1064,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(56, "fixYogaFlexBasisFitContentInMainAxis"); + markFlagAsAccessed(57, "fixYogaFlexBasisFitContentInMainAxis"); flagValue = currentProvider_->fixYogaFlexBasisFitContentInMainAxis(); fixYogaFlexBasisFitContentInMainAxis_ = flagValue; @@ -1064,7 +1082,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(57, "fuseboxAssertSingleHostState"); + markFlagAsAccessed(58, "fuseboxAssertSingleHostState"); flagValue = currentProvider_->fuseboxAssertSingleHostState(); fuseboxAssertSingleHostState_ = flagValue; @@ -1082,7 +1100,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(58, "fuseboxEnabledRelease"); + markFlagAsAccessed(59, "fuseboxEnabledRelease"); flagValue = currentProvider_->fuseboxEnabledRelease(); fuseboxEnabledRelease_ = flagValue; @@ -1100,7 +1118,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(59, "fuseboxFrameRecordingEnabled"); + markFlagAsAccessed(60, "fuseboxFrameRecordingEnabled"); flagValue = currentProvider_->fuseboxFrameRecordingEnabled(); fuseboxFrameRecordingEnabled_ = flagValue; @@ -1118,7 +1136,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxNetworkInspectionEnabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(60, "fuseboxNetworkInspectionEnabled"); + markFlagAsAccessed(61, "fuseboxNetworkInspectionEnabled"); flagValue = currentProvider_->fuseboxNetworkInspectionEnabled(); fuseboxNetworkInspectionEnabled_ = flagValue; @@ -1136,7 +1154,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(61, "fuseboxScreenshotCaptureEnabled"); + markFlagAsAccessed(62, "fuseboxScreenshotCaptureEnabled"); flagValue = currentProvider_->fuseboxScreenshotCaptureEnabled(); fuseboxScreenshotCaptureEnabled_ = flagValue; @@ -1154,7 +1172,7 @@ bool ReactNativeFeatureFlagsAccessor::hideOffscreenVirtualViewsOnIOS() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(62, "hideOffscreenVirtualViewsOnIOS"); + markFlagAsAccessed(63, "hideOffscreenVirtualViewsOnIOS"); flagValue = currentProvider_->hideOffscreenVirtualViewsOnIOS(); hideOffscreenVirtualViewsOnIOS_ = flagValue; @@ -1172,7 +1190,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(63, "optimizedAnimatedPropUpdates"); + markFlagAsAccessed(64, "optimizedAnimatedPropUpdates"); flagValue = currentProvider_->optimizedAnimatedPropUpdates(); optimizedAnimatedPropUpdates_ = flagValue; @@ -1190,7 +1208,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(64, "overrideBySynchronousMountPropsAtMountingAndroid"); + markFlagAsAccessed(65, "overrideBySynchronousMountPropsAtMountingAndroid"); flagValue = currentProvider_->overrideBySynchronousMountPropsAtMountingAndroid(); overrideBySynchronousMountPropsAtMountingAndroid_ = flagValue; @@ -1208,7 +1226,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(65, "perfIssuesEnabled"); + markFlagAsAccessed(66, "perfIssuesEnabled"); flagValue = currentProvider_->perfIssuesEnabled(); perfIssuesEnabled_ = flagValue; @@ -1226,7 +1244,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(66, "perfMonitorV2Enabled"); + markFlagAsAccessed(67, "perfMonitorV2Enabled"); flagValue = currentProvider_->perfMonitorV2Enabled(); perfMonitorV2Enabled_ = flagValue; @@ -1244,7 +1262,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(67, "preparedTextCacheSize"); + markFlagAsAccessed(68, "preparedTextCacheSize"); flagValue = currentProvider_->preparedTextCacheSize(); preparedTextCacheSize_ = flagValue; @@ -1262,7 +1280,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(68, "preventShadowTreeCommitExhaustion"); + markFlagAsAccessed(69, "preventShadowTreeCommitExhaustion"); flagValue = currentProvider_->preventShadowTreeCommitExhaustion(); preventShadowTreeCommitExhaustion_ = flagValue; @@ -1280,7 +1298,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(69, "redBoxV2Android"); + markFlagAsAccessed(70, "redBoxV2Android"); flagValue = currentProvider_->redBoxV2Android(); redBoxV2Android_ = flagValue; @@ -1298,7 +1316,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(70, "redBoxV2IOS"); + markFlagAsAccessed(71, "redBoxV2IOS"); flagValue = currentProvider_->redBoxV2IOS(); redBoxV2IOS_ = flagValue; @@ -1316,7 +1334,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(71, "shouldPressibilityUseW3CPointerEventsForHover"); + markFlagAsAccessed(72, "shouldPressibilityUseW3CPointerEventsForHover"); flagValue = currentProvider_->shouldPressibilityUseW3CPointerEventsForHover(); shouldPressibilityUseW3CPointerEventsForHover_ = flagValue; @@ -1334,7 +1352,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(72, "shouldTriggerResponderTransferOnScrollAndroid"); + markFlagAsAccessed(73, "shouldTriggerResponderTransferOnScrollAndroid"); flagValue = currentProvider_->shouldTriggerResponderTransferOnScrollAndroid(); shouldTriggerResponderTransferOnScrollAndroid_ = flagValue; @@ -1352,7 +1370,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(73, "skipActivityIdentityAssertionOnHostPause"); + markFlagAsAccessed(74, "skipActivityIdentityAssertionOnHostPause"); flagValue = currentProvider_->skipActivityIdentityAssertionOnHostPause(); skipActivityIdentityAssertionOnHostPause_ = flagValue; @@ -1370,7 +1388,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(74, "syncAndroidClipBoundsWithOverflow"); + markFlagAsAccessed(75, "syncAndroidClipBoundsWithOverflow"); flagValue = currentProvider_->syncAndroidClipBoundsWithOverflow(); syncAndroidClipBoundsWithOverflow_ = flagValue; @@ -1388,7 +1406,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(75, "traceTurboModulePromiseRejectionsOnAndroid"); + markFlagAsAccessed(76, "traceTurboModulePromiseRejectionsOnAndroid"); flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid(); traceTurboModulePromiseRejectionsOnAndroid_ = flagValue; @@ -1406,7 +1424,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(76, "updateRuntimeShadowNodeReferencesOnCommit"); + markFlagAsAccessed(77, "updateRuntimeShadowNodeReferencesOnCommit"); flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommit(); updateRuntimeShadowNodeReferencesOnCommit_ = flagValue; @@ -1424,7 +1442,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(77, "updateRuntimeShadowNodeReferencesOnCommitThread"); + markFlagAsAccessed(78, "updateRuntimeShadowNodeReferencesOnCommitThread"); flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommitThread(); updateRuntimeShadowNodeReferencesOnCommitThread_ = flagValue; @@ -1442,7 +1460,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(78, "useAlwaysAvailableJSErrorHandling"); + markFlagAsAccessed(79, "useAlwaysAvailableJSErrorHandling"); flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling(); useAlwaysAvailableJSErrorHandling_ = flagValue; @@ -1460,7 +1478,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(79, "useFabricInterop"); + markFlagAsAccessed(80, "useFabricInterop"); flagValue = currentProvider_->useFabricInterop(); useFabricInterop_ = flagValue; @@ -1478,7 +1496,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(80, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(81, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -1496,7 +1514,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(81, "useNestedScrollViewAndroid"); + markFlagAsAccessed(82, "useNestedScrollViewAndroid"); flagValue = currentProvider_->useNestedScrollViewAndroid(); useNestedScrollViewAndroid_ = flagValue; @@ -1514,7 +1532,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimizedViewRegistryOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(82, "useOptimizedViewRegistryOnAndroid"); + markFlagAsAccessed(83, "useOptimizedViewRegistryOnAndroid"); flagValue = currentProvider_->useOptimizedViewRegistryOnAndroid(); useOptimizedViewRegistryOnAndroid_ = flagValue; @@ -1532,7 +1550,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(83, "useSharedAnimatedBackend"); + markFlagAsAccessed(84, "useSharedAnimatedBackend"); flagValue = currentProvider_->useSharedAnimatedBackend(); useSharedAnimatedBackend_ = flagValue; @@ -1550,7 +1568,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(84, "useTraitHiddenOnAndroid"); + markFlagAsAccessed(85, "useTraitHiddenOnAndroid"); flagValue = currentProvider_->useTraitHiddenOnAndroid(); useTraitHiddenOnAndroid_ = flagValue; @@ -1568,7 +1586,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(85, "useTurboModuleInterop"); + markFlagAsAccessed(86, "useTurboModuleInterop"); flagValue = currentProvider_->useTurboModuleInterop(); useTurboModuleInterop_ = flagValue; @@ -1586,7 +1604,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModules() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(86, "useTurboModules"); + markFlagAsAccessed(87, "useTurboModules"); flagValue = currentProvider_->useTurboModules(); useTurboModules_ = flagValue; @@ -1604,7 +1622,7 @@ bool ReactNativeFeatureFlagsAccessor::useUnorderedMapInDifferentiator() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(87, "useUnorderedMapInDifferentiator"); + markFlagAsAccessed(88, "useUnorderedMapInDifferentiator"); flagValue = currentProvider_->useUnorderedMapInDifferentiator(); useUnorderedMapInDifferentiator_ = flagValue; @@ -1622,7 +1640,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(88, "viewCullingOutsetRatio"); + markFlagAsAccessed(89, "viewCullingOutsetRatio"); flagValue = currentProvider_->viewCullingOutsetRatio(); viewCullingOutsetRatio_ = flagValue; @@ -1640,7 +1658,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(89, "viewTransitionEnabled"); + markFlagAsAccessed(90, "viewTransitionEnabled"); flagValue = currentProvider_->viewTransitionEnabled(); viewTransitionEnabled_ = flagValue; @@ -1658,7 +1676,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(90, "viewTransitionUseHardwareBitmapAndroid"); + markFlagAsAccessed(91, "viewTransitionUseHardwareBitmapAndroid"); flagValue = currentProvider_->viewTransitionUseHardwareBitmapAndroid(); viewTransitionUseHardwareBitmapAndroid_ = flagValue; @@ -1676,7 +1694,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(91, "virtualViewPrerenderRatio"); + markFlagAsAccessed(92, "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 49228e41b6d4..96c5b12c4017 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<<8a068641229a3fbbe105a5368ea6bda9>> + * @generated SignedSource<<25437969132a4018b088032644908de4>> */ /** @@ -77,6 +77,7 @@ class ReactNativeFeatureFlagsAccessor { bool enablePropsUpdateReconciliationAndroid(); bool enableSchedulerDelegateInvalidation(); bool enableSwiftUIBasedFilters(); + bool enableSyncVoidMethods(); bool enableViewCulling(); bool enableViewRecycling(); bool enableViewRecyclingForImage(); @@ -135,7 +136,7 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 92> accessedFeatureFlags_; + std::array, 93> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> cdpInteractionMetricsEnabled_; @@ -182,6 +183,7 @@ class ReactNativeFeatureFlagsAccessor { std::atomic> enablePropsUpdateReconciliationAndroid_; std::atomic> enableSchedulerDelegateInvalidation_; std::atomic> enableSwiftUIBasedFilters_; + std::atomic> enableSyncVoidMethods_; std::atomic> enableViewCulling_; std::atomic> enableViewRecycling_; std::atomic> enableViewRecyclingForImage_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index ba342f22461e..df2666538888 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<<7be26fb138e59ef3dc34cec13d3813c4>> + * @generated SignedSource<<4cdbc660e72d8fc629a5469ee62407e1>> */ /** @@ -207,6 +207,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return false; } + bool enableSyncVoidMethods() override { + return false; + } + bool enableViewCulling() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h index 4f6aa5cbae6d..fb4e086bd3c1 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<<2ea91689e8761dc57bc35975d1161839>> + * @generated SignedSource<> */ /** @@ -450,6 +450,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef return ReactNativeFeatureFlagsDefaults::enableSwiftUIBasedFilters(); } + bool enableSyncVoidMethods() override { + auto value = values_["enableSyncVoidMethods"]; + if (!value.isNull()) { + return value.getBool(); + } + + return ReactNativeFeatureFlagsDefaults::enableSyncVoidMethods(); + } + bool enableViewCulling() override { auto value = values_["enableViewCulling"]; if (!value.isNull()) { diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index 211b2809e0c2..878fdba5df51 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<<60fc10a6c06d8381177c7c4dbd488dd9>> + * @generated SignedSource<<7331541bb27567d1711dac268742598c>> */ /** @@ -70,6 +70,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool enablePropsUpdateReconciliationAndroid() = 0; virtual bool enableSchedulerDelegateInvalidation() = 0; virtual bool enableSwiftUIBasedFilters() = 0; + virtual bool enableSyncVoidMethods() = 0; virtual bool enableViewCulling() = 0; virtual bool enableViewRecycling() = 0; virtual bool enableViewRecyclingForImage() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaInteropTurboModule.h b/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaInteropTurboModule.h index c70923bc936f..daca5d045251 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaInteropTurboModule.h +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaInteropTurboModule.h @@ -33,6 +33,11 @@ class JSI_EXPORT JavaInteropTurboModule : public JavaTurboModule { std::vector getPropertyNames(facebook::jsi::Runtime &runtime) override; + bool isInteropModule() const override + { + return true; + } + protected: jsi::Value create(jsi::Runtime &runtime, const jsi::PropNameID &propName) override; diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp b/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp index 5c9b464a8c3a..d7bf374c354e 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.cpp @@ -522,7 +522,10 @@ jsi::Value JavaTurboModule::invokeJavaMethod( const char* methodName = methodNameStr.c_str(); const char* moduleName = name_.c_str(); - bool isMethodSync = valueKind != VoidKind && valueKind != PromiseKind; + bool isMethodSync = valueKind != PromiseKind && + (valueKind != VoidKind || + (ReactNativeFeatureFlags::enableSyncVoidMethods() && + !isInteropModule())); if (isMethodSync) { TMPL::syncMethodCallStart(moduleName, methodName); @@ -546,12 +549,13 @@ jsi::Value JavaTurboModule::invokeJavaMethod( unsigned int maxReturnObjects = 3; /** - * When the return type is void, all JNI LocalReferences are converted to - * GlobalReferences. The LocalReferences are then promptly deleted - * after the conversion. + * When the return type is void and the method is async, all JNI + * LocalReferences are converted to GlobalReferences. The LocalReferences + * are then promptly deleted after the conversion. */ - unsigned int actualArgCount = - valueKind == VoidKind ? 0 : static_cast(argCount); + unsigned int actualArgCount = (valueKind == VoidKind && !isMethodSync) + ? 0 + : static_cast(argCount); unsigned int estimatedLocalRefCount = actualArgCount + maxReturnObjects + buffer; @@ -802,6 +806,17 @@ jsi::Value JavaTurboModule::invokeJavaMethod( return returnValue; } case VoidKind: { + if (isMethodSync) { + env->CallVoidMethodA(instance, methodID, jargs.data()); + checkJNIErrorForMethodCall(); + + TMPL::syncMethodCallExecutionEnd(moduleName, methodName); + TMPL::syncMethodCallReturnConversionStart(moduleName, methodName); + TMPL::syncMethodCallReturnConversionEnd(moduleName, methodName); + TMPL::syncMethodCallEnd(moduleName, methodName); + return jsi::Value::undefined(); + } + TMPL::asyncMethodCallArgConversionEnd(moduleName, methodName); TMPL::asyncMethodCallDispatch(moduleName, methodName); diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.h b/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.h index c42f1c7dbac0..41d989cb6ffe 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.h +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/android/ReactCommon/JavaTurboModule.h @@ -38,6 +38,11 @@ class JSI_EXPORT JavaTurboModule : public TurboModule { JavaTurboModule(const InitParams ¶ms); virtual ~JavaTurboModule(); + virtual bool isInteropModule() const + { + return false; + } + jsi::Value invokeJavaMethod( jsi::Runtime &runtime, TurboModuleMethodValueKind valueKind, diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTInteropTurboModule.h b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTInteropTurboModule.h index b3e98589eb14..0f51e1f1dc4d 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTInteropTurboModule.h +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTInteropTurboModule.h @@ -30,6 +30,11 @@ class JSI_EXPORT ObjCInteropTurboModule : public ObjCTurboModule { std::vector getPropertyNames(facebook::jsi::Runtime &runtime) override; + bool isInteropModule() const override + { + return true; + } + protected: jsi::Value create(jsi::Runtime &runtime, const jsi::PropNameID &propName) override; diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.h b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.h index d3fc87e6f148..154c23639fa4 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.h +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.h @@ -62,6 +62,11 @@ class JSI_EXPORT ObjCTurboModule : public TurboModule { ObjCTurboModule(const InitParams ¶ms); + virtual bool isInteropModule() const + { + return false; + } + jsi::Value invokeObjCMethod( jsi::Runtime &runtime, TurboModuleMethodValueKind returnType, diff --git a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm index a1111f9c8565..5af072206a27 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm +++ b/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.mm @@ -746,6 +746,10 @@ TraceSection s( return true; } + if (returnType == VoidKind && ReactNativeFeatureFlags::enableSyncVoidMethods() && !isInteropModule()) { + return true; + } + return returnType != VoidKind && returnType != PromiseKind; } @@ -798,13 +802,14 @@ TraceSection s( break; } case VoidKind: { - performVoidMethodInvocation(runtime, methodName, inv, retainedObjectsForInvocation); if (isSyncInvocation) { + performMethodInvocation(runtime, true, methodName, inv, retainedObjectsForInvocation); TurboModulePerfLogger::syncMethodCallReturnConversionStart(moduleName, methodName); - } - returnValue = jsi::Value::undefined(); - if (isSyncInvocation) { + returnValue = jsi::Value::undefined(); TurboModulePerfLogger::syncMethodCallReturnConversionEnd(moduleName, methodName); + } else { + performVoidMethodInvocation(runtime, methodName, inv, retainedObjectsForInvocation); + returnValue = jsi::Value::undefined(); } break; } diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index fa2b1c34d164..843769db43c5 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<<4deb82376e94d28a1d1775930ece1ccd>> + * @generated SignedSource<<7afde6ebd381a85d83f8359b4ce256df>> */ /** @@ -269,6 +269,11 @@ bool NativeReactNativeFeatureFlags::enableSwiftUIBasedFilters( return ReactNativeFeatureFlags::enableSwiftUIBasedFilters(); } +bool NativeReactNativeFeatureFlags::enableSyncVoidMethods( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::enableSyncVoidMethods(); +} + bool NativeReactNativeFeatureFlags::enableViewCulling( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::enableViewCulling(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index 1af7196475f8..33b2c51beefd 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<<1bc2c347fb241190b4ae048e12c5a885>> + * @generated SignedSource<> */ /** @@ -126,6 +126,8 @@ class NativeReactNativeFeatureFlags bool enableSwiftUIBasedFilters(jsi::Runtime& runtime); + bool enableSyncVoidMethods(jsi::Runtime& runtime); + bool enableViewCulling(jsi::Runtime& runtime); bool enableViewRecycling(jsi::Runtime& runtime); diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index a121712d7627..98fabfe07c85 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -525,6 +525,17 @@ const definitions: FeatureFlagDefinitions = { }, ossReleaseStage: 'canary', }, + enableSyncVoidMethods: { + defaultValue: false, + metadata: { + dateAdded: '2026-05-07', + description: + 'When enabled, TurboModule methods with void return type will be invoked synchronously on the JS thread instead of being dispatched asynchronously. Only applies to pure TurboModules, not interop modules.', + expectedReleaseValue: true, + purpose: 'experimentation', + }, + ossReleaseStage: 'none', + }, enableViewCulling: { defaultValue: false, metadata: { diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index 58505d265d49..5ebe61a9694c 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<<361b1ff3430ffad98aaf24bea3824208>> + * @generated SignedSource<<3d79b833c54b48e0915077071619f791>> * @flow strict * @noformat */ @@ -91,6 +91,7 @@ export type ReactNativeFeatureFlags = $ReadOnly<{ enablePropsUpdateReconciliationAndroid: Getter, enableSchedulerDelegateInvalidation: Getter, enableSwiftUIBasedFilters: Getter, + enableSyncVoidMethods: Getter, enableViewCulling: Getter, enableViewRecycling: Getter, enableViewRecyclingForImage: Getter, @@ -379,6 +380,10 @@ export const enableSchedulerDelegateInvalidation: Getter = createNative * When enabled, it will use SwiftUI for filter effects like blur on iOS. */ export const enableSwiftUIBasedFilters: Getter = createNativeFlagGetter('enableSwiftUIBasedFilters', false); +/** + * When enabled, TurboModule methods with void return type will be invoked synchronously on the JS thread instead of being dispatched asynchronously. Only applies to pure TurboModules, not interop modules. + */ +export const enableSyncVoidMethods: Getter = createNativeFlagGetter('enableSyncVoidMethods', false); /** * Enables View Culling: as soon as a view goes off screen, it can be reused anywhere in the UI and pieced together with other items to create new UI elements. */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index 59a8ae061881..121d270b918c 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<<69bfd288593aebd59355309a7777cd79>> + * @generated SignedSource<<3e10c2fb17c7ae0237b699316274a67b>> * @flow strict * @noformat */ @@ -70,6 +70,7 @@ export interface Spec extends TurboModule { +enablePropsUpdateReconciliationAndroid?: () => boolean; +enableSchedulerDelegateInvalidation?: () => boolean; +enableSwiftUIBasedFilters?: () => boolean; + +enableSyncVoidMethods?: () => boolean; +enableViewCulling?: () => boolean; +enableViewRecycling?: () => boolean; +enableViewRecyclingForImage?: () => boolean; diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api index bef10cabb729..f19328c85b07 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api @@ -3002,6 +3002,7 @@ class facebook::react::JWritableMapBuffer : public facebook::jni::JavaClass& methodDescriptors); + public virtual bool isInteropModule() const override; public virtual std::vector getPropertyNames(facebook::jsi::Runtime& runtime) override; } @@ -3044,6 +3045,7 @@ class facebook::react::JavaTurboModule : public facebook::react::TurboModule { protected void setEventEmitterCallback(jni::alias_ref); public JavaTurboModule(const facebook::react::JavaTurboModule::InitParams& params); public facebook::jsi::Value invokeJavaMethod(facebook::jsi::Runtime& runtime, facebook::react::TurboModuleMethodValueKind valueKind, const std::string& methodName, const std::string& methodSignature, const facebook::jsi::Value* args, size_t argCount, jmethodID& cachedMethodID); + public virtual bool isInteropModule() const; public virtual ~JavaTurboModule(); } diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api index 68b1a1f4344c..eff51ff7cc53 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api @@ -2999,6 +2999,7 @@ class facebook::react::JWritableMapBuffer : public facebook::jni::JavaClass& methodDescriptors); + public virtual bool isInteropModule() const override; public virtual std::vector getPropertyNames(facebook::jsi::Runtime& runtime) override; } @@ -3041,6 +3042,7 @@ class facebook::react::JavaTurboModule : public facebook::react::TurboModule { protected void setEventEmitterCallback(jni::alias_ref); public JavaTurboModule(const facebook::react::JavaTurboModule::InitParams& params); public facebook::jsi::Value invokeJavaMethod(facebook::jsi::Runtime& runtime, facebook::react::TurboModuleMethodValueKind valueKind, const std::string& methodName, const std::string& methodSignature, const facebook::jsi::Value* args, size_t argCount, jmethodID& cachedMethodID); + public virtual bool isInteropModule() const; public virtual ~JavaTurboModule(); } diff --git a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api index c1530e62333c..03c4321e6a68 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api @@ -6482,6 +6482,7 @@ class facebook::react::ObjCInteropTurboModule : public facebook::react::ObjCTurb protected virtual facebook::jsi::Value create(facebook::jsi::Runtime& runtime, const facebook::jsi::PropNameID& propName) override; protected virtual void setInvocationArg(facebook::jsi::Runtime& runtime, const char* methodName, const std::string& objCArgType, const facebook::jsi::Value& arg, size_t i, NSInvocation* inv, NSMutableArray* retainedObjectsForInvocation) override; public ObjCInteropTurboModule(const facebook::react::ObjCTurboModule::InitParams& params); + public virtual bool isInteropModule() const override; public virtual std::vector getPropertyNames(facebook::jsi::Runtime& runtime) override; } @@ -6502,6 +6503,7 @@ class facebook::react::ObjCTurboModule : public facebook::react::TurboModule { public facebook::jsi::Value invokeObjCMethod(facebook::jsi::Runtime& runtime, facebook::react::TurboModuleMethodValueKind returnType, const std::string& methodName, SEL selector, const facebook::jsi::Value* args, size_t count); public id instance_; public std::shared_ptr nativeMethodCallInvoker_; + public virtual bool isInteropModule() const; } struct facebook::react::ObjCTurboModule::InitParams { diff --git a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api index b085abf3af7e..787f6db953b6 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api @@ -6479,6 +6479,7 @@ class facebook::react::ObjCInteropTurboModule : public facebook::react::ObjCTurb protected virtual facebook::jsi::Value create(facebook::jsi::Runtime& runtime, const facebook::jsi::PropNameID& propName) override; protected virtual void setInvocationArg(facebook::jsi::Runtime& runtime, const char* methodName, const std::string& objCArgType, const facebook::jsi::Value& arg, size_t i, NSInvocation* inv, NSMutableArray* retainedObjectsForInvocation) override; public ObjCInteropTurboModule(const facebook::react::ObjCTurboModule::InitParams& params); + public virtual bool isInteropModule() const override; public virtual std::vector getPropertyNames(facebook::jsi::Runtime& runtime) override; } @@ -6499,6 +6500,7 @@ class facebook::react::ObjCTurboModule : public facebook::react::TurboModule { public facebook::jsi::Value invokeObjCMethod(facebook::jsi::Runtime& runtime, facebook::react::TurboModuleMethodValueKind returnType, const std::string& methodName, SEL selector, const facebook::jsi::Value* args, size_t count); public id instance_; public std::shared_ptr nativeMethodCallInvoker_; + public virtual bool isInteropModule() const; } struct facebook::react::ObjCTurboModule::InitParams {