Fix optimized bundle stuff.

Reviewed By: davidaurelio, tadeuzagallo

Differential Revision: D3563710

fbshipit-source-id: 2b0a982d388ee5f44b806f8e561ef49a3fd8c8ca
This commit is contained in:
Michał Gregorczyk
2016-07-14 15:23:53 -07:00
committed by Facebook Github Bot 7
parent 0c0ac6e21c
commit 3c0f428f05
18 changed files with 200 additions and 158 deletions

View File

@@ -5,6 +5,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := libreactnativefb
LOCAL_SRC_FILES := \
Executor.cpp \
Instance.cpp \
JSCExecutor.cpp \
JSCHelpers.cpp \

View File

@@ -109,6 +109,7 @@ react_library(
force_static = True,
srcs = [
'CxxMessageQueue.cpp',
'Executor.cpp',
'Instance.cpp',
'JSCExecutor.cpp',
'JSCHelpers.cpp',

View File

@@ -0,0 +1,77 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include "Executor.h"
#include <errno.h>
#include <fcntl.h>
#include <fstream>
#include <stdio.h>
#include <sys/stat.h>
#include <folly/Memory.h>
namespace facebook {
namespace react {
void JSExecutor::loadApplicationScript(std::string bundlePath, std::string sourceURL, int flags) {
if ((flags & UNPACKED_JS_SOURCE) == 0) {
throw std::runtime_error("No unpacked js source file");
}
return loadApplicationScript(
JSBigMmapString::fromOptimizedBundle(bundlePath),
std::move(sourceURL));
}
static JSBigMmapString::Encoding encodingFromByte(uint8_t byte) {
switch (byte) {
case 0:
return JSBigMmapString::Encoding::Unknown;
case 1:
return JSBigMmapString::Encoding::Ascii;
case 2:
return JSBigMmapString::Encoding::Utf8;
case 3:
return JSBigMmapString::Encoding::Utf16;
default:
throw std::invalid_argument("Unknown bundle encoding");
}
}
std::unique_ptr<const JSBigMmapString> JSBigMmapString::fromOptimizedBundle(
const std::string& bundlePath) {
uint8_t sha1[20];
uint8_t encoding;
struct stat fileInfo;
int fd = -1;
SCOPE_FAIL { CHECK(fd == -1 || ::close(fd) == 0); };
{
auto metaPath = bundlePath + UNPACKED_META_PATH_SUFFIX;
std::ifstream metaFile;
metaFile.exceptions(std::ifstream::eofbit | std::ifstream::failbit | std::ifstream::badbit);
metaFile.open(metaPath, std::ifstream::in | std::ifstream::binary);
metaFile.read(reinterpret_cast<char*>(sha1), sizeof(sha1));
metaFile.read(reinterpret_cast<char*>(&encoding), sizeof(encoding));
}
{
auto sourcePath = bundlePath + UNPACKED_JS_SOURCE_PATH_SUFFIX;
fd = ::open(sourcePath.c_str(), O_RDONLY);
if (fd == -1) {
throw std::runtime_error(std::string("could not open js bundle file: ") + ::strerror(errno));
}
}
if (::fstat(fd, &fileInfo)) {
throw std::runtime_error(std::string("fstat on js bundle failed: ") + strerror(errno));
}
return folly::make_unique<const JSBigMmapString>(
fd,
fileInfo.st_size,
sha1,
encodingFromByte(encoding));
}
} // namespace react
} // namespace facebook

View File

@@ -16,6 +16,13 @@
namespace facebook {
namespace react {
#define UNPACKED_JS_SOURCE_PATH_SUFFIX "/bundle.js"
#define UNPACKED_META_PATH_SUFFIX "/bundle.meta"
enum {
UNPACKED_JS_SOURCE = (1 << 0),
};
class JSExecutor;
class MessageQueueThread;
@@ -190,6 +197,8 @@ public:
return m_encoding;
}
static std::unique_ptr<const JSBigMmapString> fromOptimizedBundle(const std::string& bundlePath);
private:
int m_fd;
size_t m_size;
@@ -206,6 +215,11 @@ public:
virtual void loadApplicationScript(std::unique_ptr<const JSBigString> script,
std::string sourceURL) = 0;
/**
* Execute an application script optimized bundle in the JS context.
*/
virtual void loadApplicationScript(std::string bundlePath, std::string source, int flags);
/**
* Add an application "unbundle" file
*/
@@ -245,4 +259,6 @@ public:
virtual ~JSExecutor() {}
};
std::unique_ptr<const JSBigMmapString> readJSBundle(const std::string& path);
} }

View File

