/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #pragma once #include #include #include #include #include #include #ifndef RN_EXPORT #define RN_EXPORT __attribute__((visibility("default"))) #endif namespace folly { struct dynamic; } namespace facebook { namespace react { class JSBigString; class JSExecutorFactory; class MessageQueueThread; class ModuleRegistry; class RAMBundleRegistry; struct InstanceCallback { virtual ~InstanceCallback() {} virtual void onBatchComplete() {} virtual void incrementPendingJSCalls() {} virtual void decrementPendingJSCalls() {} }; class RN_EXPORT Instance { public: ~Instance(); void initializeBridge( std::unique_ptr callback, std::shared_ptr jsef, std::shared_ptr jsQueue, std::shared_ptr moduleRegistry); void initializeRuntime(); void setSourceURL(std::string sourceURL); void loadScriptFromString( std::unique_ptr string, std::string sourceURL, bool loadSynchronously); void loadRAMBundleFromString( std::unique_ptr script, const std::string &sourceURL); void loadRAMBundleFromFile( const std::string &sourcePath, const std::string &sourceURL, bool loadSynchronously); void loadRAMBundle( std::unique_ptr bundleRegistry, std::unique_ptr startupScript, std::string startupScriptSourceURL, bool loadSynchronously); bool supportsProfiling(); void setGlobalVariable( std::string propName, std::unique_ptr jsonValue); void *getJavaScriptContext(); bool isInspectable(); bool isBatchActive(); void callJSFunction( std::string &&module, std::string &&method, folly::dynamic &¶ms); void callJSCallback(uint64_t callbackId, folly::dynamic &¶ms); // This method is experimental, and may be modified or removed. void registerBundle(uint32_t bundleId, const std::string &bundlePath); const ModuleRegistry &getModuleRegistry() const; ModuleRegistry &getModuleRegistry(); void handleMemoryPressure(int pressureLevel); /** * JS CallInvoker is used by TurboModules to schedule work on the JS thread. * * Why is the bridge creating JS CallInvoker? * * - After every Native -> JS call in the TurboModule system, the bridge * needs to flush all queued NativeModule method calls. The bridge must * also dispatch onBatchComplete if the queue of NativeModule method calls * was not empty. */ std::shared_ptr getJSCallInvoker(); /** * Native CallInvoker is used by TurboModules to schedule work on the * NativeModule thread(s). * * Why is the bridge decorating native CallInvoker? * * - The bridge must be informed of all TurboModule async method calls. Why? * When all queued NativeModule method calls are flushed by a call from * Native -> JS, if that queue was non-zero in size, JsToNativeBridge * dispatches onBatchComplete. When we turn our NativeModules to * TurboModules, there will be less and less pending NativeModule method * calls, so onBatchComplete will not fire as often. Therefore, the bridge * needs to know how many TurboModule async method calls have been completed * since the last time the bridge was flushed. If this number is non-zero, * we fire onBatchComplete. * * Why can't we just create and return a new native CallInvoker? * * - On Android, we have one NativeModule thread. That thread is created and * managed outside of NativeToJsBridge. On iOS, we have one MethodQueue per * module. Those MethodQueues are also created and managed outside of * NativeToJsBridge. Therefore, we need to pass in a CallInvoker that * schedules work on the respective thread. */ std::shared_ptr getDecoratedNativeCallInvoker( std::shared_ptr nativeInvoker); /** * RuntimeExecutor is used by Fabric to access the jsi::Runtime. */ RuntimeExecutor getRuntimeExecutor(); private: void callNativeModules(folly::dynamic &&calls, bool isEndOfBatch); void loadBundle( std::unique_ptr bundleRegistry, std::unique_ptr startupScript, std::string startupScriptSourceURL); void loadBundleSync( std::unique_ptr bundleRegistry, std::unique_ptr startupScript, std::string startupScriptSourceURL); std::shared_ptr callback_; std::shared_ptr nativeToJsBridge_; std::shared_ptr moduleRegistry_; std::mutex m_syncMutex; std::condition_variable m_syncCV; bool m_syncReady = false; class JSCallInvoker : public CallInvoker { private: std::weak_ptr m_nativeToJsBridge; std::mutex m_mutex; bool m_shouldBuffer = true; std::list> m_workBuffer; void scheduleAsync(std::function &&work); public: void setNativeToJsBridgeAndFlushCalls( std::weak_ptr nativeToJsBridge); void invokeAsync(std::function &&work) override; void invokeSync(std::function &&work) override; }; std::shared_ptr jsCallInvoker_ = std::make_shared(); }; } // namespace react } // namespace facebook