RCTCxxBridge.mm 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #include <atomic>
  8. #include <future>
  9. #import <React/RCTAssert.h>
  10. #import <React/RCTBridge+Private.h>
  11. #import <React/RCTBridge.h>
  12. #import <React/RCTBridgeMethod.h>
  13. #import <React/RCTConvert.h>
  14. #import <React/RCTCxxBridgeDelegate.h>
  15. #import <React/RCTCxxModule.h>
  16. #import <React/RCTCxxUtils.h>
  17. #import <React/RCTDevSettings.h>
  18. #import <React/RCTDisplayLink.h>
  19. #import <React/RCTFollyConvert.h>
  20. #import <React/RCTJavaScriptLoader.h>
  21. #import <React/RCTLog.h>
  22. #import <React/RCTModuleData.h>
  23. #import <React/RCTPerformanceLogger.h>
  24. #import <React/RCTProfile.h>
  25. #import <React/RCTRedBox.h>
  26. #import <React/RCTReloadCommand.h>
  27. #import <React/RCTUtils.h>
  28. #import <cxxreact/CxxNativeModule.h>
  29. #import <cxxreact/Instance.h>
  30. #import <cxxreact/JSBundleType.h>
  31. #import <cxxreact/JSIndexedRAMBundle.h>
  32. #import <cxxreact/ModuleRegistry.h>
  33. #import <cxxreact/RAMBundleRegistry.h>
  34. #import <cxxreact/ReactMarker.h>
  35. #import <jsireact/JSIExecutor.h>
  36. #import "JSCExecutorFactory.h"
  37. #import "NSDataBigString.h"
  38. #import "RCTMessageThread.h"
  39. #import "RCTObjcExecutor.h"
  40. #ifdef WITH_FBSYSTRACE
  41. #import <React/RCTFBSystrace.h>
  42. #endif
  43. #if (RCT_DEV | RCT_ENABLE_LOADING_VIEW) && __has_include(<React/RCTDevLoadingViewProtocol.h>)
  44. #import <React/RCTDevLoadingViewProtocol.h>
  45. #endif
  46. static NSString *const RCTJSThreadName = @"com.facebook.react.JavaScript";
  47. typedef void (^RCTPendingCall)();
  48. using namespace facebook::jsi;
  49. using namespace facebook::react;
  50. /**
  51. * Must be kept in sync with `MessageQueue.js`.
  52. */
  53. typedef NS_ENUM(NSUInteger, RCTBridgeFields) {
  54. RCTBridgeFieldRequestModuleIDs = 0,
  55. RCTBridgeFieldMethodIDs,
  56. RCTBridgeFieldParams,
  57. RCTBridgeFieldCallID,
  58. };
  59. namespace {
  60. class GetDescAdapter : public JSExecutorFactory {
  61. public:
  62. GetDescAdapter(RCTCxxBridge *bridge, std::shared_ptr<JSExecutorFactory> factory) : bridge_(bridge), factory_(factory)
  63. {
  64. }
  65. std::unique_ptr<JSExecutor> createJSExecutor(
  66. std::shared_ptr<ExecutorDelegate> delegate,
  67. std::shared_ptr<MessageQueueThread> jsQueue) override
  68. {
  69. auto ret = factory_->createJSExecutor(delegate, jsQueue);
  70. bridge_.bridgeDescription = @(ret->getDescription().c_str());
  71. return ret;
  72. }
  73. private:
  74. RCTCxxBridge *bridge_;
  75. std::shared_ptr<JSExecutorFactory> factory_;
  76. };
  77. }
  78. static bool isRAMBundle(NSData *script)
  79. {
  80. BundleHeader header;
  81. [script getBytes:&header length:sizeof(header)];
  82. return parseTypeFromHeader(header) == ScriptTag::RAMBundle;
  83. }
  84. static void notifyAboutModuleSetup(RCTPerformanceLogger *performanceLogger, const char *tag)
  85. {
  86. NSString *moduleName = [[NSString alloc] initWithUTF8String:tag];
  87. if (moduleName) {
  88. int64_t setupTime = [performanceLogger durationForTag:RCTPLNativeModuleSetup];
  89. [[NSNotificationCenter defaultCenter] postNotificationName:RCTDidSetupModuleNotification
  90. object:nil
  91. userInfo:@{
  92. RCTDidSetupModuleNotificationModuleNameKey : moduleName,
  93. RCTDidSetupModuleNotificationSetupTimeKey : @(setupTime)
  94. }];
  95. }
  96. }
  97. static void registerPerformanceLoggerHooks(RCTPerformanceLogger *performanceLogger)
  98. {
  99. __weak RCTPerformanceLogger *weakPerformanceLogger = performanceLogger;
  100. ReactMarker::logTaggedMarker = [weakPerformanceLogger](
  101. const ReactMarker::ReactMarkerId markerId, const char *__unused tag) {
  102. switch (markerId) {
  103. case ReactMarker::RUN_JS_BUNDLE_START:
  104. [weakPerformanceLogger markStartForTag:RCTPLScriptExecution];
  105. break;
  106. case ReactMarker::RUN_JS_BUNDLE_STOP:
  107. [weakPerformanceLogger markStopForTag:RCTPLScriptExecution];
  108. break;
  109. case ReactMarker::NATIVE_REQUIRE_START:
  110. [weakPerformanceLogger appendStartForTag:RCTPLRAMNativeRequires];
  111. break;
  112. case ReactMarker::NATIVE_REQUIRE_STOP:
  113. [weakPerformanceLogger appendStopForTag:RCTPLRAMNativeRequires];
  114. [weakPerformanceLogger addValue:1 forTag:RCTPLRAMNativeRequiresCount];
  115. break;
  116. case ReactMarker::NATIVE_MODULE_SETUP_START:
  117. [weakPerformanceLogger markStartForTag:RCTPLNativeModuleSetup];
  118. break;
  119. case ReactMarker::NATIVE_MODULE_SETUP_STOP:
  120. [weakPerformanceLogger markStopForTag:RCTPLNativeModuleSetup];
  121. notifyAboutModuleSetup(weakPerformanceLogger, tag);
  122. break;
  123. case ReactMarker::CREATE_REACT_CONTEXT_STOP:
  124. case ReactMarker::JS_BUNDLE_STRING_CONVERT_START:
  125. case ReactMarker::JS_BUNDLE_STRING_CONVERT_STOP:
  126. case ReactMarker::REGISTER_JS_SEGMENT_START:
  127. case ReactMarker::REGISTER_JS_SEGMENT_STOP:
  128. // These are not used on iOS.
  129. break;
  130. }
  131. };
  132. }
  133. @interface RCTCxxBridge ()
  134. @property (nonatomic, weak, readonly) RCTBridge *parentBridge;
  135. @property (nonatomic, assign, readonly) BOOL moduleSetupComplete;
  136. - (instancetype)initWithParentBridge:(RCTBridge *)bridge;
  137. - (void)partialBatchDidFlush;
  138. - (void)batchDidComplete;
  139. @end
  140. struct RCTInstanceCallback : public InstanceCallback {
  141. __weak RCTCxxBridge *bridge_;
  142. RCTInstanceCallback(RCTCxxBridge *bridge) : bridge_(bridge){};
  143. void onBatchComplete() override
  144. {
  145. // There's no interface to call this per partial batch
  146. [bridge_ partialBatchDidFlush];
  147. [bridge_ batchDidComplete];
  148. }
  149. };
  150. @implementation RCTCxxBridge {
  151. BOOL _didInvalidate;
  152. BOOL _moduleRegistryCreated;
  153. NSMutableArray<RCTPendingCall> *_pendingCalls;
  154. std::atomic<NSInteger> _pendingCount;
  155. // Native modules
  156. NSMutableDictionary<NSString *, RCTModuleData *> *_moduleDataByName;
  157. NSMutableArray<RCTModuleData *> *_moduleDataByID;
  158. NSMutableArray<Class> *_moduleClassesByID;
  159. NSUInteger _modulesInitializedOnMainQueue;
  160. RCTDisplayLink *_displayLink;
  161. // JS thread management
  162. NSThread *_jsThread;
  163. std::shared_ptr<RCTMessageThread> _jsMessageThread;
  164. std::mutex _moduleRegistryLock;
  165. // This is uniquely owned, but weak_ptr is used.
  166. std::shared_ptr<Instance> _reactInstance;
  167. // Necessary for searching in TurboModuleRegistry
  168. id<RCTTurboModuleLookupDelegate> _turboModuleLookupDelegate;
  169. }
  170. @synthesize bridgeDescription = _bridgeDescription;
  171. @synthesize loading = _loading;
  172. @synthesize performanceLogger = _performanceLogger;
  173. @synthesize valid = _valid;
  174. - (void)setRCTTurboModuleLookupDelegate:(id<RCTTurboModuleLookupDelegate>)turboModuleLookupDelegate
  175. {
  176. _turboModuleLookupDelegate = turboModuleLookupDelegate;
  177. }
  178. - (std::shared_ptr<MessageQueueThread>)jsMessageThread
  179. {
  180. return _jsMessageThread;
  181. }
  182. - (BOOL)isInspectable
  183. {
  184. return _reactInstance ? _reactInstance->isInspectable() : NO;
  185. }
  186. - (instancetype)initWithParentBridge:(RCTBridge *)bridge
  187. {
  188. RCTAssertParam(bridge);
  189. if ((self = [super initWithDelegate:bridge.delegate
  190. bundleURL:bridge.bundleURL
  191. moduleProvider:bridge.moduleProvider
  192. launchOptions:bridge.launchOptions])) {
  193. _parentBridge = bridge;
  194. _performanceLogger = [bridge performanceLogger];
  195. registerPerformanceLoggerHooks(_performanceLogger);
  196. /**
  197. * Set Initial State
  198. */
  199. _valid = YES;
  200. _loading = YES;
  201. _moduleRegistryCreated = NO;
  202. _pendingCalls = [NSMutableArray new];
  203. _displayLink = [RCTDisplayLink new];
  204. _moduleDataByName = [NSMutableDictionary new];
  205. _moduleClassesByID = [NSMutableArray new];
  206. _moduleDataByID = [NSMutableArray new];
  207. [RCTBridge setCurrentBridge:self];
  208. }
  209. return self;
  210. }
  211. + (void)runRunLoop
  212. {
  213. @autoreleasepool {
  214. RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge runJSRunLoop] setup", nil);
  215. // copy thread name to pthread name
  216. pthread_setname_np([NSThread currentThread].name.UTF8String);
  217. // Set up a dummy runloop source to avoid spinning
  218. CFRunLoopSourceContext noSpinCtx = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
  219. CFRunLoopSourceRef noSpinSource = CFRunLoopSourceCreate(NULL, 0, &noSpinCtx);
  220. CFRunLoopAddSource(CFRunLoopGetCurrent(), noSpinSource, kCFRunLoopDefaultMode);
  221. CFRelease(noSpinSource);
  222. RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
  223. // run the run loop
  224. while (kCFRunLoopRunStopped !=
  225. CFRunLoopRunInMode(
  226. kCFRunLoopDefaultMode, ((NSDate *)[NSDate distantFuture]).timeIntervalSinceReferenceDate, NO)) {
  227. RCTAssert(NO, @"not reached assertion"); // runloop spun. that's bad.
  228. }
  229. }
  230. }
  231. - (void)_tryAndHandleError:(dispatch_block_t)block
  232. {
  233. NSError *error = tryAndReturnError(block);
  234. if (error) {
  235. [self handleError:error];
  236. }
  237. }
  238. /**
  239. * Ensure block is run on the JS thread. If we're already on the JS thread, the block will execute synchronously.
  240. * If we're not on the JS thread, the block is dispatched to that thread. Any errors encountered while executing
  241. * the block will go through handleError:
  242. */
  243. - (void)ensureOnJavaScriptThread:(dispatch_block_t)block
  244. {
  245. RCTAssert(_jsThread, @"This method must not be called before the JS thread is created");
  246. // This does not use _jsMessageThread because it may be called early before the runloop reference is captured
  247. // and _jsMessageThread is valid. _jsMessageThread also doesn't allow us to shortcut the dispatch if we're
  248. // already on the correct thread.
  249. if ([NSThread currentThread] == _jsThread) {
  250. [self _tryAndHandleError:block];
  251. } else {
  252. [self performSelector:@selector(_tryAndHandleError:) onThread:_jsThread withObject:block waitUntilDone:NO];
  253. }
  254. }
  255. - (void)start
  256. {
  257. RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge start]", nil);
  258. [[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptWillStartLoadingNotification
  259. object:_parentBridge
  260. userInfo:@{@"bridge" : self}];
  261. // Set up the JS thread early
  262. _jsThread = [[NSThread alloc] initWithTarget:[self class] selector:@selector(runRunLoop) object:nil];
  263. _jsThread.name = RCTJSThreadName;
  264. _jsThread.qualityOfService = NSOperationQualityOfServiceUserInteractive;
  265. #if RCT_DEBUG
  266. _jsThread.stackSize *= 2;
  267. #endif
  268. [_jsThread start];
  269. dispatch_group_t prepareBridge = dispatch_group_create();
  270. [_performanceLogger markStartForTag:RCTPLNativeModuleInit];
  271. [self registerExtraModules];
  272. // Initialize all native modules that cannot be loaded lazily
  273. (void)[self _initializeModules:RCTGetModuleClasses() withDispatchGroup:prepareBridge lazilyDiscovered:NO];
  274. [self registerExtraLazyModules];
  275. [_performanceLogger markStopForTag:RCTPLNativeModuleInit];
  276. // This doesn't really do anything. The real work happens in initializeBridge.
  277. _reactInstance.reset(new Instance);
  278. __weak RCTCxxBridge *weakSelf = self;
  279. // Prepare executor factory (shared_ptr for copy into block)
  280. std::shared_ptr<JSExecutorFactory> executorFactory;
  281. if (!self.executorClass) {
  282. if ([self.delegate conformsToProtocol:@protocol(RCTCxxBridgeDelegate)]) {
  283. id<RCTCxxBridgeDelegate> cxxDelegate = (id<RCTCxxBridgeDelegate>)self.delegate;
  284. executorFactory = [cxxDelegate jsExecutorFactoryForBridge:self];
  285. }
  286. if (!executorFactory) {
  287. executorFactory = std::make_shared<JSCExecutorFactory>(nullptr);
  288. }
  289. } else {
  290. id<RCTJavaScriptExecutor> objcExecutor = [self moduleForClass:self.executorClass];
  291. executorFactory.reset(new RCTObjcExecutorFactory(objcExecutor, ^(NSError *error) {
  292. if (error) {
  293. [weakSelf handleError:error];
  294. }
  295. }));
  296. }
  297. // Dispatch the instance initialization as soon as the initial module metadata has
  298. // been collected (see initModules)
  299. dispatch_group_enter(prepareBridge);
  300. [self ensureOnJavaScriptThread:^{
  301. [weakSelf _initializeBridge:executorFactory];
  302. dispatch_group_leave(prepareBridge);
  303. }];
  304. // Load the source asynchronously, then store it for later execution.
  305. dispatch_group_enter(prepareBridge);
  306. __block NSData *sourceCode;
  307. [self
  308. loadSource:^(NSError *error, RCTSource *source) {
  309. if (error) {
  310. [weakSelf handleError:error];
  311. }
  312. sourceCode = source.data;
  313. dispatch_group_leave(prepareBridge);
  314. }
  315. onProgress:^(RCTLoadingProgress *progressData) {
  316. #if (RCT_DEV | RCT_ENABLE_LOADING_VIEW) && __has_include(<React/RCTDevLoadingViewProtocol.h>)
  317. id<RCTDevLoadingViewProtocol> loadingView = [weakSelf moduleForName:@"DevLoadingView"
  318. lazilyLoadIfNecessary:YES];
  319. [loadingView updateProgress:progressData];
  320. #endif
  321. }];
  322. // Wait for both the modules and source code to have finished loading
  323. dispatch_group_notify(prepareBridge, dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
  324. RCTCxxBridge *strongSelf = weakSelf;
  325. if (sourceCode && strongSelf.loading) {
  326. [strongSelf executeSourceCode:sourceCode sync:NO];
  327. }
  328. });
  329. RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
  330. }
  331. - (void)loadSource:(RCTSourceLoadBlock)_onSourceLoad onProgress:(RCTSourceLoadProgressBlock)onProgress
  332. {
  333. NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
  334. [center postNotificationName:RCTBridgeWillDownloadScriptNotification object:_parentBridge];
  335. [_performanceLogger markStartForTag:RCTPLScriptDownload];
  336. NSUInteger cookie = RCTProfileBeginAsyncEvent(0, @"JavaScript download", nil);
  337. // Suppress a warning if RCTProfileBeginAsyncEvent gets compiled out
  338. (void)cookie;
  339. RCTPerformanceLogger *performanceLogger = _performanceLogger;
  340. RCTSourceLoadBlock onSourceLoad = ^(NSError *error, RCTSource *source) {
  341. RCTProfileEndAsyncEvent(0, @"native", cookie, @"JavaScript download", @"JS async");
  342. [performanceLogger markStopForTag:RCTPLScriptDownload];
  343. [performanceLogger setValue:source.length forTag:RCTPLBundleSize];
  344. NSDictionary *userInfo = @{
  345. RCTBridgeDidDownloadScriptNotificationSourceKey : source ?: [NSNull null],
  346. RCTBridgeDidDownloadScriptNotificationBridgeDescriptionKey : self->_bridgeDescription ?: [NSNull null],
  347. };
  348. [center postNotificationName:RCTBridgeDidDownloadScriptNotification object:self->_parentBridge userInfo:userInfo];
  349. _onSourceLoad(error, source);
  350. };
  351. if ([self.delegate respondsToSelector:@selector(loadSourceForBridge:onProgress:onComplete:)]) {
  352. [self.delegate loadSourceForBridge:_parentBridge onProgress:onProgress onComplete:onSourceLoad];
  353. } else if ([self.delegate respondsToSelector:@selector(loadSourceForBridge:withBlock:)]) {
  354. [self.delegate loadSourceForBridge:_parentBridge withBlock:onSourceLoad];
  355. } else if (!self.bundleURL) {
  356. NSError *error = RCTErrorWithMessage(
  357. @"No bundle URL present.\n\nMake sure you're running a packager "
  358. "server or have included a .jsbundle file in your application bundle.");
  359. onSourceLoad(error, nil);
  360. } else {
  361. __weak RCTCxxBridge *weakSelf = self;
  362. [RCTJavaScriptLoader loadBundleAtURL:self.bundleURL
  363. onProgress:onProgress
  364. onComplete:^(NSError *error, RCTSource *source) {
  365. if (error) {
  366. [weakSelf handleError:error];
  367. return;
  368. }
  369. onSourceLoad(error, source);
  370. }];
  371. }
  372. }
  373. - (NSArray<Class> *)moduleClasses
  374. {
  375. if (RCT_DEBUG && _valid && _moduleClassesByID == nil) {
  376. RCTLogError(
  377. @"Bridge modules have not yet been initialized. You may be "
  378. "trying to access a module too early in the startup procedure.");
  379. }
  380. return _moduleClassesByID;
  381. }
  382. /**
  383. * Used by RCTUIManager
  384. */
  385. - (RCTModuleData *)moduleDataForName:(NSString *)moduleName
  386. {
  387. return _moduleDataByName[moduleName];
  388. }
  389. - (id)moduleForName:(NSString *)moduleName
  390. {
  391. return [self moduleForName:moduleName lazilyLoadIfNecessary:NO];
  392. }
  393. - (id)moduleForName:(NSString *)moduleName lazilyLoadIfNecessary:(BOOL)lazilyLoad
  394. {
  395. if (RCTTurboModuleEnabled() && _turboModuleLookupDelegate) {
  396. const char *moduleNameCStr = [moduleName UTF8String];
  397. if (lazilyLoad || [_turboModuleLookupDelegate moduleIsInitialized:moduleNameCStr]) {
  398. id<RCTTurboModule> module = [_turboModuleLookupDelegate moduleForName:moduleNameCStr warnOnLookupFailure:NO];
  399. if (module != nil) {
  400. return module;
  401. }
  402. }
  403. }
  404. if (!lazilyLoad) {
  405. return _moduleDataByName[moduleName].instance;
  406. }
  407. RCTModuleData *moduleData = _moduleDataByName[moduleName];
  408. if (moduleData) {
  409. if (![moduleData isKindOfClass:[RCTModuleData class]]) {
  410. // There is rare race condition where the data stored in the dictionary
  411. // may have been deallocated, which means the module instance is no longer
  412. // usable.
  413. return nil;
  414. }
  415. return moduleData.instance;
  416. }
  417. // Module may not be loaded yet, so attempt to force load it here.
  418. const BOOL result = [self.delegate respondsToSelector:@selector(bridge:didNotFindModule:)] &&
  419. [self.delegate bridge:self didNotFindModule:moduleName];
  420. if (result) {
  421. // Try again.
  422. moduleData = _moduleDataByName[moduleName];
  423. #if RCT_DEV
  424. // If the `_moduleDataByName` is nil, it must have been cleared by the reload.
  425. } else if (_moduleDataByName != nil) {
  426. RCTLogError(@"Unable to find module for %@", moduleName);
  427. }
  428. #else
  429. } else {
  430. RCTLogError(@"Unable to find module for %@", moduleName);
  431. }
  432. #endif
  433. return moduleData.instance;
  434. }
  435. - (BOOL)moduleIsInitialized:(Class)moduleClass
  436. {
  437. NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
  438. if (_moduleDataByName[moduleName].hasInstance) {
  439. return YES;
  440. }
  441. if (_turboModuleLookupDelegate) {
  442. return [_turboModuleLookupDelegate moduleIsInitialized:[moduleName UTF8String]];
  443. }
  444. return NO;
  445. }
  446. - (id)moduleForClass:(Class)moduleClass
  447. {
  448. return [self moduleForName:RCTBridgeModuleNameForClass(moduleClass) lazilyLoadIfNecessary:YES];
  449. }
  450. - (std::shared_ptr<ModuleRegistry>)_buildModuleRegistryUnlocked
  451. {
  452. if (!self.valid) {
  453. return {};
  454. }
  455. [_performanceLogger markStartForTag:RCTPLNativeModulePrepareConfig];
  456. RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge buildModuleRegistry]", nil);
  457. __weak __typeof(self) weakSelf = self;
  458. ModuleRegistry::ModuleNotFoundCallback moduleNotFoundCallback = ^bool(const std::string &name) {
  459. __strong __typeof(weakSelf) strongSelf = weakSelf;
  460. return [strongSelf.delegate respondsToSelector:@selector(bridge:didNotFindModule:)] &&
  461. [strongSelf.delegate bridge:strongSelf didNotFindModule:@(name.c_str())];
  462. };
  463. auto registry = std::make_shared<ModuleRegistry>(
  464. createNativeModules(_moduleDataByID, self, _reactInstance), moduleNotFoundCallback);
  465. [_performanceLogger markStopForTag:RCTPLNativeModulePrepareConfig];
  466. RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
  467. return registry;
  468. }
  469. - (void)_initializeBridge:(std::shared_ptr<JSExecutorFactory>)executorFactory
  470. {
  471. if (!self.valid) {
  472. return;
  473. }
  474. __weak RCTCxxBridge *weakSelf = self;
  475. _jsMessageThread = std::make_shared<RCTMessageThread>([NSRunLoop currentRunLoop], ^(NSError *error) {
  476. if (error) {
  477. [weakSelf handleError:error];
  478. }
  479. });
  480. RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge initializeBridge:]", nil);
  481. // This can only be false if the bridge was invalidated before startup completed
  482. if (_reactInstance) {
  483. #if RCT_DEV
  484. executorFactory = std::make_shared<GetDescAdapter>(self, executorFactory);
  485. #endif
  486. [self _initializeBridgeLocked:executorFactory];
  487. #if RCT_PROFILE
  488. if (RCTProfileIsProfiling()) {
  489. _reactInstance->setGlobalVariable("__RCTProfileIsProfiling", std::make_unique<JSBigStdString>("true"));
  490. }
  491. #endif
  492. }
  493. RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
  494. }
  495. - (void)_initializeBridgeLocked:(std::shared_ptr<JSExecutorFactory>)executorFactory
  496. {
  497. std::lock_guard<std::mutex> guard(_moduleRegistryLock);
  498. // This is async, but any calls into JS are blocked by the m_syncReady CV in Instance
  499. _reactInstance->initializeBridge(
  500. std::make_unique<RCTInstanceCallback>(self),
  501. executorFactory,
  502. _jsMessageThread,
  503. [self _buildModuleRegistryUnlocked]);
  504. _moduleRegistryCreated = YES;
  505. }
  506. - (void)updateModuleWithInstance:(id<RCTBridgeModule>)instance
  507. {
  508. NSString *const moduleName = RCTBridgeModuleNameForClass([instance class]);
  509. if (moduleName) {
  510. RCTModuleData *const moduleData = _moduleDataByName[moduleName];
  511. if (moduleData) {
  512. moduleData.instance = instance;
  513. }
  514. }
  515. }
  516. - (NSArray<RCTModuleData *> *)registerModulesForClasses:(NSArray<Class> *)moduleClasses
  517. {
  518. return [self _registerModulesForClasses:moduleClasses lazilyDiscovered:NO];
  519. }
  520. - (NSArray<RCTModuleData *> *)_registerModulesForClasses:(NSArray<Class> *)moduleClasses
  521. lazilyDiscovered:(BOOL)lazilyDiscovered
  522. {
  523. RCT_PROFILE_BEGIN_EVENT(
  524. RCTProfileTagAlways, @"-[RCTCxxBridge initModulesWithDispatchGroup:] autoexported moduleData", nil);
  525. NSArray *moduleClassesCopy = [moduleClasses copy];
  526. NSMutableArray<RCTModuleData *> *moduleDataByID = [NSMutableArray arrayWithCapacity:moduleClassesCopy.count];
  527. for (Class moduleClass in moduleClassesCopy) {
  528. if (RCTTurboModuleEnabled() && [moduleClass conformsToProtocol:@protocol(RCTTurboModule)]) {
  529. continue;
  530. }
  531. NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
  532. // Check for module name collisions
  533. RCTModuleData *moduleData = _moduleDataByName[moduleName];
  534. if (moduleData) {
  535. if (moduleData.hasInstance || lazilyDiscovered) {
  536. // Existing module was preregistered, so it takes precedence
  537. continue;
  538. } else if ([moduleClass new] == nil) {
  539. // The new module returned nil from init, so use the old module
  540. continue;
  541. } else if ([moduleData.moduleClass new] != nil) {
  542. // Both modules were non-nil, so it's unclear which should take precedence
  543. RCTLogWarn(
  544. @"Attempted to register RCTBridgeModule class %@ for the "
  545. "name '%@', but name was already registered by class %@",
  546. moduleClass,
  547. moduleName,
  548. moduleData.moduleClass);
  549. }
  550. }
  551. // Instantiate moduleData
  552. // TODO #13258411: can we defer this until config generation?
  553. moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass bridge:self];
  554. _moduleDataByName[moduleName] = moduleData;
  555. [_moduleClassesByID addObject:moduleClass];
  556. [moduleDataByID addObject:moduleData];
  557. }
  558. [_moduleDataByID addObjectsFromArray:moduleDataByID];
  559. RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
  560. return moduleDataByID;
  561. }
  562. - (void)registerExtraModules
  563. {
  564. RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge initModulesWithDispatchGroup:] extraModules", nil);
  565. NSArray<id<RCTBridgeModule>> *extraModules = nil;
  566. if ([self.delegate respondsToSelector:@selector(extraModulesForBridge:)]) {
  567. extraModules = [self.delegate extraModulesForBridge:_parentBridge];
  568. } else if (self.moduleProvider) {
  569. extraModules = self.moduleProvider();
  570. }
  571. RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
  572. RCT_PROFILE_BEGIN_EVENT(
  573. RCTProfileTagAlways, @"-[RCTCxxBridge initModulesWithDispatchGroup:] preinitialized moduleData", nil);
  574. // Set up moduleData for pre-initialized module instances
  575. for (id<RCTBridgeModule> module in extraModules) {
  576. Class moduleClass = [module class];
  577. NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
  578. if (RCT_DEBUG) {
  579. // Check for name collisions between preregistered modules
  580. RCTModuleData *moduleData = _moduleDataByName[moduleName];
  581. if (moduleData) {
  582. RCTLogError(
  583. @"Attempted to register RCTBridgeModule class %@ for the "
  584. "name '%@', but name was already registered by class %@",
  585. moduleClass,
  586. moduleName,
  587. moduleData.moduleClass);
  588. continue;
  589. }
  590. }
  591. if (RCTTurboModuleEnabled() && [module conformsToProtocol:@protocol(RCTTurboModule)]) {
  592. #if RCT_DEBUG
  593. // TODO: don't ask for extra module for when TurboModule is enabled.
  594. RCTLogError(
  595. @"NativeModule '%@' was marked as TurboModule, but provided as an extra NativeModule "
  596. "by the class '%@', ignoring.",
  597. moduleName,
  598. moduleClass);
  599. #endif
  600. continue;
  601. }
  602. // Instantiate moduleData container
  603. RCTModuleData *moduleData = [[RCTModuleData alloc] initWithModuleInstance:module bridge:self];
  604. _moduleDataByName[moduleName] = moduleData;
  605. [_moduleClassesByID addObject:moduleClass];
  606. [_moduleDataByID addObject:moduleData];
  607. }
  608. RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
  609. }
  610. - (void)registerExtraLazyModules
  611. {
  612. #if RCT_DEBUG
  613. // This is debug-only and only when Chrome is attached, since it expects all modules to be already
  614. // available on start up. Otherwise, we can let the lazy module discovery to load them on demand.
  615. Class executorClass = [_parentBridge executorClass];
  616. if (executorClass && [NSStringFromClass(executorClass) isEqualToString:@"RCTWebSocketExecutor"]) {
  617. NSDictionary<NSString *, Class> *moduleClasses = nil;
  618. if ([self.delegate respondsToSelector:@selector(extraLazyModuleClassesForBridge:)]) {
  619. moduleClasses = [self.delegate extraLazyModuleClassesForBridge:_parentBridge];
  620. }
  621. if (!moduleClasses) {
  622. return;
  623. }
  624. // This logic is mostly copied from `registerModulesForClasses:`, but with one difference:
  625. // we must use the names provided by the delegate method here.
  626. for (NSString *moduleName in moduleClasses) {
  627. Class moduleClass = moduleClasses[moduleName];
  628. if (RCTTurboModuleEnabled() && [moduleClass conformsToProtocol:@protocol(RCTTurboModule)]) {
  629. continue;
  630. }
  631. // Check for module name collisions
  632. RCTModuleData *moduleData = _moduleDataByName[moduleName];
  633. if (moduleData) {
  634. if (moduleData.hasInstance) {
  635. // Existing module was preregistered, so it takes precedence
  636. continue;
  637. } else if ([moduleClass new] == nil) {
  638. // The new module returned nil from init, so use the old module
  639. continue;
  640. } else if ([moduleData.moduleClass new] != nil) {
  641. // Use existing module since it was already loaded but not yet instantiated.
  642. continue;
  643. }
  644. }
  645. moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass bridge:self];
  646. _moduleDataByName[moduleName] = moduleData;
  647. [_moduleClassesByID addObject:moduleClass];
  648. [_moduleDataByID addObject:moduleData];
  649. }
  650. }
  651. #endif
  652. }
  653. - (NSArray<RCTModuleData *> *)_initializeModules:(NSArray<Class> *)modules
  654. withDispatchGroup:(dispatch_group_t)dispatchGroup
  655. lazilyDiscovered:(BOOL)lazilyDiscovered
  656. {
  657. // Set up moduleData for automatically-exported modules
  658. NSArray<RCTModuleData *> *moduleDataById = [self _registerModulesForClasses:modules
  659. lazilyDiscovered:lazilyDiscovered];
  660. if (lazilyDiscovered) {
  661. #if RCT_DEBUG
  662. // Lazily discovered modules do not require instantiation here,
  663. // as they are not allowed to have pre-instantiated instance
  664. // and must not require the main queue.
  665. for (RCTModuleData *moduleData in moduleDataById) {
  666. RCTAssert(
  667. !(moduleData.requiresMainQueueSetup || moduleData.hasInstance),
  668. @"Module \'%@\' requires initialization on the Main Queue or has pre-instantiated, which is not supported for the lazily discovered modules.",
  669. moduleData.name);
  670. }
  671. #endif
  672. } else {
  673. RCT_PROFILE_BEGIN_EVENT(
  674. RCTProfileTagAlways, @"-[RCTCxxBridge initModulesWithDispatchGroup:] moduleData.hasInstance", nil);
  675. // Dispatch module init onto main thread for those modules that require it
  676. // For non-lazily discovered modules we run through the entire set of modules
  677. // that we have, otherwise some modules coming from the delegate
  678. // or module provider block, will not be properly instantiated.
  679. for (RCTModuleData *moduleData in _moduleDataByID) {
  680. if (moduleData.hasInstance && (!moduleData.requiresMainQueueSetup || RCTIsMainQueue())) {
  681. // Modules that were pre-initialized should ideally be set up before
  682. // bridge init has finished, otherwise the caller may try to access the
  683. // module directly rather than via `[bridge moduleForClass:]`, which won't
  684. // trigger the lazy initialization process. If the module cannot safely be
  685. // set up on the current thread, it will instead be async dispatched
  686. // to the main thread to be set up in _prepareModulesWithDispatchGroup:.
  687. (void)[moduleData instance];
  688. }
  689. }
  690. RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
  691. // From this point on, RCTDidInitializeModuleNotification notifications will
  692. // be sent the first time a module is accessed.
  693. _moduleSetupComplete = YES;
  694. [self _prepareModulesWithDispatchGroup:dispatchGroup];
  695. }
  696. #if RCT_PROFILE
  697. if (RCTProfileIsProfiling()) {
  698. // Depends on moduleDataByID being loaded
  699. RCTProfileHookModules(self);
  700. }
  701. #endif
  702. return moduleDataById;
  703. }
  704. - (void)registerAdditionalModuleClasses:(NSArray<Class> *)modules
  705. {
  706. std::lock_guard<std::mutex> guard(_moduleRegistryLock);
  707. if (_moduleRegistryCreated) {
  708. NSArray<RCTModuleData *> *newModules = [self _initializeModules:modules
  709. withDispatchGroup:NULL
  710. lazilyDiscovered:YES];
  711. assert(_reactInstance); // at this point you must have reactInstance as you already called
  712. // reactInstance->initialzeBridge
  713. _reactInstance->getModuleRegistry().registerModules(createNativeModules(newModules, self, _reactInstance));
  714. } else {
  715. [self registerModulesForClasses:modules];
  716. }
  717. }
  718. - (void)_prepareModulesWithDispatchGroup:(dispatch_group_t)dispatchGroup
  719. {
  720. RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTCxxBridge _prepareModulesWithDispatchGroup]", nil);
  721. BOOL initializeImmediately = NO;
  722. if (dispatchGroup == NULL) {
  723. // If no dispatchGroup is passed in, we must prepare everything immediately.
  724. // We better be on the right thread too.
  725. RCTAssertMainQueue();
  726. initializeImmediately = YES;
  727. }
  728. // Set up modules that require main thread init or constants export
  729. [_performanceLogger setValue:0 forTag:RCTPLNativeModuleMainThread];
  730. for (RCTModuleData *moduleData in _moduleDataByID) {
  731. if (moduleData.requiresMainQueueSetup) {
  732. // Modules that need to be set up on the main thread cannot be initialized
  733. // lazily when required without doing a dispatch_sync to the main thread,
  734. // which can result in deadlock. To avoid this, we initialize all of these
  735. // modules on the main thread in parallel with loading the JS code, so
  736. // they will already be available before they are ever required.
  737. dispatch_block_t block = ^{
  738. if (self.valid && ![moduleData.moduleClass isSubclassOfClass:[RCTCxxModule class]]) {
  739. [self->_performanceLogger appendStartForTag:RCTPLNativeModuleMainThread];
  740. (void)[moduleData instance];
  741. [moduleData gatherConstants];
  742. [self->_performanceLogger appendStopForTag:RCTPLNativeModuleMainThread];
  743. }
  744. };
  745. if (initializeImmediately && RCTIsMainQueue()) {
  746. block();
  747. } else {
  748. // We've already checked that dispatchGroup is non-null, but this satisfies the
  749. // Xcode analyzer
  750. if (dispatchGroup) {
  751. dispatch_group_async(dispatchGroup, dispatch_get_main_queue(), block);
  752. }
  753. }
  754. _modulesInitializedOnMainQueue++;
  755. }
  756. }
  757. [_performanceLogger setValue:_modulesInitializedOnMainQueue forTag:RCTPLNativeModuleMainThreadUsesCount];
  758. RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
  759. }
  760. - (void)registerModuleForFrameUpdates:(id<RCTBridgeModule>)module withModuleData:(RCTModuleData *)moduleData
  761. {
  762. [_displayLink registerModuleForFrameUpdates:module withModuleData:moduleData];
  763. }
  764. - (void)executeSourceCode:(NSData *)sourceCode sync:(BOOL)sync
  765. {
  766. // This will get called from whatever thread was actually executing JS.
  767. dispatch_block_t completion = ^{
  768. // Log start up metrics early before processing any other js calls
  769. [self logStartupFinish];
  770. // Flush pending calls immediately so we preserve ordering
  771. [self _flushPendingCalls];
  772. // Perform the state update and notification on the main thread, so we can't run into
  773. // timing issues with RCTRootView
  774. dispatch_async(dispatch_get_main_queue(), ^{
  775. [[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidLoadNotification
  776. object:self->_parentBridge
  777. userInfo:@{@"bridge" : self}];
  778. // Starting the display link is not critical to startup, so do it last
  779. [self ensureOnJavaScriptThread:^{
  780. // Register the display link to start sending js calls after everything is setup
  781. [self->_displayLink addToRunLoop:[NSRunLoop currentRunLoop]];
  782. }];
  783. });
  784. };
  785. if (sync) {
  786. [self executeApplicationScriptSync:sourceCode url:self.bundleURL];
  787. completion();
  788. } else {
  789. [self enqueueApplicationScript:sourceCode url:self.bundleURL onComplete:completion];
  790. }
  791. [self.devSettings setupHotModuleReloadClientIfApplicableForURL:self.bundleURL];
  792. }
  793. - (void)handleError:(NSError *)error
  794. {
  795. // This is generally called when the infrastructure throws an
  796. // exception while calling JS. Most product exceptions will not go
  797. // through this method, but through RCTExceptionManager.
  798. // There are three possible states:
  799. // 1. initializing == _valid && _loading
  800. // 2. initializing/loading finished (success or failure) == _valid && !_loading
  801. // 3. invalidated == !_valid && !_loading
  802. // !_valid && _loading can't happen.
  803. // In state 1: on main queue, move to state 2, reset the bridge, and RCTFatal.
  804. // In state 2: go directly to RCTFatal. Do not enqueue, do not collect $200.
  805. // In state 3: do nothing.
  806. if (self->_valid && !self->_loading) {
  807. if ([error userInfo][RCTJSRawStackTraceKey]) {
  808. [self.redBox showErrorMessage:[error localizedDescription] withRawStack:[error userInfo][RCTJSRawStackTraceKey]];
  809. }
  810. RCTFatal(error);
  811. // RN will stop, but let the rest of the app keep going.
  812. return;
  813. }
  814. if (!_valid || !_loading) {
  815. return;
  816. }
  817. // Hack: once the bridge is invalidated below, it won't initialize any new native
  818. // modules. Initialize the redbox module now so we can still report this error.
  819. RCTRedBox *redBox = [self redBox];
  820. _loading = NO;
  821. _valid = NO;
  822. _moduleRegistryCreated = NO;
  823. dispatch_async(dispatch_get_main_queue(), ^{
  824. if (self->_jsMessageThread) {
  825. // Make sure initializeBridge completed
  826. self->_jsMessageThread->runOnQueueSync([] {});
  827. }
  828. self->_reactInstance.reset();
  829. self->_jsMessageThread.reset();
  830. [[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidFailToLoadNotification
  831. object:self->_parentBridge
  832. userInfo:@{@"bridge" : self, @"error" : error}];
  833. if ([error userInfo][RCTJSRawStackTraceKey]) {
  834. [redBox showErrorMessage:[error localizedDescription] withRawStack:[error userInfo][RCTJSRawStackTraceKey]];
  835. }
  836. RCTFatal(error);
  837. });
  838. }
  839. RCT_NOT_IMPLEMENTED(-(instancetype)initWithDelegate
  840. : (__unused id<RCTBridgeDelegate>)delegate bundleURL
  841. : (__unused NSURL *)bundleURL moduleProvider
  842. : (__unused RCTBridgeModuleListProvider)block launchOptions
  843. : (__unused NSDictionary *)launchOptions)
  844. RCT_NOT_IMPLEMENTED(-(instancetype)initWithBundleURL
  845. : (__unused NSURL *)bundleURL moduleProvider
  846. : (__unused RCTBridgeModuleListProvider)block launchOptions
  847. : (__unused NSDictionary *)launchOptions)
  848. /**
  849. * Prevent super from calling setUp (that'd create another batchedBridge)
  850. */
  851. - (void)setUp
  852. {
  853. }
  854. - (void)reload
  855. {
  856. if (!_valid) {
  857. RCTLogWarn(
  858. @"Attempting to reload bridge before it's valid: %@. Try restarting the development server if connected.",
  859. self);
  860. }
  861. RCTTriggerReloadCommandListeners(@"Unknown from cxx bridge");
  862. }
  863. - (void)reloadWithReason:(NSString *)reason
  864. {
  865. if (!_valid) {
  866. RCTLogWarn(
  867. @"Attempting to reload bridge before it's valid: %@. Try restarting the development server if connected.",
  868. self);
  869. }
  870. RCTTriggerReloadCommandListeners(reason);
  871. }
  872. - (Class)executorClass
  873. {
  874. return _parentBridge.executorClass;
  875. }
  876. - (void)setExecutorClass:(Class)executorClass
  877. {
  878. RCTAssertMainQueue();
  879. _parentBridge.executorClass = executorClass;
  880. }
  881. - (NSURL *)bundleURL
  882. {
  883. return _parentBridge.bundleURL;
  884. }
  885. - (void)setBundleURL:(NSURL *)bundleURL
  886. {
  887. _parentBridge.bundleURL = bundleURL;
  888. }
  889. - (id<RCTBridgeDelegate>)delegate
  890. {
  891. return _parentBridge.delegate;
  892. }
  893. - (void)dispatchBlock:(dispatch_block_t)block queue:(dispatch_queue_t)queue
  894. {
  895. if (queue == RCTJSThread) {
  896. [self ensureOnJavaScriptThread:block];
  897. } else if (queue) {
  898. dispatch_async(queue, block);
  899. }
  900. }
  901. #pragma mark - RCTInvalidating
  902. - (void)invalidate
  903. {
  904. if (_didInvalidate) {
  905. return;
  906. }
  907. RCTAssertMainQueue();
  908. RCTLogInfo(@"Invalidating %@ (parent: %@, executor: %@)", self, _parentBridge, [self executorClass]);
  909. _loading = NO;
  910. _valid = NO;
  911. _didInvalidate = YES;
  912. _moduleRegistryCreated = NO;
  913. if ([RCTBridge currentBridge] == self) {
  914. [RCTBridge setCurrentBridge:nil];
  915. }
  916. // Stop JS instance and message thread
  917. [self ensureOnJavaScriptThread:^{
  918. [self->_displayLink invalidate];
  919. self->_displayLink = nil;
  920. if (RCTProfileIsProfiling()) {
  921. RCTProfileUnhookModules(self);
  922. }
  923. // Invalidate modules
  924. [[NSNotificationCenter defaultCenter] postNotificationName:RCTBridgeWillInvalidateModulesNotification
  925. object:self->_parentBridge
  926. userInfo:@{@"bridge" : self}];
  927. // We're on the JS thread (which we'll be suspending soon), so no new calls will be made to native modules after
  928. // this completes. We must ensure all previous calls were dispatched before deallocating the instance (and module
  929. // wrappers) or we may have invalid pointers still in flight.
  930. dispatch_group_t moduleInvalidation = dispatch_group_create();
  931. for (RCTModuleData *moduleData in self->_moduleDataByID) {
  932. // Be careful when grabbing an instance here, we don't want to instantiate
  933. // any modules just to invalidate them.
  934. if (![moduleData hasInstance]) {
  935. continue;
  936. }
  937. if ([moduleData.instance respondsToSelector:@selector(invalidate)]) {
  938. dispatch_group_enter(moduleInvalidation);
  939. [self
  940. dispatchBlock:^{
  941. [(id<RCTInvalidating>)moduleData.instance invalidate];
  942. dispatch_group_leave(moduleInvalidation);
  943. }
  944. queue:moduleData.methodQueue];
  945. }
  946. [moduleData invalidate];
  947. }
  948. if (dispatch_group_wait(moduleInvalidation, dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC))) {
  949. RCTLogError(@"Timed out waiting for modules to be invalidated");
  950. }
  951. [[NSNotificationCenter defaultCenter] postNotificationName:RCTBridgeDidInvalidateModulesNotification
  952. object:self->_parentBridge
  953. userInfo:@{@"bridge" : self}];
  954. self->_reactInstance.reset();
  955. self->_jsMessageThread.reset();
  956. self->_moduleDataByName = nil;
  957. self->_moduleDataByID = nil;
  958. self->_moduleClassesByID = nil;
  959. self->_pendingCalls = nil;
  960. [self->_jsThread cancel];
  961. self->_jsThread = nil;
  962. CFRunLoopStop(CFRunLoopGetCurrent());
  963. }];
  964. }
  965. - (void)logMessage:(NSString *)message level:(NSString *)level
  966. {
  967. if (RCT_DEBUG && _valid) {
  968. [self enqueueJSCall:@"RCTLog" method:@"logIfNoNativeHook" args:@[ level, message ] completion:NULL];
  969. }
  970. }
  971. #pragma mark - RCTBridge methods
  972. - (void)_runAfterLoad:(RCTPendingCall)block
  973. {
  974. // Ordering here is tricky. Ideally, the C++ bridge would provide
  975. // functionality to defer calls until after the app is loaded. Until that
  976. // happens, we do this. _pendingCount keeps a count of blocks which have
  977. // been deferred. It is incremented using an atomic barrier call before each
  978. // block is added to the js queue, and decremented using an atomic barrier
  979. // call after the block is executed. If _pendingCount is zero, there is no
  980. // work either in the js queue, or in _pendingCalls, so it is safe to add new
  981. // work to the JS queue directly.
  982. if (self.loading || _pendingCount > 0) {
  983. // From the callers' perspective:
  984. // Phase 1: jsQueueBlocks are added to the queue; _pendingCount is
  985. // incremented for each. If the first block is created after self.loading is
  986. // true, phase 1 will be nothing.
  987. _pendingCount++;
  988. dispatch_block_t jsQueueBlock = ^{
  989. // From the perspective of the JS queue:
  990. if (self.loading) {
  991. // Phase A: jsQueueBlocks are executed. self.loading is true, so they
  992. // are added to _pendingCalls.
  993. [self->_pendingCalls addObject:block];
  994. } else {
  995. // Phase C: More jsQueueBlocks are executed. self.loading is false, so
  996. // each block is executed, adding work to the queue, and _pendingCount is
  997. // decremented.
  998. block();
  999. self->_pendingCount--;
  1000. }
  1001. };
  1002. [self ensureOnJavaScriptThread:jsQueueBlock];
  1003. } else {
  1004. // Phase 2/Phase D: blocks are executed directly, adding work to the JS queue.
  1005. block();
  1006. }
  1007. }
  1008. - (void)logStartupFinish
  1009. {
  1010. // Log metrics about native requires during the bridge startup.
  1011. uint64_t nativeRequiresCount = [_performanceLogger valueForTag:RCTPLRAMNativeRequiresCount];
  1012. [_performanceLogger setValue:nativeRequiresCount forTag:RCTPLRAMStartupNativeRequiresCount];
  1013. uint64_t nativeRequires = [_performanceLogger valueForTag:RCTPLRAMNativeRequires];
  1014. [_performanceLogger setValue:nativeRequires forTag:RCTPLRAMStartupNativeRequires];
  1015. [_performanceLogger markStopForTag:RCTPLBridgeStartup];
  1016. }
  1017. - (void)_flushPendingCalls
  1018. {
  1019. RCT_PROFILE_BEGIN_EVENT(0, @"Processing pendingCalls", @{@"count" : [@(_pendingCalls.count) stringValue]});
  1020. // Phase B: _flushPendingCalls happens. Each block in _pendingCalls is
  1021. // executed, adding work to the queue, and _pendingCount is decremented.
  1022. // loading is set to NO.
  1023. NSArray<RCTPendingCall> *pendingCalls = _pendingCalls;
  1024. _pendingCalls = nil;
  1025. for (RCTPendingCall call in pendingCalls) {
  1026. call();
  1027. _pendingCount--;
  1028. }
  1029. _loading = NO;
  1030. RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
  1031. }
  1032. /**
  1033. * Public. Can be invoked from any thread.
  1034. */
  1035. - (void)enqueueJSCall:(NSString *)module
  1036. method:(NSString *)method
  1037. args:(NSArray *)args
  1038. completion:(dispatch_block_t)completion
  1039. {
  1040. if (!self.valid) {
  1041. return;
  1042. }
  1043. /**
  1044. * AnyThread
  1045. */
  1046. RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge enqueueJSCall:]", nil);
  1047. RCTProfileBeginFlowEvent();
  1048. __weak __typeof(self) weakSelf = self;
  1049. [self _runAfterLoad:^() {
  1050. RCTProfileEndFlowEvent();
  1051. __strong __typeof(weakSelf) strongSelf = weakSelf;
  1052. if (!strongSelf) {
  1053. return;
  1054. }
  1055. if (strongSelf->_reactInstance) {
  1056. strongSelf->_reactInstance->callJSFunction(
  1057. [module UTF8String], [method UTF8String], convertIdToFollyDynamic(args ?: @[]));
  1058. // ensureOnJavaScriptThread may execute immediately, so use jsMessageThread, to make sure
  1059. // the block is invoked after callJSFunction
  1060. if (completion) {
  1061. if (strongSelf->_jsMessageThread) {
  1062. strongSelf->_jsMessageThread->runOnQueue(completion);
  1063. } else {
  1064. RCTLogWarn(@"Can't invoke completion without messageThread");
  1065. }
  1066. }
  1067. }
  1068. }];
  1069. RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
  1070. }
  1071. /**
  1072. * Called by RCTModuleMethod from any thread.
  1073. */
  1074. - (void)enqueueCallback:(NSNumber *)cbID args:(NSArray *)args
  1075. {
  1076. if (!self.valid) {
  1077. return;
  1078. }
  1079. /**
  1080. * AnyThread
  1081. */
  1082. RCTProfileBeginFlowEvent();
  1083. __weak __typeof(self) weakSelf = self;
  1084. [self _runAfterLoad:^() {
  1085. RCTProfileEndFlowEvent();
  1086. __strong __typeof(weakSelf) strongSelf = weakSelf;
  1087. if (!strongSelf) {
  1088. return;
  1089. }
  1090. if (strongSelf->_reactInstance) {
  1091. strongSelf->_reactInstance->callJSCallback([cbID unsignedLongLongValue], convertIdToFollyDynamic(args ?: @[]));
  1092. }
  1093. }];
  1094. }
  1095. /**
  1096. * Private hack to support `setTimeout(fn, 0)`
  1097. */
  1098. - (void)_immediatelyCallTimer:(NSNumber *)timer
  1099. {
  1100. if (_reactInstance) {
  1101. _reactInstance->callJSFunction(
  1102. "JSTimers", "callTimers", folly::dynamic::array(folly::dynamic::array([timer doubleValue])));
  1103. }
  1104. }
  1105. - (void)enqueueApplicationScript:(NSData *)script url:(NSURL *)url onComplete:(dispatch_block_t)onComplete
  1106. {
  1107. RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge enqueueApplicationScript]", nil);
  1108. [self executeApplicationScript:script url:url async:YES];
  1109. RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
  1110. // Assumes that onComplete can be called when the next block on the JS thread is scheduled
  1111. if (onComplete) {
  1112. RCTAssert(_jsMessageThread != nullptr, @"Cannot invoke completion without jsMessageThread");
  1113. _jsMessageThread->runOnQueue(onComplete);
  1114. }
  1115. }
  1116. - (void)executeApplicationScriptSync:(NSData *)script url:(NSURL *)url
  1117. {
  1118. [self executeApplicationScript:script url:url async:NO];
  1119. }
  1120. - (void)executeApplicationScript:(NSData *)script url:(NSURL *)url async:(BOOL)async
  1121. {
  1122. [self _tryAndHandleError:^{
  1123. NSString *sourceUrlStr = deriveSourceURL(url);
  1124. [[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptWillStartExecutingNotification
  1125. object:self->_parentBridge
  1126. userInfo:@{@"bridge" : self}];
  1127. // hold a local reference to reactInstance in case a parallel thread
  1128. // resets it between null check and usage
  1129. auto reactInstance = self->_reactInstance;
  1130. if (isRAMBundle(script)) {
  1131. [self->_performanceLogger markStartForTag:RCTPLRAMBundleLoad];
  1132. auto ramBundle = std::make_unique<JSIndexedRAMBundle>(sourceUrlStr.UTF8String);
  1133. std::unique_ptr<const JSBigString> scriptStr = ramBundle->getStartupCode();
  1134. [self->_performanceLogger markStopForTag:RCTPLRAMBundleLoad];
  1135. [self->_performanceLogger setValue:scriptStr->size() forTag:RCTPLRAMStartupCodeSize];
  1136. if (reactInstance) {
  1137. auto registry =
  1138. RAMBundleRegistry::multipleBundlesRegistry(std::move(ramBundle), JSIndexedRAMBundle::buildFactory());
  1139. reactInstance->loadRAMBundle(std::move(registry), std::move(scriptStr), sourceUrlStr.UTF8String, !async);
  1140. }
  1141. } else if (reactInstance) {
  1142. reactInstance->loadScriptFromString(std::make_unique<NSDataBigString>(script), sourceUrlStr.UTF8String, !async);
  1143. } else {
  1144. std::string methodName = async ? "loadBundle" : "loadBundleSync";
  1145. throw std::logic_error("Attempt to call " + methodName + ": on uninitialized bridge");
  1146. }
  1147. }];
  1148. }
  1149. - (void)registerSegmentWithId:(NSUInteger)segmentId path:(NSString *)path
  1150. {
  1151. if (_reactInstance) {
  1152. _reactInstance->registerBundle(static_cast<uint32_t>(segmentId), path.UTF8String);
  1153. }
  1154. }
  1155. #pragma mark - Payload Processing
  1156. - (void)partialBatchDidFlush
  1157. {
  1158. for (RCTModuleData *moduleData in _moduleDataByID) {
  1159. if (moduleData.implementsPartialBatchDidFlush) {
  1160. [self
  1161. dispatchBlock:^{
  1162. [moduleData.instance partialBatchDidFlush];
  1163. }
  1164. queue:moduleData.methodQueue];
  1165. }
  1166. }
  1167. }
  1168. - (void)batchDidComplete
  1169. {
  1170. // TODO #12592471: batchDidComplete is only used by RCTUIManager,
  1171. // can we eliminate this special case?
  1172. for (RCTModuleData *moduleData in _moduleDataByID) {
  1173. if (moduleData.implementsBatchDidComplete) {
  1174. [self
  1175. dispatchBlock:^{
  1176. [moduleData.instance batchDidComplete];
  1177. }
  1178. queue:moduleData.methodQueue];
  1179. }
  1180. }
  1181. }
  1182. - (void)startProfiling
  1183. {
  1184. RCTAssertMainQueue();
  1185. [self ensureOnJavaScriptThread:^{
  1186. #if WITH_FBSYSTRACE
  1187. [RCTFBSystrace registerCallbacks];
  1188. #endif
  1189. RCTProfileInit(self);
  1190. [self enqueueJSCall:@"Systrace" method:@"setEnabled" args:@[ @YES ] completion:NULL];
  1191. }];
  1192. }
  1193. - (void)stopProfiling:(void (^)(NSData *))callback
  1194. {
  1195. RCTAssertMainQueue();
  1196. [self ensureOnJavaScriptThread:^{
  1197. [self enqueueJSCall:@"Systrace" method:@"setEnabled" args:@[ @NO ] completion:NULL];
  1198. RCTProfileEnd(self, ^(NSString *log) {
  1199. NSData *logData = [log dataUsingEncoding:NSUTF8StringEncoding];
  1200. callback(logData);
  1201. #if WITH_FBSYSTRACE
  1202. if (![RCTFBSystrace verifyTraceSize:logData.length]) {
  1203. RCTLogWarn(
  1204. @"Your FBSystrace trace might be truncated, try to bump up the buffer size"
  1205. " in RCTFBSystrace.m or capture a shorter trace");
  1206. }
  1207. [RCTFBSystrace unregisterCallbacks];
  1208. #endif
  1209. });
  1210. }];
  1211. }
  1212. - (BOOL)isBatchActive
  1213. {
  1214. return _reactInstance ? _reactInstance->isBatchActive() : NO;
  1215. }
  1216. - (void *)runtime
  1217. {
  1218. if (!_reactInstance) {
  1219. return nullptr;
  1220. }
  1221. return _reactInstance->getJavaScriptContext();
  1222. }
  1223. - (void)invokeAsync:(std::function<void()> &&)func
  1224. {
  1225. __block auto retainedFunc = std::move(func);
  1226. __weak __typeof(self) weakSelf = self;
  1227. [self _runAfterLoad:^{
  1228. __strong __typeof(self) strongSelf = weakSelf;
  1229. if (std::shared_ptr<CallInvoker> jsInvoker = strongSelf.jsCallInvoker) {
  1230. jsInvoker->invokeAsync(std::move(retainedFunc));
  1231. }
  1232. }];
  1233. }
  1234. #pragma mark - RCTBridge (RCTTurboModule)
  1235. - (std::shared_ptr<CallInvoker>)jsCallInvoker
  1236. {
  1237. return _reactInstance ? _reactInstance->getJSCallInvoker() : nullptr;
  1238. }
  1239. - (std::shared_ptr<CallInvoker>)decorateNativeCallInvoker:(std::shared_ptr<CallInvoker>)nativeInvoker
  1240. {
  1241. return _reactInstance ? _reactInstance->getDecoratedNativeCallInvoker(nativeInvoker) : nullptr;
  1242. }
  1243. @end