Instance.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  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 "Instance.h"
  8. #include "JSBigString.h"
  9. #include "JSBundleType.h"
  10. #include "JSExecutor.h"
  11. #include "MessageQueueThread.h"
  12. #include "MethodCall.h"
  13. #include "NativeToJsBridge.h"
  14. #include "RAMBundleRegistry.h"
  15. #include "RecoverableError.h"
  16. #include "SystraceSection.h"
  17. #include <cxxreact/JSIndexedRAMBundle.h>
  18. #include <folly/MoveWrapper.h>
  19. #include <folly/json.h>
  20. #include <glog/logging.h>
  21. #include <condition_variable>
  22. #include <exception>
  23. #include <fstream>
  24. #include <memory>
  25. #include <mutex>
  26. #include <string>
  27. namespace facebook {
  28. namespace react {
  29. Instance::~Instance() {
  30. if (nativeToJsBridge_) {
  31. nativeToJsBridge_->destroy();
  32. }
  33. }
  34. void Instance::initializeBridge(
  35. std::unique_ptr<InstanceCallback> callback,
  36. std::shared_ptr<JSExecutorFactory> jsef,
  37. std::shared_ptr<MessageQueueThread> jsQueue,
  38. std::shared_ptr<ModuleRegistry> moduleRegistry) {
  39. callback_ = std::move(callback);
  40. moduleRegistry_ = std::move(moduleRegistry);
  41. jsQueue->runOnQueueSync([this, &jsef, jsQueue]() mutable {
  42. nativeToJsBridge_ = std::make_shared<NativeToJsBridge>(
  43. jsef.get(), moduleRegistry_, jsQueue, callback_);
  44. nativeToJsBridge_->initializeRuntime();
  45. /**
  46. * After NativeToJsBridge is created, the jsi::Runtime should exist.
  47. * Also, the JS message queue thread exists. So, it's safe to
  48. * schedule all queued up js Calls.
  49. */
  50. jsCallInvoker_->setNativeToJsBridgeAndFlushCalls(nativeToJsBridge_);
  51. std::lock_guard<std::mutex> lock(m_syncMutex);
  52. m_syncReady = true;
  53. m_syncCV.notify_all();
  54. });
  55. CHECK(nativeToJsBridge_);
  56. }
  57. void Instance::loadBundle(
  58. std::unique_ptr<RAMBundleRegistry> bundleRegistry,
  59. std::unique_ptr<const JSBigString> string,
  60. std::string sourceURL) {
  61. callback_->incrementPendingJSCalls();
  62. SystraceSection s("Instance::loadBundle", "sourceURL", sourceURL);
  63. nativeToJsBridge_->loadBundle(
  64. std::move(bundleRegistry), std::move(string), std::move(sourceURL));
  65. }
  66. void Instance::loadBundleSync(
  67. std::unique_ptr<RAMBundleRegistry> bundleRegistry,
  68. std::unique_ptr<const JSBigString> string,
  69. std::string sourceURL) {
  70. std::unique_lock<std::mutex> lock(m_syncMutex);
  71. m_syncCV.wait(lock, [this] { return m_syncReady; });
  72. SystraceSection s("Instance::loadBundleSync", "sourceURL", sourceURL);
  73. nativeToJsBridge_->loadBundleSync(
  74. std::move(bundleRegistry), std::move(string), std::move(sourceURL));
  75. }
  76. void Instance::setSourceURL(std::string sourceURL) {
  77. callback_->incrementPendingJSCalls();
  78. SystraceSection s("Instance::setSourceURL", "sourceURL", sourceURL);
  79. nativeToJsBridge_->loadBundle(nullptr, nullptr, std::move(sourceURL));
  80. }
  81. void Instance::loadScriptFromString(
  82. std::unique_ptr<const JSBigString> string,
  83. std::string sourceURL,
  84. bool loadSynchronously) {
  85. SystraceSection s("Instance::loadScriptFromString", "sourceURL", sourceURL);
  86. if (loadSynchronously) {
  87. loadBundleSync(nullptr, std::move(string), std::move(sourceURL));
  88. } else {
  89. loadBundle(nullptr, std::move(string), std::move(sourceURL));
  90. }
  91. }
  92. bool Instance::isIndexedRAMBundle(const char *sourcePath) {
  93. std::ifstream bundle_stream(sourcePath, std::ios_base::in);
  94. BundleHeader header;
  95. if (!bundle_stream ||
  96. !bundle_stream.read(reinterpret_cast<char *>(&header), sizeof(header))) {
  97. return false;
  98. }
  99. return parseTypeFromHeader(header) == ScriptTag::RAMBundle;
  100. }
  101. bool Instance::isIndexedRAMBundle(std::unique_ptr<const JSBigString> *script) {
  102. BundleHeader header;
  103. strncpy(
  104. reinterpret_cast<char *>(&header),
  105. script->get()->c_str(),
  106. sizeof(header));
  107. return parseTypeFromHeader(header) == ScriptTag::RAMBundle;
  108. }
  109. void Instance::loadRAMBundleFromString(
  110. std::unique_ptr<const JSBigString> script,
  111. const std::string &sourceURL) {
  112. auto bundle = std::make_unique<JSIndexedRAMBundle>(std::move(script));
  113. auto startupScript = bundle->getStartupCode();
  114. auto registry = RAMBundleRegistry::singleBundleRegistry(std::move(bundle));
  115. loadRAMBundle(std::move(registry), std::move(startupScript), sourceURL, true);
  116. }
  117. void Instance::loadRAMBundleFromFile(
  118. const std::string &sourcePath,
  119. const std::string &sourceURL,
  120. bool loadSynchronously) {
  121. auto bundle = std::make_unique<JSIndexedRAMBundle>(sourcePath.c_str());
  122. auto startupScript = bundle->getStartupCode();
  123. auto registry = RAMBundleRegistry::multipleBundlesRegistry(
  124. std::move(bundle), JSIndexedRAMBundle::buildFactory());
  125. loadRAMBundle(
  126. std::move(registry),
  127. std::move(startupScript),
  128. sourceURL,
  129. loadSynchronously);
  130. }
  131. void Instance::loadRAMBundle(
  132. std::unique_ptr<RAMBundleRegistry> bundleRegistry,
  133. std::unique_ptr<const JSBigString> startupScript,
  134. std::string startupScriptSourceURL,
  135. bool loadSynchronously) {
  136. if (loadSynchronously) {
  137. loadBundleSync(
  138. std::move(bundleRegistry),
  139. std::move(startupScript),
  140. std::move(startupScriptSourceURL));
  141. } else {
  142. loadBundle(
  143. std::move(bundleRegistry),
  144. std::move(startupScript),
  145. std::move(startupScriptSourceURL));
  146. }
  147. }
  148. void Instance::setGlobalVariable(
  149. std::string propName,
  150. std::unique_ptr<const JSBigString> jsonValue) {
  151. nativeToJsBridge_->setGlobalVariable(
  152. std::move(propName), std::move(jsonValue));
  153. }
  154. void *Instance::getJavaScriptContext() {
  155. return nativeToJsBridge_ ? nativeToJsBridge_->getJavaScriptContext()
  156. : nullptr;
  157. }
  158. bool Instance::isInspectable() {
  159. return nativeToJsBridge_ ? nativeToJsBridge_->isInspectable() : false;
  160. }
  161. bool Instance::isBatchActive() {
  162. return nativeToJsBridge_ ? nativeToJsBridge_->isBatchActive() : false;
  163. }
  164. void Instance::callJSFunction(
  165. std::string &&module,
  166. std::string &&method,
  167. folly::dynamic &&params) {
  168. callback_->incrementPendingJSCalls();
  169. nativeToJsBridge_->callFunction(
  170. std::move(module), std::move(method), std::move(params));
  171. }
  172. void Instance::callJSCallback(uint64_t callbackId, folly::dynamic &&params) {
  173. SystraceSection s("Instance::callJSCallback");
  174. callback_->incrementPendingJSCalls();
  175. nativeToJsBridge_->invokeCallback((double)callbackId, std::move(params));
  176. }
  177. void Instance::registerBundle(
  178. uint32_t bundleId,
  179. const std::string &bundlePath) {
  180. nativeToJsBridge_->registerBundle(bundleId, bundlePath);
  181. }
  182. const ModuleRegistry &Instance::getModuleRegistry() const {
  183. return *moduleRegistry_;
  184. }
  185. ModuleRegistry &Instance::getModuleRegistry() {
  186. return *moduleRegistry_;
  187. }
  188. void Instance::handleMemoryPressure(int pressureLevel) {
  189. nativeToJsBridge_->handleMemoryPressure(pressureLevel);
  190. }
  191. std::shared_ptr<CallInvoker> Instance::getJSCallInvoker() {
  192. return std::static_pointer_cast<CallInvoker>(jsCallInvoker_);
  193. }
  194. std::shared_ptr<CallInvoker> Instance::getDecoratedNativeCallInvoker(
  195. std::shared_ptr<CallInvoker> nativeInvoker) {
  196. return nativeToJsBridge_->getDecoratedNativeCallInvoker(nativeInvoker);
  197. }
  198. void Instance::JSCallInvoker::setNativeToJsBridgeAndFlushCalls(
  199. std::weak_ptr<NativeToJsBridge> nativeToJsBridge) {
  200. std::lock_guard<std::mutex> guard(m_mutex);
  201. m_shouldBuffer = false;
  202. m_nativeToJsBridge = nativeToJsBridge;
  203. while (m_workBuffer.size() > 0) {
  204. scheduleAsync(std::move(m_workBuffer.front()));
  205. m_workBuffer.pop_front();
  206. }
  207. }
  208. void Instance::JSCallInvoker::invokeSync(std::function<void()> &&work) {
  209. // TODO: Replace JS Callinvoker with RuntimeExecutor.
  210. throw std::runtime_error(
  211. "Synchronous native -> JS calls are currently not supported.");
  212. }
  213. void Instance::JSCallInvoker::invokeAsync(std::function<void()> &&work) {
  214. std::lock_guard<std::mutex> guard(m_mutex);
  215. /**
  216. * Why is is necessary to queue up async work?
  217. *
  218. * 1. TurboModuleManager must be created synchronously after the Instance,
  219. * before we load the source code. This is when the NativeModule system
  220. * is initialized. RCTDevLoadingView shows bundle download progress.
  221. * 2. TurboModuleManager requires a JS CallInvoker.
  222. * 3. The JS CallInvoker requires the NativeToJsBridge, which is created on
  223. * the JS thread in Instance::initializeBridge.
  224. *
  225. * Therefore, although we don't call invokeAsync before the JS bundle is
  226. * executed, this buffering is implemented anyways to ensure that work
  227. * isn't discarded.
  228. */
  229. if (m_shouldBuffer) {
  230. m_workBuffer.push_back(std::move(work));
  231. return;
  232. }
  233. scheduleAsync(std::move(work));
  234. }
  235. void Instance::JSCallInvoker::scheduleAsync(std::function<void()> &&work) {
  236. if (auto strongNativeToJsBridge = m_nativeToJsBridge.lock()) {
  237. strongNativeToJsBridge->runOnExecutorQueue(
  238. [work = std::move(work)](JSExecutor *executor) {
  239. work();
  240. executor->flush();
  241. });
  242. }
  243. }
  244. } // namespace react
  245. } // namespace facebook