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 58fef2240b5c..fb2d9625c184 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<<3272436c25e63e1e2152f4af9aafcffa>> */ /** @@ -306,6 +306,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 af835e326c9c..145192b2c9cf 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<<189cc2dd3b42cd736191f13b442e7317>> + * @generated SignedSource<<62523747d1f721ebc68d3b3b77bc4a48>> */ /** @@ -66,6 +66,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 @@ -527,6 +528,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 4d938732cdfd..86df07d0bfcd 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<<81c6672ae539af203fae7e0f9cf541a6>> + * @generated SignedSource<<2b91d3a03ec71265f0f9d1f25cf61d66>> */ /** @@ -120,6 +120,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 da6ecfa21521..86c14183fe3d 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<<053d67947ccd1a3556c8f6e1b6af5a14>> + * @generated SignedSource<<46918ab06dcb1dd3c1409a2bf847e775>> */ /** @@ -115,6 +115,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 62e08a41871b..2a427b086379 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<<24972f077ba738a8191a2956be61b491>> + * @generated SignedSource<> */ /** @@ -70,6 +70,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 @@ -577,6 +578,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 5b6f5a0134a2..690f02a849f4 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<<6dd7973e8cdb5896dd05cc34d32b4d87>> */ /** @@ -115,6 +115,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 550dea7bf2e2..1b7aa49152ac 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<<74f0602ce337a86730efe638ab8e966d>> + * @generated SignedSource<<41c6ef0fd874996ba107d6e6ef8d0c56>> */ /** @@ -315,6 +315,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"); @@ -825,6 +831,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(); @@ -1224,6 +1235,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 ae047522710f..3e05cedc3a79 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<<2e867941f693c14c0c52475d790cfed4>> + * @generated SignedSource<<4fa295306f59d64cbfe739fa68cdf7fa>> */ /** @@ -168,6 +168,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 c2df5fcedb2a..1c8cb5ed7039 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<<9c49f2931ab219997bc29969de95805d>> + * @generated SignedSource<<71a2b6b2ad1cfff01739580ab7a3e968>> */ /** @@ -210,6 +210,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 b951c7359443..3c97c5751c88 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -269,6 +269,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 cedf28e78a41..c3bd8600b50e 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<<51ffddd6283069a1846336c65d40338c>> + * @generated SignedSource<> */ /** @@ -857,6 +857,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(46, "enableSyncVoidMethods"); + + flagValue = currentProvider_->enableSyncVoidMethods(); + enableSyncVoidMethods_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::enableViewCulling() { auto flagValue = enableViewCulling_.load(); @@ -866,7 +884,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(46, "enableViewCulling"); + markFlagAsAccessed(47, "enableViewCulling"); flagValue = currentProvider_->enableViewCulling(); enableViewCulling_ = flagValue; @@ -884,7 +902,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(47, "enableViewRecycling"); + markFlagAsAccessed(48, "enableViewRecycling"); flagValue = currentProvider_->enableViewRecycling(); enableViewRecycling_ = flagValue; @@ -902,7 +920,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(48, "enableViewRecyclingForImage"); + markFlagAsAccessed(49, "enableViewRecyclingForImage"); flagValue = currentProvider_->enableViewRecyclingForImage(); enableViewRecyclingForImage_ = flagValue; @@ -920,7 +938,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(49, "enableViewRecyclingForScrollView"); + markFlagAsAccessed(50, "enableViewRecyclingForScrollView"); flagValue = currentProvider_->enableViewRecyclingForScrollView(); enableViewRecyclingForScrollView_ = flagValue; @@ -938,7 +956,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(50, "enableViewRecyclingForText"); + markFlagAsAccessed(51, "enableViewRecyclingForText"); flagValue = currentProvider_->enableViewRecyclingForText(); enableViewRecyclingForText_ = flagValue; @@ -956,7 +974,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(51, "enableViewRecyclingForView"); + markFlagAsAccessed(52, "enableViewRecyclingForView"); flagValue = currentProvider_->enableViewRecyclingForView(); enableViewRecyclingForView_ = flagValue; @@ -974,7 +992,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(52, "enableVirtualViewContainerStateExperimental"); + markFlagAsAccessed(53, "enableVirtualViewContainerStateExperimental"); flagValue = currentProvider_->enableVirtualViewContainerStateExperimental(); enableVirtualViewContainerStateExperimental_ = flagValue; @@ -992,7 +1010,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(53, "enableVirtualViewDebugFeatures"); + markFlagAsAccessed(54, "enableVirtualViewDebugFeatures"); flagValue = currentProvider_->enableVirtualViewDebugFeatures(); enableVirtualViewDebugFeatures_ = flagValue; @@ -1010,7 +1028,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(54, "fixDifferentiatorParentTagForUnflattenCase"); + markFlagAsAccessed(55, "fixDifferentiatorParentTagForUnflattenCase"); flagValue = currentProvider_->fixDifferentiatorParentTagForUnflattenCase(); fixDifferentiatorParentTagForUnflattenCase_ = flagValue; @@ -1028,7 +1046,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(55, "fixFindShadowNodeByTagRaceCondition"); + markFlagAsAccessed(56, "fixFindShadowNodeByTagRaceCondition"); flagValue = currentProvider_->fixFindShadowNodeByTagRaceCondition(); fixFindShadowNodeByTagRaceCondition_ = flagValue; @@ -1046,7 +1064,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(56, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); + markFlagAsAccessed(57, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); flagValue = currentProvider_->fixMappingOfEventPrioritiesBetweenFabricAndReact(); fixMappingOfEventPrioritiesBetweenFabricAndReact_ = flagValue; @@ -1064,7 +1082,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(57, "fixYogaFlexBasisFitContentInMainAxis"); + markFlagAsAccessed(58, "fixYogaFlexBasisFitContentInMainAxis"); flagValue = currentProvider_->fixYogaFlexBasisFitContentInMainAxis(); fixYogaFlexBasisFitContentInMainAxis_ = flagValue; @@ -1082,7 +1100,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(58, "fuseboxAssertSingleHostState"); + markFlagAsAccessed(59, "fuseboxAssertSingleHostState"); flagValue = currentProvider_->fuseboxAssertSingleHostState(); fuseboxAssertSingleHostState_ = flagValue; @@ -1100,7 +1118,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(59, "fuseboxEnabledRelease"); + markFlagAsAccessed(60, "fuseboxEnabledRelease"); flagValue = currentProvider_->fuseboxEnabledRelease(); fuseboxEnabledRelease_ = flagValue; @@ -1118,7 +1136,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(60, "fuseboxFrameRecordingEnabled"); + markFlagAsAccessed(61, "fuseboxFrameRecordingEnabled"); flagValue = currentProvider_->fuseboxFrameRecordingEnabled(); fuseboxFrameRecordingEnabled_ = flagValue; @@ -1136,7 +1154,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(61, "fuseboxNetworkInspectionEnabled"); + markFlagAsAccessed(62, "fuseboxNetworkInspectionEnabled"); flagValue = currentProvider_->fuseboxNetworkInspectionEnabled(); fuseboxNetworkInspectionEnabled_ = flagValue; @@ -1154,7 +1172,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(62, "fuseboxScreenshotCaptureEnabled"); + markFlagAsAccessed(63, "fuseboxScreenshotCaptureEnabled"); flagValue = currentProvider_->fuseboxScreenshotCaptureEnabled(); fuseboxScreenshotCaptureEnabled_ = flagValue; @@ -1172,7 +1190,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(63, "hideOffscreenVirtualViewsOnIOS"); + markFlagAsAccessed(64, "hideOffscreenVirtualViewsOnIOS"); flagValue = currentProvider_->hideOffscreenVirtualViewsOnIOS(); hideOffscreenVirtualViewsOnIOS_ = 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 745dae1b7fab..719426e2919b 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<<46d2d87deec97afaa3d5b89d22fc9ff7>> + * @generated SignedSource<<3326aca16ba12e34d9f02e94abca1082>> */ /** @@ -78,6 +78,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_; @@ -183,6 +184,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 2e03064e81b7..9db7aabe66b7 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<<3e3db9d13a20d62c9cfb80330de6b4e0>> + * @generated SignedSource<> */ /** @@ -211,6 +211,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 f613a6c53cc4..daa3ed334d10 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<<963ea85be18e1df973142b74addf3b16>> + * @generated SignedSource<<3881fa99ccebddd334b4510903e0b748>> */ /** @@ -459,6 +459,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 34c682a21cf6..eabc4b777cc0 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<6025d7856ba3674a18bbc05eeba3e94a>> */ /** @@ -71,6 +71,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 35e340808300..49c1c0ca4567 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<<9061422bb5437e737602f33e74453779>> + * @generated SignedSource<<82739e50ab1b4736e9687dfe0beffd60>> */ /** @@ -274,6 +274,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 03256727f721..84bc26ca1eb5 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<<295f75a120dcf079af2846c5cabb8bb4>> + * @generated SignedSource<> */ /** @@ -128,6 +128,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 2ffbc02a78a8..f9c82a3fea8e 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -536,6 +536,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 852d46623502..4623dfde4798 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<<72c610dc5a8efc1eba2121949e1c24a0>> + * @generated SignedSource<> * @flow strict * @noformat */ @@ -92,6 +92,7 @@ export type ReactNativeFeatureFlags = $ReadOnly<{ enablePropsUpdateReconciliationAndroid: Getter, enableSchedulerDelegateInvalidation: Getter, enableSwiftUIBasedFilters: Getter, + enableSyncVoidMethods: Getter, enableViewCulling: Getter, enableViewRecycling: Getter, enableViewRecyclingForImage: Getter, @@ -383,6 +384,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 8e118718a57c..4583f5b5f80f 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<<198728d86480c873bf44fc0d8d1633ef>> + * @generated SignedSource<<0d1f09cabeb016f14be43787257634fe>> * @flow strict * @noformat */ @@ -71,6 +71,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 54d994781de4..69638379e986 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api @@ -2996,6 +2996,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; } @@ -3038,6 +3039,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 6a0a48343467..0aa8972473a4 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api @@ -2993,6 +2993,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; } @@ -3035,6 +3036,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 bb3a74b3522e..661b67ba3b2b 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api @@ -6442,6 +6442,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; } @@ -6462,6 +6463,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 53f03430fc4b..04fc59011518 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api @@ -6439,6 +6439,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; } @@ -6459,6 +6460,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 {