Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Eagerly initialize TurboModules before executing JS bundle
Summary: ## Context 1. In FBReactModule jsExecutorForBridge, we asynchronously initialize a list of TurboModules on the main queue: https://fburl.com/diffusion/i56wi3px 2. After initializing the bridge, we start executing the JS bundle, here: https://github.com/facebook/react-native/blob/e23e9328aa164d0a70fe4f16042c982e7801d924/React/CxxBridge/RCTCxxBridge.mm#L414-L417. Since bridge initialization knows nothing about TurboModule eager initialization, this happens concurrently with 1, and starts requiring NativeModules/TurboModules on the JS thread. ## The Race 1. Both the main thread and the JS thread race to create a TurboModule that requires main queue setup. 2. The JS thread wins, and starts creating the TurboModule. Meanwhile, the main thread blocks, waiting on a signal here, in RCTTurboModuleManager: https://github.com/facebook/react-native/blob/e23e9328aa164d0a70fe4f16042c982e7801d924/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm#L430 3. The JS thread tries to dispatch_sync to the main queue to setup the TurboModule because the TurboModule requires main queue setup, here: https://github.com/facebook/react-native/blob/e23e9328aa164d0a70fe4f16042c982e7801d924/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm#L402 4. We deadlock. ## The fix Succinctly, NativeModule eager initialization finishes before execute the JS bundle, but TurboModule initialization doesn't. This diff corrects that mistake. The changes in this diff: 1. The RN application via the TurboModuleManager delegate can now optionally provide the names of all eagerly initialized TurboModules by implementing two methods `getEagerInitModuleNames`, `getEagerInitMainQueueModuleNames`. 2. The TurboModuleManager grabs these two lists from the delegate, and exposes them to its owner via the `RCTTurboModuleRegistry` protocol. 3. The RCTCxxBridge, which already owns a `id<RCTTurboModuleRegistry>` object, uses it to eagerly initialize the TurboModules in these two lists with the correct timing requirements. This is exactly how we implement eager initialization in Android. **Note:** Right now, phase one and two of TurboModule eager initialization happen after phase one and two of NativeModule eager initialization. We could make the timing even more correct by initializing the TurboModules at the exact same time we initialize the NativeModules. However, that would require a bit more surgery on the bridge, and the bridge delegate. I think this is good enough for now. Changelog: [iOS][Fixed] - Fix TurboModule eager init race Reviewed By: PeteTheHeat Differential Revision: D22406171 fbshipit-source-id: 4715be0bceb478a8e4aa206180c0316eaaf287e8
- Loading branch information