diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java index 313e5d66ea4f04..242cdf5661a516 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java @@ -165,4 +165,10 @@ public class ReactFeatureFlags { /** Enables Stable API for TurboModule (removal of ReactModule, ReactModuleInfoProvider). */ public static boolean enableTurboModuleStableAPI = false; + + /** + * When enabled, it uses the modern fork of RuntimeScheduler that allows scheduling tasks with + * priorities from any thread. + */ + public static boolean useModernRuntimeScheduler = false; } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactInstance.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactInstance.java index a9f01fda727a3e..1c5fc2a9db1354 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactInstance.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactInstance.java @@ -170,6 +170,9 @@ public void onHostDestroy() { // Notify JS if profiling is enabled boolean isProfiling = Systrace.isTracing(Systrace.TRACE_TAG_REACT_APPS | Systrace.TRACE_TAG_REACT_JS_VM_CALLS); + // TODO(T166383606): Remove this parameter when we remove the legacy runtime scheduler or we + // have access to ReactNativeConfig before we initialize it. + boolean useModernRuntimeScheduler = ReactFeatureFlags.useModernRuntimeScheduler; mHybridData = initHybrid( jsEngineInstance, @@ -179,7 +182,8 @@ public void onHostDestroy() { jsTimerExecutor, reactExceptionManager, bindingsInstaller, - isProfiling); + isProfiling, + useModernRuntimeScheduler); RuntimeExecutor unbufferedRuntimeExecutor = getUnbufferedRuntimeExecutor(); @@ -435,7 +439,8 @@ private native HybridData initHybrid( JSTimerExecutor jsTimerExecutor, ReactJsExceptionHandler jReactExceptionsManager, @Nullable BindingsInstaller jBindingsInstaller, - boolean isProfiling); + boolean isProfiling, + boolean useModernRuntimeScheduler); @DoNotStrip private static native JSTimerExecutor createJSTimerExecutor(); diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.cpp index 832b8aa6f2ccf8..325c3c32d0646d 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.cpp @@ -36,7 +36,8 @@ JReactInstance::JReactInstance( jni::alias_ref jsTimerExecutor, jni::alias_ref jReactExceptionManager, jni::alias_ref jBindingsInstaller, - bool isProfiling) noexcept { + bool isProfiling, + bool useModernRuntimeScheduler) noexcept { // TODO(janzer): Lazily create runtime auto sharedJSMessageQueueThread = std::make_shared(jsMessageQueueThread); @@ -64,7 +65,8 @@ JReactInstance::JReactInstance( jsEngineInstance->cthis()->createJSRuntime(sharedJSMessageQueueThread), sharedJSMessageQueueThread, timerManager, - std::move(jsErrorHandlingFunc)); + std::move(jsErrorHandlingFunc), + useModernRuntimeScheduler); auto bufferedRuntimeExecutor = instance_->getBufferedRuntimeExecutor(); timerManager->setRuntimeExecutor(bufferedRuntimeExecutor); @@ -115,7 +117,8 @@ jni::local_ref JReactInstance::initHybrid( jni::alias_ref jsTimerExecutor, jni::alias_ref jReactExceptionManager, jni::alias_ref jBindingsInstaller, - bool isProfiling) { + bool isProfiling, + bool useModernRuntimeScheduler) { return makeCxxInstance( jsEngineInstance, jsMessageQueueThread, @@ -124,7 +127,8 @@ jni::local_ref JReactInstance::initHybrid( jsTimerExecutor, jReactExceptionManager, jBindingsInstaller, - isProfiling); + isProfiling, + useModernRuntimeScheduler); } void JReactInstance::loadJSBundleFromAssets( diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.h b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.h index 55ec3e9ffa105a..0fd9a28a438a28 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/runtime/jni/JReactInstance.h @@ -45,7 +45,8 @@ class JReactInstance : public jni::HybridClass { jni::alias_ref jsTimerExecutor, jni::alias_ref jReactExceptionManager, jni::alias_ref jBindingsInstaller, - bool isProfiling); + bool isProfiling, + bool useModernRuntimeScheduler); /* * Instantiates and returns an instance of `JSTimerExecutor`. @@ -90,7 +91,8 @@ class JReactInstance : public jni::HybridClass { jni::alias_ref jsTimerExecutor, jni::alias_ref jReactExceptionManager, jni::alias_ref jBindingsInstaller, - bool isProfiling) noexcept; + bool isProfiling, + bool useModernRuntimeScheduler) noexcept; jni::alias_ref getJSCallInvokerHolder(); jni::alias_ref diff --git a/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp b/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp index abfda3b74a41ab..ecb994e9f3c0a2 100644 --- a/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp +++ b/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp @@ -28,7 +28,8 @@ ReactInstance::ReactInstance( std::unique_ptr runtime, std::shared_ptr jsMessageQueueThread, std::shared_ptr timerManager, - JsErrorHandler::JsErrorHandlingFunc jsErrorHandlingFunc) + JsErrorHandler::JsErrorHandlingFunc jsErrorHandlingFunc, + bool useModernRuntimeScheduler) : runtime_(std::move(runtime)), jsMessageQueueThread_(jsMessageQueueThread), timerManager_(std::move(timerManager)), @@ -75,8 +76,8 @@ ReactInstance::ReactInstance( } }; - runtimeScheduler_ = - std::make_shared(std::move(runtimeExecutor)); + runtimeScheduler_ = std::make_shared( + std::move(runtimeExecutor), useModernRuntimeScheduler); auto pipedRuntimeExecutor = [runtimeScheduler = runtimeScheduler_.get()]( diff --git a/packages/react-native/ReactCommon/react/runtime/ReactInstance.h b/packages/react-native/ReactCommon/react/runtime/ReactInstance.h index f3126c302f387d..0d1762af01c529 100644 --- a/packages/react-native/ReactCommon/react/runtime/ReactInstance.h +++ b/packages/react-native/ReactCommon/react/runtime/ReactInstance.h @@ -32,7 +32,8 @@ class ReactInstance final { std::unique_ptr runtime, std::shared_ptr jsMessageQueueThread, std::shared_ptr timerManager, - JsErrorHandler::JsErrorHandlingFunc JsErrorHandlingFunc); + JsErrorHandler::JsErrorHandlingFunc JsErrorHandlingFunc, + bool useModernRuntimeScheduler = false); RuntimeExecutor getUnbufferedRuntimeExecutor() noexcept; diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.h b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.h index 2d57954823b273..3dc528f8a506ec 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.h +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.h @@ -35,6 +35,18 @@ NS_ASSUME_NONNULL_BEGIN @end +/** + * This is a private protocol used to configure internal behavior of the runtime. + * DO NOT USE THIS OUTSIDE OF THE REACT NATIVE CODEBASE. + */ +@protocol RCTHostDelegateInternal + +// TODO(T166383606): Remove this method when we remove the legacy runtime scheduler or we have access to +// ReactNativeConfig before we initialize it. +- (BOOL)useModernRuntimeScheduler:(RCTHost *)host; + +@end + @protocol RCTHostRuntimeDelegate - (void)host:(RCTHost *)host didInitializeRuntime:(facebook::jsi::Runtime &)runtime; diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm index f733d5514f6c8d..53ddc5cab4368b 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm @@ -23,7 +23,7 @@ using namespace facebook::react; -@interface RCTHost () +@interface RCTHost () @end @implementation RCTHost { @@ -247,6 +247,17 @@ - (void)instance:(RCTInstance *)instance didInitializeRuntime:(facebook::jsi::Ru [self.runtimeDelegate host:self didInitializeRuntime:runtime]; } +#pragma mark - RCTInstanceDelegateInternal + +- (BOOL)useModernRuntimeScheduler:(RCTHost *)host +{ + if ([_hostDelegate respondsToSelector:@selector(useModernRuntimeScheduler:)]) { + return [(id)_hostDelegate useModernRuntimeScheduler:self]; + } + + return NO; +} + #pragma mark - RCTContextContainerHandling - (void)didCreateContextContainer:(std::shared_ptr)contextContainer diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.h b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.h index be1bc2207c89ec..79e9ff50e2e9ee 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.h +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.h @@ -46,6 +46,18 @@ RCT_EXTERN void RCTInstanceSetRuntimeDiagnosticFlags(NSString *_Nullable flags); @end +/** + * This is a private protocol used to configure internal behavior of the runtime. + * DO NOT USE THIS OUTSIDE OF THE REACT NATIVE CODEBASE. + */ +@protocol RCTInstanceDelegateInternal + +// TODO(T166383606): Remove this method when we remove the legacy runtime scheduler or we have access to +// ReactNativeConfig before we initialize it. +- (BOOL)useModernRuntimeScheduler:(RCTInstance *)instance; + +@end + typedef void (^_Null_unspecified RCTInstanceInitialBundleLoadCompletionBlock)(); /** diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm index f73100ae5fdc53..bf5bd8fe6ba42d 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm @@ -216,12 +216,18 @@ - (void)_start __weak __typeof(self) weakSelf = self; auto jsErrorHandlingFunc = [=](MapBuffer errorMap) { [weakSelf _handleJSErrorMap:std::move(errorMap)]; }; + auto useModernRuntimeScheduler = false; + if ([_delegate respondsToSelector:@selector(useModernRuntimeScheduler:)]) { + useModernRuntimeScheduler = [(id)_delegate useModernRuntimeScheduler:self]; + } + // Create the React Instance _reactInstance = std::make_unique( _jsEngineInstance->createJSRuntime(_jsThreadManager.jsMessageThread), _jsThreadManager.jsMessageThread, timerManager, - jsErrorHandlingFunc); + jsErrorHandlingFunc, + useModernRuntimeScheduler); _valid = true; RuntimeExecutor bufferedRuntimeExecutor = _reactInstance->getBufferedRuntimeExecutor();