@@ -75,6 +75,16 @@ void Instance::loadScriptFromFile(const std::string& filename,
loadScriptFromString(std::move(buf), sourceURL);
}
void Instance::loadScriptFromOptimizedBundle(std::string bundlePath,
std::string sourceURL,
int flags) {
SystraceSection s("reactbridge_xplat_loadScriptFromOptimizedBundle",
"bundlePath", bundlePath);
nativeToJsBridge_->loadOptimizedApplicationScript(std::move(bundlePath),
std::move(sourceURL),
flags);
}
void Instance::loadUnbundle(std::unique_ptr<JSModulesUnbundle> unbundle,
std::unique_ptr<const JSBigString> startupScript,
std::string startupScriptSourceURL) {

View File

@@ -36,6 +36,7 @@ class Instance {
std::shared_ptr<ModuleRegistry> moduleRegistry);
void loadScriptFromString(std::unique_ptr<const JSBigString> string, std::string sourceURL);
void loadScriptFromFile(const std::string& filename, const std::string& sourceURL);
void loadScriptFromOptimizedBundle(std::string bundlePath, std::string sourceURL, int flags);
void loadUnbundle(
std::unique_ptr<JSModulesUnbundle> unbundle,
std::unique_ptr<const JSBigString> startupScript,

View File

@@ -254,15 +254,38 @@ void JSCExecutor::terminateOnJSVMThread() {
}
#ifdef WITH_FBJSCEXTENSIONS
static void loadApplicationSource(
const JSGlobalContextRef context,
const JSBigMmapString* script,
const std::string& sourceURL) {
void JSCExecutor::loadApplicationScript(
std::string bundlePath,
std::string sourceURL,
int flags) {
SystraceSection s("JSCExecutor::loadApplicationScript",
"sourceURL", sourceURL);
if ((flags & UNPACKED_JS_SOURCE) == 0) {
throw std::runtime_error("Optimized bundle with no unpacked js source");
}
auto jsScriptBigString = JSBigMmapString::fromOptimizedBundle(bundlePath);
if (jsScriptBigString->encoding() != JSBigMmapString::Encoding::Ascii) {
LOG(WARNING) << "Bundle is not ASCII encoded - falling back to the slow path";
return loadApplicationScript(std::move(jsScriptBigString), sourceURL);
}
String jsSourceURL(sourceURL.c_str());
bool is8bit = script->encoding() == JSBigMmapString::Encoding::Ascii || script->encoding() == JSBigMmapString::Encoding::Utf8;
JSSourceCodeRef sourceCode = JSCreateSourceCode(script->fd(), script->size(), jsSourceURL, script->hash(), is8bit);
evaluateSourceCode(context, sourceCode, jsSourceURL);
JSReleaseSourceCode(sourceCode);
JSSourceCodeRef sourceCode = JSCreateSourceCode(
jsScriptBigString->fd(),
jsScriptBigString->size(),
jsSourceURL,
jsScriptBigString->hash(),
true);
SCOPE_EXIT { JSReleaseSourceCode(sourceCode); };
evaluateSourceCode(m_context, sourceCode, jsSourceURL);
bindBridge();
flush();
ReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
}
#endif
@@ -270,16 +293,6 @@ void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> scrip
SystraceSection s("JSCExecutor::loadApplicationScript",
"sourceURL", sourceURL);
#ifdef WITH_FBJSCEXTENSIONS
if (auto source = dynamic_cast<const JSBigMmapString *>(script.get())) {
loadApplicationSource(m_context, source, sourceURL);
bindBridge();
flush();
ReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
return;
}
#endif
#ifdef WITH_FBSYSTRACE
fbsystrace_begin_section(
TRACE_TAG_REACT_CXX_BRIDGE,

View File

@@ -59,6 +59,12 @@ public:
virtual void loadApplicationScript(
std::unique_ptr<const JSBigString> script,
std::string sourceURL) throw(JSException) override;
#ifdef WITH_FBJSCEXTENSIONS
virtual void loadApplicationScript(
std::string bundlePath,
std::string sourceURL,
int flags) override;
#endif
virtual void setJSModulesUnbundle(
std::unique_ptr<JSModulesUnbundle> unbundle) override;
virtual void callFunction(

View File

@@ -124,6 +124,20 @@ void NativeToJsBridge::loadApplicationScript(std::unique_ptr<const JSBigString>
m_mainExecutor->loadApplicationScript(std::move(script), std::move(sourceURL));
}
void NativeToJsBridge::loadOptimizedApplicationScript(
std::string bundlePath,
std::string sourceURL,
int flags) {
runOnExecutorQueue(
m_mainExecutorToken,
[bundlePath=std::move(bundlePath),
sourceURL=std::move(sourceURL),
flags=flags]
(JSExecutor* executor) {
executor->loadApplicationScript(std::move(bundlePath), std::move(sourceURL), flags);
});
}
void NativeToJsBridge::loadApplicationUnbundle(
std::unique_ptr<JSModulesUnbundle> unbundle,
std::unique_ptr<const JSBigString> startupScript,

View File

@@ -84,6 +84,12 @@ public:
*/
void loadApplicationScript(std::unique_ptr<const JSBigString> script, std::string sourceURL);
/**
* Similar to loading a "bundle", but instead of passing js source this method accepts
* path to a directory containing files prepared for particular JSExecutor.
*/
void loadOptimizedApplicationScript(std::string bundlePath, std::string sourceURL, int flags);
/**
* An "unbundle" is a backend that stores and injects JavaScript modules as
* individual scripts, rather than bundling all of them into a single scrupt.