diff --git a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp index b0ee45e6b09a..db2d563839a8 100644 --- a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp +++ b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp @@ -13,14 +13,13 @@ #include #include #include +#include #include -#include #include -#include #include #include #include -#include +// #include #include #include #include @@ -31,8 +30,8 @@ #include "CxxModuleWrapper.h" #include "JavaScriptExecutorHolder.h" #include "JNativeRunnable.h" -#include "JniJSModulesUnbundle.h" #include "NativeArray.h" +#include "FileRAMBundle.h" using namespace facebook::jni; @@ -178,7 +177,7 @@ void CatalystInstanceImpl::jniSetSourceURL(const std::string& sourceURL) { } void CatalystInstanceImpl::jniRegisterSegment(int segmentId, const std::string& path) { - // TODO: remove + // TODO: remove or figure out how to port it } void CatalystInstanceImpl::jniLoadScriptFromAssets( @@ -190,25 +189,19 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets( auto manager = extractAssetManager(assetManager); auto script = loadScriptFromAssets(manager, sourceURL); - // TODO: refactor + add checks - std::unique_ptr bundle = - std::make_unique(std::move(script), assetURL, sourceURL); - instance_->loadBundle(std::move(bundle), loadSynchronously); - // if (JniJSModulesUnbundle::isUnbundle(manager, sourceURL)) { - // auto bundle = JniJSModulesUnbundle::fromEntryFile(manager, sourceURL); - // auto registry = RAMBundleRegistry::singleBundleRegistry(std::move(bundle)); - // instance_->loadRAMBundle( - // std::move(registry), - // std::move(script), - // sourceURL, - // loadSynchronously); - // return; - // } else if (Instance::isIndexedRAMBundle(&script)) { - // instance_->loadRAMBundleFromString(std::move(script), sourceURL); - // } else { - // instance_->loadScriptFromString(std::move(script), sourceURL, loadSynchronously); - // } + std::unique_ptr bundle; + if (FileRAMBundle::isFileRAMBundle(manager, sourceURL.c_str())) { + // TODO: create File RAM Bundle + } else if (IndexedRAMBundle::isIndexedRAMBundle(script.get())) { + bundle = std::make_unique(std::move(script), + sourceURL, + sourceURL); + } else { + bundle = std::make_unique(std::move(script), sourceURL); + } + + instance_->loadBundle(std::move(bundle), loadSynchronously); } void CatalystInstanceImpl::jniLoadScriptFromFile(const std::string& fileName, diff --git a/ReactAndroid/src/main/jni/react/jni/FileRAMBundle.cpp b/ReactAndroid/src/main/jni/react/jni/FileRAMBundle.cpp index a0b8199722da..7344b715bea0 100644 --- a/ReactAndroid/src/main/jni/react/jni/FileRAMBundle.cpp +++ b/ReactAndroid/src/main/jni/react/jni/FileRAMBundle.cpp @@ -20,8 +20,8 @@ namespace react { using asset_ptr = std::unique_ptr>; -static std::string jsModulesDir(const std::string& entryFile) { - std::string dir = dirname(entryFile.c_str()); +static std::string jsModulesDir(const char* entryFile) { + std::string dir = dirname(entryFile); // android's asset manager does not work with paths that start with a dot return dir == "." ? "js-modules/" : dir + "/js-modules/"; @@ -29,15 +29,14 @@ static std::string jsModulesDir(const std::string& entryFile) { static asset_ptr openAsset( AAssetManager* manager, - const std::string& fileName, + const char* fileName, int mode = AASSET_MODE_STREAMING) { return asset_ptr( - AAssetManager_open(manager, fileName.c_str(), mode), AAsset_close); + AAssetManager_open(manager, fileName, mode), AAsset_close); } -bool FileRAMBundle::isFileRAMBundle( - AAssetManager* assetManager, - const std::string& assetName) { +bool FileRAMBundle::isFileRAMBundle(AAssetManager* assetManager, + const char* assetName) { if (!assetManager) { return false; } @@ -61,8 +60,12 @@ FileRAMBundle::FileRAMBundle( moduleDirectory_(moduleDirectory), startupScript_(std::move(startupScript)) {} -std::shared_ptr FileRAMBundle::getStartupScript() const { - return startupScript_; +std::unique_ptr FileRAMBundle::getStartupScript() const { + // It might be used multiple times, so we don't want to move it, but instead copy it. + std::unique_ptr script = + std::make_unique(startupScript_->size()); + std::memcpy(script->data(), startupScript_->c_str(), startupScript_->size()); + return std::move(script); } std::string FileRAMBundle::getSourcePath() const { @@ -85,7 +88,7 @@ FileRAMBundle::Module FileRAMBundle::getModule(uint32_t moduleId) const { auto sourceUrl = folly::to(moduleId, ".js"); auto fileName = moduleDirectory_ + sourceUrl; - auto asset = openAsset(assetManager_, fileName, AASSET_MODE_BUFFER); + auto asset = openAsset(assetManager_, fileName.c_str(), AASSET_MODE_BUFFER); const char* buffer = nullptr; if (asset != nullptr) { diff --git a/ReactAndroid/src/main/jni/react/jni/FileRAMBundle.h b/ReactAndroid/src/main/jni/react/jni/FileRAMBundle.h index 34a86491df76..4a1da9b143da 100644 --- a/ReactAndroid/src/main/jni/react/jni/FileRAMBundle.h +++ b/ReactAndroid/src/main/jni/react/jni/FileRAMBundle.h @@ -13,6 +13,8 @@ class FileRAMBundle : public RAMBundle { * This implementation reads modules as single file from the assets of an apk. */ public: + static bool isFileRAMBundle(AAssetManager* assetManager, const char* assetName); + FileRAMBundle() = default; FileRAMBundle( AAssetManager* assetManager, @@ -20,20 +22,16 @@ class FileRAMBundle : public RAMBundle { std::unique_ptr startupScript); ~FileRAMBundle() {} - static bool isFileRAMBundle( - AAssetManager* assetManager, - const std::string& assetName); - std::string getSourcePath() const override; std::string getSourceURL() const override; - std::shared_ptr getStartupScript() const override; + std::unique_ptr getStartupScript() const override; Module getModule(uint32_t moduleId) const override; BundleType getBundleType() const override; private: AAssetManager* assetManager_ = nullptr; std::string moduleDirectory_; - std::shared_ptr startupScript_; + std::unique_ptr startupScript_; }; } // namespace react diff --git a/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.cpp b/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.cpp deleted file mode 100644 index 57b1fe69af97..000000000000 --- a/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.cpp +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. - -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -#include "JniJSModulesUnbundle.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -using magic_number_t = uint32_t; -const magic_number_t MAGIC_FILE_HEADER = 0xFB0BD1E5; -const char* MAGIC_FILE_NAME = "UNBUNDLE"; - -namespace facebook { -namespace react { - -using asset_ptr = - std::unique_ptr>; - -static std::string jsModulesDir(const std::string& entryFile) { - std::string dir = dirname(entryFile.c_str()); - - // android's asset manager does not work with paths that start with a dot - return dir == "." ? "js-modules/" : dir + "/js-modules/"; -} - -static asset_ptr openAsset( - AAssetManager *manager, - const std::string& fileName, - int mode = AASSET_MODE_STREAMING) { - return asset_ptr( - AAssetManager_open(manager, fileName.c_str(), mode), - AAsset_close); -} - -std::unique_ptr JniJSModulesUnbundle::fromEntryFile( - AAssetManager *assetManager, - const std::string& entryFile) { - return folly::make_unique(assetManager, jsModulesDir(entryFile)); - } - -JniJSModulesUnbundle::JniJSModulesUnbundle(AAssetManager *assetManager, const std::string& moduleDirectory) : - m_assetManager(assetManager), - m_moduleDirectory(moduleDirectory) {} - -bool JniJSModulesUnbundle::isUnbundle( - AAssetManager *assetManager, - const std::string& assetName) { - if (!assetManager) { - return false; - } - - auto magicFileName = jsModulesDir(assetName) + MAGIC_FILE_NAME; - auto asset = openAsset(assetManager, magicFileName.c_str()); - if (asset == nullptr) { - return false; - } - - magic_number_t fileHeader = 0; - AAsset_read(asset.get(), &fileHeader, sizeof(fileHeader)); - return fileHeader == htole32(MAGIC_FILE_HEADER); -} - -JSModulesUnbundle::Module JniJSModulesUnbundle::getModule(uint32_t moduleId) const { - // can be nullptr for default constructor. - FBASSERTMSGF(m_assetManager != nullptr, "Unbundle has not been initialized with an asset manager"); - - std::ostringstream sourceUrlBuilder; - sourceUrlBuilder << moduleId << ".js"; - auto sourceUrl = sourceUrlBuilder.str(); - - auto fileName = m_moduleDirectory + sourceUrl; - auto asset = openAsset(m_assetManager, fileName, AASSET_MODE_BUFFER); - - const char *buffer = nullptr; - if (asset != nullptr) { - buffer = static_cast(AAsset_getBuffer(asset.get())); - } - if (buffer == nullptr) { - throw ModuleNotFound(moduleId); - } - return {sourceUrl, std::string(buffer, AAsset_getLength(asset.get()))}; -} - -} -} diff --git a/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.h b/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.h deleted file mode 100644 index 86385432c877..000000000000 --- a/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Facebook, Inc. and its 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 - -namespace facebook { -namespace react { - -class JniJSModulesUnbundle : public JSModulesUnbundle { - /** - * This implementation reads modules as single file from the assets of an apk. - */ -public: - JniJSModulesUnbundle() = default; - JniJSModulesUnbundle(AAssetManager *assetManager, const std::string& moduleDirectory); - JniJSModulesUnbundle(JniJSModulesUnbundle&& other) = delete; - JniJSModulesUnbundle& operator= (JSModulesUnbundle&& other) = delete; - - static std::unique_ptr fromEntryFile(AAssetManager *assetManager, const std::string& entryFile); - - static bool isUnbundle( - AAssetManager *assetManager, - const std::string& assetName); - virtual Module getModule(uint32_t moduleId) const override; -private: - AAssetManager *m_assetManager = nullptr; - std::string m_moduleDirectory; -}; - -} -} diff --git a/ReactCommon/cxxreact/BasicBundle.cpp b/ReactCommon/cxxreact/BasicBundle.cpp index 09cc64d4cd99..f85193d921dd 100644 --- a/ReactCommon/cxxreact/BasicBundle.cpp +++ b/ReactCommon/cxxreact/BasicBundle.cpp @@ -16,8 +16,12 @@ std::string BasicBundle::getSourceURL() const { return sourceURL_; } -std::shared_ptr BasicBundle::getScript() { - return script_; +std::unique_ptr BasicBundle::getScript() const { + // It might be used multiple times, so we don't want to move it, but instead copy it. + std::unique_ptr script = + std::make_unique(script_->size()); + std::memcpy(script->data(), script_->c_str(), script_->size()); + return std::move(script); } } // react diff --git a/ReactCommon/cxxreact/BasicBundle.h b/ReactCommon/cxxreact/BasicBundle.h index 8858f0181d97..aef52812797b 100644 --- a/ReactCommon/cxxreact/BasicBundle.h +++ b/ReactCommon/cxxreact/BasicBundle.h @@ -12,11 +12,11 @@ class BasicBundle : public Bundle { BasicBundle(std::unique_ptr script, std::string sourceURL); std::string getSourceURL() const override; - std::shared_ptr getScript(); + std::unique_ptr getScript() const; BundleType getBundleType() const override; private: std::string sourceURL_; - std::shared_ptr script_; + std::unique_ptr script_; }; } // react diff --git a/ReactCommon/cxxreact/Bundle.cpp b/ReactCommon/cxxreact/Bundle.cpp new file mode 100644 index 000000000000..feef48337e58 --- /dev/null +++ b/ReactCommon/cxxreact/Bundle.cpp @@ -0,0 +1,39 @@ +#include "Bundle.h" +#include + +namespace facebook { +namespace react { + +static uint32_t constexpr RAMBundleMagicNumber = 0xFB0BD1E5; +static uint32_t constexpr BCBundleMagicNumber = 0x6D657300; + +BundleType Bundle::parseTypeFromHeader(const BundleHeader& header) { + switch (folly::Endian::little(header.magic)) { + case RAMBundleMagicNumber: + return BundleType::IndexedRAMBundle; + case BCBundleMagicNumber: + return BundleType::BCBundle; + default: + return BundleType::BasicBundle; + } +} + +const char* Bundle::stringForBundleType(const BundleType& type) { + switch (type) { + case BundleType::BasicBundle: + return "BundleType"; + case BundleType::IndexedRAMBundle: + return "Indexed RAM Bundle"; + case BundleType::FileRAMBundle: + return "File RAM Bundle"; + case BundleType::BCBundle: + return "BC Bundle"; + case BundleType::DeltaBundle: + return "Delta Bundle"; + default: + return ""; + } +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/cxxreact/Bundle.h b/ReactCommon/cxxreact/Bundle.h index e65e442fa685..0f3b5d2f12b6 100644 --- a/ReactCommon/cxxreact/Bundle.h +++ b/ReactCommon/cxxreact/Bundle.h @@ -1,20 +1,56 @@ #pragma once +#include #include #include "JSBigString.h" +#ifndef RN_EXPORT +#define RN_EXPORT __attribute__((visibility("default"))) +#endif + namespace facebook { namespace react { +/** + * BundleHeader + * + * RAM bundles and BC bundles begin with headers. For RAM bundles this is + * 4 bytes, for BC bundles this is 12 bytes. This structure holds the first 12 + * bytes from a bundle in a way that gives access to that information. + */ +FOLLY_PACK_PUSH +struct FOLLY_PACK_ATTR BundleHeader { + BundleHeader() { + std::memset(this, 0, sizeof(BundleHeader)); + } + + uint32_t magic; + uint32_t reserved_; + uint32_t version; +}; +FOLLY_PACK_POP + enum class BundleType : unsigned int { BasicBundle = 0, IndexedRAMBundle = 1, FileRAMBundle = 2, DeltaBundle = 3, + BCBundle = 4, // NOTE: what is this? is it used anywhere? }; class Bundle { public: + /** + * Takes the first 8 bytes of a bundle, and returns a tag describing the + * bundle's format. + */ + static RN_EXPORT BundleType parseTypeFromHeader(const BundleHeader& header); + /** + * Convert an `BundleType` enum into a string, useful for emitting in errors + * and diagnostic messages. + */ + static RN_EXPORT const char* stringForBundleType(const BundleType& type); + Bundle() = default; Bundle(const Bundle&) = delete; Bundle& operator=(const Bundle&) = delete; diff --git a/ReactCommon/cxxreact/BundleRegistry.cpp b/ReactCommon/cxxreact/BundleRegistry.cpp index 0712a2d13a34..24cb490653a3 100644 --- a/ReactCommon/cxxreact/BundleRegistry.cpp +++ b/ReactCommon/cxxreact/BundleRegistry.cpp @@ -30,37 +30,40 @@ void BundleRegistry::runNewExecutionEnvironment(std::unique_ptr in execEnv = bundleExecutionEnvironments_.back(); execEnv->jsQueue->runOnQueueSync([this, execEnv, callback]() mutable { execEnv->nativeToJsBridge = std::make_unique(jsExecutorFactory_, - moduleRegistry_, - execEnv->jsQueue, - callback_); + moduleRegistry_, + execEnv->jsQueue, + callback_); auto bundle = execEnv->initialBundle.lock(); if (bundle->getBundleType() == BundleType::FileRAMBundle || bundle->getBundleType() == BundleType::IndexedRAMBundle) { std::shared_ptr ramBundle = std::dynamic_pointer_cast(bundle); - // TODO: check if ramBundle is not empty or throw exception - - auto getModuleLambda = folly::Optional>( - [ramBundle](uint32_t moduleId) { - return ramBundle->getModule(moduleId); - }); - execEnv->nativeToJsBridge-> - setupEnvironmentSync([](std::string p, bool n) {}, // TODO: provide actual impl - getModuleLambda); + if (!ramBundle) { + throw std::runtime_error("Cannot cast Bundle to RAMBundle"); + } + + auto getModule = folly::Optional([ramBundle](uint32_t moduleId) { + return ramBundle->getModule(moduleId); + }); - // TODO: figure out if we can get away from copying - std::unique_ptr startupScript = std::make_unique( - std::string(ramBundle->getStartupScript()->c_str())); - execEnv->nativeToJsBridge-> - loadScriptSync(std::move(startupScript), - ramBundle->getSourceURL()); + evalInitialBundle(execEnv, + ramBundle->getStartupScript(), + ramBundle->getSourceURL(), + makeLoadBundleLambda(), + getModule); } else { std::shared_ptr basicBundle = std::dynamic_pointer_cast(bundle); - // TODO: check if ramBundle is not empty or throw exception + if (!basicBundle) { + throw std::runtime_error("Cannot cast Bundle to BasicBundle"); + } - // TODO: setupEnvironment + loadScript + evalInitialBundle(execEnv, + basicBundle->getScript(), + basicBundle->getSourceURL(), + makeLoadBundleLambda(), + folly::Optional()); } execEnv->valid = true; @@ -68,13 +71,30 @@ void BundleRegistry::runNewExecutionEnvironment(std::unique_ptr in }); } +void BundleRegistry::evalInitialBundle(std::shared_ptr execEnv, + std::unique_ptr startupScript, + std::string sourceURL, + LoadBundleLambda loadBundle, + folly::Optional getModule) { + execEnv->nativeToJsBridge->setupEnvironmentSync(loadBundle, getModule); + execEnv->nativeToJsBridge->loadScriptSync(std::move(startupScript), + sourceURL); +} + +BundleRegistry::LoadBundleLambda BundleRegistry::makeLoadBundleLambda() { + return [](std::string bundlePath, bool inCurrentEnvironment) { + // TODO: provide actual implementation + throw std::runtime_error("loadBundle is not implemented yet"); + }; +} + void BundleRegistry::disposeExecutionEnvironments() { for (auto execEnv : bundleExecutionEnvironments_) { execEnv->nativeToJsBridge->destroy(); } } -std::weak_ptr BundleRegistry::getFirstExecutionEnvironemnt() { +std::weak_ptr BundleRegistry::getFirstExecutionEnvironment() { if (bundleExecutionEnvironments_.size() == 0) { throw std::runtime_error("Cannot get first BundleExecutionEnvironment"); } @@ -82,7 +102,7 @@ std::weak_ptr BundleRegistry::getFir return std::weak_ptr(bundleExecutionEnvironments_[0]); } -bool BundleRegistry::hasExecutionEnvironemnt() { +bool BundleRegistry::hasExecutionEnvironment() { return bundleExecutionEnvironments_.size() > 0; } diff --git a/ReactCommon/cxxreact/BundleRegistry.h b/ReactCommon/cxxreact/BundleRegistry.h index 5824d48b1335..cd24e31f51ca 100644 --- a/ReactCommon/cxxreact/BundleRegistry.h +++ b/ReactCommon/cxxreact/BundleRegistry.h @@ -14,6 +14,9 @@ class ModuleRegistry; class BundleRegistry { public: + using LoadBundleLambda = std::function; + using GetModuleLambda = std::function; + struct BundleExecutionEnvironment { std::shared_ptr jsQueue; std::unique_ptr nativeToJsBridge; @@ -33,8 +36,8 @@ class BundleRegistry { std::function callback); void disposeExecutionEnvironments(); // TODO: get rid of this - std::weak_ptr getFirstExecutionEnvironemnt(); - bool hasExecutionEnvironemnt(); + std::weak_ptr getFirstExecutionEnvironment(); + bool hasExecutionEnvironment(); private: @@ -44,6 +47,18 @@ class BundleRegistry { std::shared_ptr moduleRegistry_; std::shared_ptr callback_; std::function()> jsQueueFactory_; + + /** + * Setup environment and load initial bundle. Should be called only once + * per BundleExecutionEnvironemnt. + */ + void evalInitialBundle(std::shared_ptr execEnv, + std::unique_ptr startupScript, + std::string sourceURL, + LoadBundleLambda loadBundle, + folly::Optional getModule); + + LoadBundleLambda makeLoadBundleLambda(/* take pointer to BEE or initial Bundle */); }; } // react diff --git a/ReactCommon/cxxreact/IndexedRAMBundle.cpp b/ReactCommon/cxxreact/IndexedRAMBundle.cpp index eeb938d00e5a..9a7818dd32c5 100644 --- a/ReactCommon/cxxreact/IndexedRAMBundle.cpp +++ b/ReactCommon/cxxreact/IndexedRAMBundle.cpp @@ -6,6 +6,28 @@ namespace facebook { namespace react { + +bool IndexedRAMBundle::isIndexedRAMBundle(const char* sourcePath) { + std::ifstream bundle_stream(sourcePath, std::ios_base::in); + BundleHeader header; + + if (!bundle_stream || + !bundle_stream.read(reinterpret_cast(&header), sizeof(header))) { + return false; + } + + return parseTypeFromHeader(header) == BundleType::IndexedRAMBundle; +} + +bool IndexedRAMBundle::isIndexedRAMBundle(const JSBigString* script) { + BundleHeader header; + std::memcpy(reinterpret_cast(&header), + script->c_str(), + sizeof(header)); + + return parseTypeFromHeader(header) == BundleType::IndexedRAMBundle; +} + IndexedRAMBundle::IndexedRAMBundle(std::string sourcePath, std::string sourceURL) { bundle_ = std::make_unique( std::ifstream(sourcePath, std::ifstream::binary)); @@ -80,8 +102,12 @@ IndexedRAMBundle::Module IndexedRAMBundle::getModule(uint32_t moduleId) const { return ret; } -std::shared_ptr IndexedRAMBundle::getStartupScript() const { - return startupScript_; +std::unique_ptr IndexedRAMBundle::getStartupScript() const { + // It might be used multiple times, so we don't want to move it, but instead copy it. + std::unique_ptr script = + std::make_unique(startupScript_->size()); + std::memcpy(script->data(), startupScript_->c_str(), startupScript_->size()); + return std::move(script); } std::string IndexedRAMBundle::getModuleCode(const uint32_t id) const { diff --git a/ReactCommon/cxxreact/IndexedRAMBundle.h b/ReactCommon/cxxreact/IndexedRAMBundle.h index 1315c902b467..c823904f7ed5 100644 --- a/ReactCommon/cxxreact/IndexedRAMBundle.h +++ b/ReactCommon/cxxreact/IndexedRAMBundle.h @@ -10,6 +10,9 @@ namespace react { class IndexedRAMBundle : public RAMBundle { public: + static bool isIndexedRAMBundle(const char* sourcePath); + static bool isIndexedRAMBundle(const JSBigString* script); + IndexedRAMBundle(std::string sourcePath, std::string sourceURL); // For Android IndexedRAMBundle loaded from Assets @@ -20,7 +23,7 @@ class IndexedRAMBundle : public RAMBundle { std::string getSourceURL() const override; std::string getSourcePath() const override; - std::shared_ptr getStartupScript() const override; + std::unique_ptr getStartupScript() const override; Module getModule(uint32_t moduleId) const override; BundleType getBundleType() const override; @@ -55,7 +58,7 @@ class IndexedRAMBundle : public RAMBundle { std::string sourceURL_; std::string sourcePath_; - std::shared_ptr startupScript_; + std::unique_ptr startupScript_; mutable std::unique_ptr bundle_; ModuleTable table_; size_t baseOffset_; diff --git a/ReactCommon/cxxreact/Instance.cpp b/ReactCommon/cxxreact/Instance.cpp index 0efabb21977d..0fd1fb3b384f 100644 --- a/ReactCommon/cxxreact/Instance.cpp +++ b/ReactCommon/cxxreact/Instance.cpp @@ -6,16 +6,12 @@ #include "Instance.h" #include "JSBigString.h" -#include "JSBundleType.h" #include "JSExecutor.h" #include "MessageQueueThread.h" #include "MethodCall.h" -#include "NativeToJsBridge.h" -#include "RAMBundleRegistry.h" #include "RecoverableError.h" #include "SystraceSection.h" -#include #include #include #include @@ -49,16 +45,6 @@ void Instance::initializeBridge( callback_, [jsQueue]() { return jsQueue; } // TODO: use a factory ); - // jsQueue->runOnQueueSync([this, &jsef, jsQueue]() mutable { - // nativeToJsBridge_ = folly::make_unique( - // jsef.get(), moduleRegistry_, jsQueue, callback_); - - // std::lock_guard lock(m_syncMutex); - // m_syncReady = true; - // m_syncCV.notify_all(); - // }); - - // CHECK(nativeToJsBridge_); } void Instance::loadBundleAsync(std::unique_ptr bundle) { @@ -93,28 +79,9 @@ void Instance::loadBundle(std::unique_ptr bundle, bool loadSynchro } } -bool Instance::isIndexedRAMBundle(const char *sourcePath) { - std::ifstream bundle_stream(sourcePath, std::ios_base::in); - BundleHeader header; - - if (!bundle_stream || - !bundle_stream.read(reinterpret_cast(&header), sizeof(header))) { - return false; - } - - return parseTypeFromHeader(header) == ScriptTag::RAMBundle; -} - -bool Instance::isIndexedRAMBundle(std::unique_ptr* script) { - BundleHeader header; - strncpy(reinterpret_cast(&header), script->get()->c_str(), sizeof(header)); - - return parseTypeFromHeader(header) == ScriptTag::RAMBundle; -} - void Instance::setGlobalVariable(std::string propName, std::unique_ptr jsonValue) { - if (auto execEnv = bundleRegistry_->getFirstExecutionEnvironemnt().lock()) { + if (auto execEnv = bundleRegistry_->getFirstExecutionEnvironment().lock()) { execEnv->nativeToJsBridge->setGlobalVariable(std::move(propName), std::move(jsonValue)); } else { @@ -123,8 +90,8 @@ void Instance::setGlobalVariable(std::string propName, } void* Instance::getJavaScriptContext() { - if (bundleRegistry_->hasExecutionEnvironemnt()) { - if (auto execEnv = bundleRegistry_->getFirstExecutionEnvironemnt().lock()) { + if (bundleRegistry_->hasExecutionEnvironment()) { + if (auto execEnv = bundleRegistry_->getFirstExecutionEnvironment().lock()) { return execEnv->nativeToJsBridge ? execEnv->nativeToJsBridge->getJavaScriptContext() : nullptr; } } @@ -133,8 +100,8 @@ void* Instance::getJavaScriptContext() { } bool Instance::isInspectable() { - if (bundleRegistry_->hasExecutionEnvironemnt()) { - if (auto execEnv = bundleRegistry_->getFirstExecutionEnvironemnt().lock()) { + if (bundleRegistry_->hasExecutionEnvironment()) { + if (auto execEnv = bundleRegistry_->getFirstExecutionEnvironment().lock()) { return execEnv->nativeToJsBridge ? execEnv->nativeToJsBridge->isInspectable() : false; } } @@ -143,8 +110,8 @@ bool Instance::isInspectable() { } bool Instance::isBatchActive() { - if (bundleRegistry_->hasExecutionEnvironemnt()) { - if (auto execEnv = bundleRegistry_->getFirstExecutionEnvironemnt().lock()) { + if (bundleRegistry_->hasExecutionEnvironment()) { + if (auto execEnv = bundleRegistry_->getFirstExecutionEnvironment().lock()) { return execEnv->nativeToJsBridge ? execEnv->nativeToJsBridge->isBatchActive() : false; } } @@ -155,7 +122,7 @@ bool Instance::isBatchActive() { void Instance::callJSFunction(std::string &&module, std::string &&method, folly::dynamic &¶ms) { callback_->incrementPendingJSCalls(); - if (auto execEnv = bundleRegistry_->getFirstExecutionEnvironemnt().lock()) { + if (auto execEnv = bundleRegistry_->getFirstExecutionEnvironment().lock()) { execEnv->nativeToJsBridge->callFunction(std::move(module), std::move(method), std::move(params)); @@ -167,7 +134,7 @@ void Instance::callJSFunction(std::string &&module, std::string &&method, void Instance::callJSCallback(uint64_t callbackId, folly::dynamic &¶ms) { SystraceSection s("Instance::callJSCallback"); callback_->incrementPendingJSCalls(); - if (auto execEnv = bundleRegistry_->getFirstExecutionEnvironemnt().lock()) { + if (auto execEnv = bundleRegistry_->getFirstExecutionEnvironment().lock()) { execEnv->nativeToJsBridge->invokeCallback((double)callbackId, std::move(params)); } else { throw std::runtime_error("BundleExecutionEnvironment pointer is invalid"); @@ -181,7 +148,7 @@ const ModuleRegistry &Instance::getModuleRegistry() const { ModuleRegistry &Instance::getModuleRegistry() { return *moduleRegistry_; } void Instance::handleMemoryPressure(int pressureLevel) { - if (auto execEnv = bundleRegistry_->getFirstExecutionEnvironemnt().lock()) { + if (auto execEnv = bundleRegistry_->getFirstExecutionEnvironment().lock()) { execEnv->nativeToJsBridge->handleMemoryPressure(pressureLevel); } else { throw std::runtime_error("BundleExecutionEnvironment pointer is invalid"); diff --git a/ReactCommon/cxxreact/Instance.h b/ReactCommon/cxxreact/Instance.h index 9e8c361e8609..f03f45e6a834 100644 --- a/ReactCommon/cxxreact/Instance.h +++ b/ReactCommon/cxxreact/Instance.h @@ -42,9 +42,6 @@ class RN_EXPORT Instance { std::shared_ptr jsQueue, std::shared_ptr moduleRegistry); - static bool isIndexedRAMBundle(const char *sourcePath); - static bool isIndexedRAMBundle(std::unique_ptr* string); - void loadBundle(std::unique_ptr bundle, bool loadSynchronously); bool supportsProfiling(); diff --git a/ReactCommon/cxxreact/JSBundleType.cpp b/ReactCommon/cxxreact/JSBundleType.cpp deleted file mode 100644 index f2b7a519a798..000000000000 --- a/ReactCommon/cxxreact/JSBundleType.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. - -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -#include "JSBundleType.h" - -#include - -namespace facebook { -namespace react { - -static uint32_t constexpr RAMBundleMagicNumber = 0xFB0BD1E5; -static uint32_t constexpr BCBundleMagicNumber = 0x6D657300; - -ScriptTag parseTypeFromHeader(const BundleHeader& header) { - switch (folly::Endian::little(header.magic)) { - case RAMBundleMagicNumber: - return ScriptTag::RAMBundle; - case BCBundleMagicNumber: - return ScriptTag::BCBundle; - default: - return ScriptTag::String; - } -} - -const char *stringForScriptTag(const ScriptTag& tag) { - switch (tag) { - case ScriptTag::String: - return "String"; - case ScriptTag::RAMBundle: - return "RAM Bundle"; - case ScriptTag::BCBundle: - return "BC Bundle"; - } - return ""; -} - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/cxxreact/JSBundleType.h b/ReactCommon/cxxreact/JSBundleType.h deleted file mode 100644 index 0cd18948a6fb..000000000000 --- a/ReactCommon/cxxreact/JSBundleType.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) Facebook, Inc. and its 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 - -#ifndef RN_EXPORT -#define RN_EXPORT __attribute__((visibility("default"))) -#endif - -namespace facebook { -namespace react { - -/* - * ScriptTag - * - * Scripts given to the JS Executors to run could be in any of the following - * formats. They are tagged so the executor knows how to run them. - */ -enum struct ScriptTag { - String = 0, - RAMBundle, - BCBundle, -}; - -/** - * BundleHeader - * - * RAM bundles and BC bundles begin with headers. For RAM bundles this is - * 4 bytes, for BC bundles this is 12 bytes. This structure holds the first 12 - * bytes from a bundle in a way that gives access to that information. - */ -FOLLY_PACK_PUSH -struct FOLLY_PACK_ATTR BundleHeader { - BundleHeader() { - std::memset(this, 0, sizeof(BundleHeader)); - } - - uint32_t magic; - uint32_t reserved_; - uint32_t version; -}; -FOLLY_PACK_POP - -/** - * parseTypeFromHeader - * - * Takes the first 8 bytes of a bundle, and returns a tag describing the - * bundle's format. - */ -RN_EXPORT ScriptTag parseTypeFromHeader(const BundleHeader& header); - -/** - * stringForScriptTag - * - * Convert an `ScriptTag` enum into a string, useful for emitting in errors - * and diagnostic messages. - */ -RN_EXPORT const char* stringForScriptTag(const ScriptTag& tag); - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp b/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp deleted file mode 100644 index 6d49ae0a062d..000000000000 --- a/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. - -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -#include "JSIndexedRAMBundle.h" -#include -#include -#include - -namespace facebook { -namespace react { - -std::function(std::string)> JSIndexedRAMBundle::buildFactory() { - return [](const std::string& bundlePath){ - return folly::make_unique(bundlePath.c_str()); - }; -} - -JSIndexedRAMBundle::JSIndexedRAMBundle(const char *sourcePath) { - m_bundle = std::make_unique( - std::ifstream(sourcePath, std::ifstream::binary)); - if (!m_bundle) { - throw std::ios_base::failure( - folly::to("Bundle ", sourcePath, - "cannot be opened: ", m_bundle->rdstate())); - } - init(); -} - -JSIndexedRAMBundle::JSIndexedRAMBundle(std::unique_ptr script) { - // tmpStream is needed because m_bundle is std::istream type - // which has no member 'write' - std::unique_ptr tmpStream = std::make_unique( - std::stringstream()); - tmpStream->write(script->c_str(), script->size()); - m_bundle = std::move(tmpStream); - if (!m_bundle) { - throw std::ios_base::failure( - folly::to("Bundle from string cannot be opened: ", m_bundle->rdstate())); - } - init(); -} - -void JSIndexedRAMBundle::init() { - // read in magic header, number of entries, and length of the startup section - uint32_t header[3]; - static_assert( - sizeof(header) == 12, - "header size must exactly match the input file format"); - - readBundle(reinterpret_cast(header), sizeof(header)); - const size_t numTableEntries = folly::Endian::little(header[1]); - const size_t startupCodeSize = folly::Endian::little(header[2]); - - // allocate memory for meta data and lookup table. - m_table = ModuleTable(numTableEntries); - m_baseOffset = sizeof(header) + m_table.byteLength(); - - // read the lookup table from the file - readBundle( - reinterpret_cast(m_table.data.get()), m_table.byteLength()); - - // read the startup code - m_startupCode = std::unique_ptr(new JSBigBufferString{startupCodeSize - 1}); - - readBundle(m_startupCode->data(), startupCodeSize - 1); -} - -JSIndexedRAMBundle::Module JSIndexedRAMBundle::getModule(uint32_t moduleId) const { - Module ret; - ret.name = folly::to(moduleId, ".js"); - ret.code = getModuleCode(moduleId); - return ret; -} - -std::unique_ptr JSIndexedRAMBundle::getStartupCode() { - CHECK(m_startupCode) << "startup code for a RAM Bundle can only be retrieved once"; - return std::move(m_startupCode); -} - -std::string JSIndexedRAMBundle::getModuleCode(const uint32_t id) const { - const auto moduleData = id < m_table.numEntries ? &m_table.data[id] : nullptr; - - // entries without associated code have offset = 0 and length = 0 - const uint32_t length = moduleData ? folly::Endian::little(moduleData->length) : 0; - if (length == 0) { - throw std::ios_base::failure( - folly::to("Error loading module", id, "from RAM Bundle")); - } - - std::string ret(length - 1, '\0'); - readBundle(&ret.front(), length - 1, m_baseOffset + folly::Endian::little(moduleData->offset)); - return ret; -} - -void JSIndexedRAMBundle::readBundle(char *buffer, const std::streamsize bytes) const { - if (!m_bundle->read(buffer, bytes)) { - if (m_bundle->rdstate() & std::ios::eofbit) { - throw std::ios_base::failure("Unexpected end of RAM Bundle file"); - } - throw std::ios_base::failure( - folly::to("Error reading RAM Bundle: ", m_bundle->rdstate())); - } -} - -void JSIndexedRAMBundle::readBundle( - char *buffer, - const std::streamsize bytes, - const std::ifstream::pos_type position) const { - - if (!m_bundle->seekg(position)) { - throw std::ios_base::failure( - folly::to("Error reading RAM Bundle: ", m_bundle->rdstate())); - } - readBundle(buffer, bytes); -} - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/cxxreact/JSIndexedRAMBundle.h b/ReactCommon/cxxreact/JSIndexedRAMBundle.h deleted file mode 100644 index 2f2db3b708fc..000000000000 --- a/ReactCommon/cxxreact/JSIndexedRAMBundle.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) Facebook, Inc. and its 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 - -#ifndef RN_EXPORT -#define RN_EXPORT __attribute__((visibility("default"))) -#endif - -namespace facebook { -namespace react { - -class RN_EXPORT JSIndexedRAMBundle : public JSModulesUnbundle { -public: - static std::function(std::string)> buildFactory(); - - // Throws std::runtime_error on failure. - JSIndexedRAMBundle(const char *sourceURL); - JSIndexedRAMBundle(std::unique_ptr script); - - // Throws std::runtime_error on failure. - std::unique_ptr getStartupCode(); - // Throws std::runtime_error on failure. - Module getModule(uint32_t moduleId) const override; - -private: - struct ModuleData { - uint32_t offset; - uint32_t length; - }; - static_assert( - sizeof(ModuleData) == 8, - "ModuleData must not have any padding and use sizes matching input files"); - - struct ModuleTable { - size_t numEntries; - std::unique_ptr data; - ModuleTable() : numEntries(0) {}; - ModuleTable(size_t entries) : - numEntries(entries), - data(std::unique_ptr(new ModuleData[numEntries])) {}; - size_t byteLength() const { - return numEntries * sizeof(ModuleData); - } - }; - - void init(); - std::string getModuleCode(const uint32_t id) const; - void readBundle(char *buffer, const std::streamsize bytes) const; - void readBundle( - char *buffer, const - std::streamsize bytes, - const std::istream::pos_type position) const; - - mutable std::unique_ptr m_bundle; - ModuleTable m_table; - size_t m_baseOffset; - std::unique_ptr m_startupCode; -}; - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/cxxreact/RAMBundle.h b/ReactCommon/cxxreact/RAMBundle.h index 0cdf0166c1e0..b26b8d890c97 100644 --- a/ReactCommon/cxxreact/RAMBundle.h +++ b/ReactCommon/cxxreact/RAMBundle.h @@ -25,7 +25,7 @@ class RAMBundle : public Bundle { virtual ~RAMBundle() {}; virtual std::string getSourcePath() const = 0; - virtual std::shared_ptr getStartupScript() const = 0; + virtual std::unique_ptr getStartupScript() const = 0; virtual Module getModule(uint32_t moduleId) const = 0; };