mirror of
https://github.com/status-im/react-native.git
synced 2025-01-28 02:04:55 +00:00
add API to CatalystInstanceImpl for executing optimized bundle
Reviewed By: tadeuzagallo Differential Revision: D3545345 fbshipit-source-id: 538fec77b816c3fd767e8c2eda81c78971996b17
This commit is contained in:
parent
a665914d18
commit
1331e20db5
@ -161,8 +161,9 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
|||||||
MessageQueueThread moduleQueue,
|
MessageQueueThread moduleQueue,
|
||||||
ModuleRegistryHolder registryHolder);
|
ModuleRegistryHolder registryHolder);
|
||||||
|
|
||||||
/* package */ native void loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean useLazyBundle);
|
/* package */ native void loadScriptFromAssets(AssetManager assetManager, String assetURL);
|
||||||
/* package */ native void loadScriptFromFile(String fileName, String sourceURL);
|
/* package */ native void loadScriptFromFile(String fileName, String sourceURL);
|
||||||
|
/* package */ native void loadScriptFromOptimizedBundle(String path, String sourceURL, int flags);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void runJSBundle() {
|
public void runJSBundle() {
|
||||||
|
@ -30,18 +30,11 @@ public abstract class JSBundleLoader {
|
|||||||
public static JSBundleLoader createFileLoader(
|
public static JSBundleLoader createFileLoader(
|
||||||
final Context context,
|
final Context context,
|
||||||
final String fileName) {
|
final String fileName) {
|
||||||
return createFileLoader(context, fileName, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JSBundleLoader createFileLoader(
|
|
||||||
final Context context,
|
|
||||||
final String fileName,
|
|
||||||
final boolean useLazyBundle) {
|
|
||||||
return new JSBundleLoader() {
|
return new JSBundleLoader() {
|
||||||
@Override
|
@Override
|
||||||
public void loadScript(CatalystInstanceImpl instance) {
|
public void loadScript(CatalystInstanceImpl instance) {
|
||||||
if (fileName.startsWith("assets://")) {
|
if (fileName.startsWith("assets://")) {
|
||||||
instance.loadScriptFromAssets(context.getAssets(), fileName, useLazyBundle);
|
instance.loadScriptFromAssets(context.getAssets(), fileName);
|
||||||
} else {
|
} else {
|
||||||
instance.loadScriptFromFile(fileName, fileName);
|
instance.loadScriptFromFile(fileName, fileName);
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,12 @@ import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE;
|
|||||||
*/
|
*/
|
||||||
public class UnpackingJSBundleLoader extends JSBundleLoader {
|
public class UnpackingJSBundleLoader extends JSBundleLoader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag passed to loadScriptFromOptimizedBundle to let the bridge know that
|
||||||
|
* the unpacked unpacked js source file.
|
||||||
|
*/
|
||||||
|
static final int UNPACKED_JS_SOURCE = (1 << 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of the lock files. Multiple processes can be spawned off the same app
|
* Name of the lock files. Multiple processes can be spawned off the same app
|
||||||
* and we need to guarantee that at most one unpacks files at any time. To
|
* and we need to guarantee that at most one unpacks files at any time. To
|
||||||
@ -141,10 +147,10 @@ public class UnpackingJSBundleLoader extends JSBundleLoader {
|
|||||||
@Override
|
@Override
|
||||||
public void loadScript(CatalystInstanceImpl instance) {
|
public void loadScript(CatalystInstanceImpl instance) {
|
||||||
prepare();
|
prepare();
|
||||||
// TODO(12128379): add instance method that would take bundle directory
|
instance.loadScriptFromOptimizedBundle(
|
||||||
instance.loadScriptFromFile(
|
mDirectoryPath.getPath(),
|
||||||
new File(mDirectoryPath, "bundle.js").getPath(),
|
mSourceURL,
|
||||||
mSourceURL);
|
UNPACKED_JS_SOURCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -13,8 +13,6 @@
|
|||||||
#include <jni/Countable.h>
|
#include <jni/Countable.h>
|
||||||
#include <jni/LocalReference.h>
|
#include <jni/LocalReference.h>
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#include <cxxreact/Instance.h>
|
#include <cxxreact/Instance.h>
|
||||||
#include <cxxreact/MethodCall.h>
|
#include <cxxreact/MethodCall.h>
|
||||||
#include <cxxreact/ModuleRegistry.h>
|
#include <cxxreact/ModuleRegistry.h>
|
||||||
@ -25,7 +23,6 @@
|
|||||||
#include "ModuleRegistryHolder.h"
|
#include "ModuleRegistryHolder.h"
|
||||||
#include "NativeArray.h"
|
#include "NativeArray.h"
|
||||||
#include "JNativeRunnable.h"
|
#include "JNativeRunnable.h"
|
||||||
#include "OnLoad.h"
|
|
||||||
|
|
||||||
using namespace facebook::jni;
|
using namespace facebook::jni;
|
||||||
|
|
||||||
@ -101,9 +98,11 @@ void CatalystInstanceImpl::registerNatives() {
|
|||||||
makeNativeMethod("initHybrid", CatalystInstanceImpl::initHybrid),
|
makeNativeMethod("initHybrid", CatalystInstanceImpl::initHybrid),
|
||||||
makeNativeMethod("initializeBridge", CatalystInstanceImpl::initializeBridge),
|
makeNativeMethod("initializeBridge", CatalystInstanceImpl::initializeBridge),
|
||||||
makeNativeMethod("loadScriptFromAssets",
|
makeNativeMethod("loadScriptFromAssets",
|
||||||
"(Landroid/content/res/AssetManager;Ljava/lang/String;Z)V",
|
"(Landroid/content/res/AssetManager;Ljava/lang/String;)V",
|
||||||
CatalystInstanceImpl::loadScriptFromAssets),
|
CatalystInstanceImpl::loadScriptFromAssets),
|
||||||
makeNativeMethod("loadScriptFromFile", CatalystInstanceImpl::loadScriptFromFile),
|
makeNativeMethod("loadScriptFromFile", CatalystInstanceImpl::loadScriptFromFile),
|
||||||
|
makeNativeMethod("loadScriptFromOptimizedBundle",
|
||||||
|
CatalystInstanceImpl::loadScriptFromOptimizedBundle),
|
||||||
makeNativeMethod("callJSFunction", CatalystInstanceImpl::callJSFunction),
|
makeNativeMethod("callJSFunction", CatalystInstanceImpl::callJSFunction),
|
||||||
makeNativeMethod("callJSCallback", CatalystInstanceImpl::callJSCallback),
|
makeNativeMethod("callJSCallback", CatalystInstanceImpl::callJSCallback),
|
||||||
makeNativeMethod("getMainExecutorToken", CatalystInstanceImpl::getMainExecutorToken),
|
makeNativeMethod("getMainExecutorToken", CatalystInstanceImpl::getMainExecutorToken),
|
||||||
@ -152,131 +151,20 @@ void CatalystInstanceImpl::initializeBridge(
|
|||||||
mrh->getModuleRegistry());
|
mrh->getModuleRegistry());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_FBJSCEXTENSIONS
|
|
||||||
static std::unique_ptr<const JSBigString> loadScriptFromCache(
|
|
||||||
AAssetManager* manager,
|
|
||||||
std::string& sourceURL) {
|
|
||||||
|
|
||||||
// 20-byte sha1 as hex
|
|
||||||
static const size_t HASH_STR_SIZE = 40;
|
|
||||||
|
|
||||||
// load bundle hash from the metadata file in the APK
|
|
||||||
auto hash = react::loadScriptFromAssets(manager, sourceURL + ".meta");
|
|
||||||
auto cacheDir = getApplicationCacheDir() + "/rn-bundle";
|
|
||||||
auto encoding = static_cast<JSBigMmapString::Encoding>(hash->c_str()[20]);
|
|
||||||
|
|
||||||
if (mkdir(cacheDir.c_str(), 0755) == -1 && errno != EEXIST) {
|
|
||||||
throw std::runtime_error("Can't create cache directory");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (encoding != JSBigMmapString::Encoding::Ascii) {
|
|
||||||
throw std::runtime_error("Can't use mmap fastpath for non-ascii bundles");
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert hash to string
|
|
||||||
char hashStr[HASH_STR_SIZE + 1];
|
|
||||||
for (size_t i = 0; i < HASH_STR_SIZE; i += 2) {
|
|
||||||
snprintf(hashStr + i, 3, "%02hhx", hash->c_str()[i / 2] & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
// the name of the cached bundle file should be the hash
|
|
||||||
std::string cachePath = cacheDir + "/" + hashStr;
|
|
||||||
FILE *cache = fopen(cachePath.c_str(), "r");
|
|
||||||
SCOPE_EXIT { if (cache) fclose(cache); };
|
|
||||||
|
|
||||||
size_t size = 0;
|
|
||||||
if (cache == NULL) {
|
|
||||||
// delete old bundle, if there was one.
|
|
||||||
std::string metaPath = cacheDir + "/meta";
|
|
||||||
if (auto meta = fopen(metaPath.c_str(), "r")) {
|
|
||||||
char oldBundleHash[HASH_STR_SIZE + 1];
|
|
||||||
if (fread(oldBundleHash, HASH_STR_SIZE, 1, meta) == HASH_STR_SIZE) {
|
|
||||||
remove((cacheDir + "/" + oldBundleHash).c_str());
|
|
||||||
remove(metaPath.c_str());
|
|
||||||
}
|
|
||||||
fclose(meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
// load script from the APK and write to temporary file
|
|
||||||
auto script = react::loadScriptFromAssets(manager, sourceURL);
|
|
||||||
auto tmpPath = cachePath + "_";
|
|
||||||
cache = fopen(tmpPath.c_str(), "w");
|
|
||||||
if (!cache) {
|
|
||||||
throw std::runtime_error("Can't open cache, errno: " + errno);
|
|
||||||
}
|
|
||||||
if (fwrite(script->c_str(), 1, script->size(), cache) != size) {
|
|
||||||
remove(tmpPath.c_str());
|
|
||||||
throw std::runtime_error("Failed to unpack bundle");
|
|
||||||
}
|
|
||||||
|
|
||||||
// force data to be written to disk
|
|
||||||
fsync(fileno(cache));
|
|
||||||
fclose(cache);
|
|
||||||
|
|
||||||
// move script to final path - atomic operation
|
|
||||||
if (rename(tmpPath.c_str(), cachePath.c_str())) {
|
|
||||||
throw std::runtime_error("Failed to update cache, errno: " + errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
// store the bundle hash in a metadata file
|
|
||||||
auto meta = fopen(metaPath.c_str(), "w");
|
|
||||||
if (!meta) {
|
|
||||||
throw std::runtime_error("Failed to open metadata file to store bundle hash");
|
|
||||||
}
|
|
||||||
if (fwrite(hashStr, HASH_STR_SIZE, 1, meta) != HASH_STR_SIZE) {
|
|
||||||
throw std::runtime_error("Failed to write bundle hash to metadata file");
|
|
||||||
}
|
|
||||||
fsync(fileno(meta));
|
|
||||||
fclose(meta);
|
|
||||||
|
|
||||||
// return the final written cache
|
|
||||||
cache = fopen(cachePath.c_str(), "r");
|
|
||||||
if (!cache) {
|
|
||||||
throw std::runtime_error("Cache has been cleared");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
struct stat fileInfo = {0};
|
|
||||||
if (fstat(fileno(cache), &fileInfo)) {
|
|
||||||
throw std::runtime_error("Failed to get cache stats, errno: " + errno);
|
|
||||||
}
|
|
||||||
size = fileInfo.st_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return folly::make_unique<const JSBigMmapString>(
|
|
||||||
dup(fileno(cache)),
|
|
||||||
size,
|
|
||||||
reinterpret_cast<const uint8_t*>(hash->c_str()),
|
|
||||||
encoding);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void CatalystInstanceImpl::loadScriptFromAssets(jobject assetManager,
|
void CatalystInstanceImpl::loadScriptFromAssets(jobject assetManager,
|
||||||
const std::string& assetURL,
|
const std::string& assetURL) {
|
||||||
bool useLazyBundle) {
|
|
||||||
const int kAssetsLength = 9; // strlen("assets://");
|
const int kAssetsLength = 9; // strlen("assets://");
|
||||||
auto sourceURL = assetURL.substr(kAssetsLength);
|
auto sourceURL = assetURL.substr(kAssetsLength);
|
||||||
auto manager = react::extractAssetManager(assetManager);
|
|
||||||
|
|
||||||
|
auto manager = react::extractAssetManager(assetManager);
|
||||||
|
auto script = react::loadScriptFromAssets(manager, sourceURL);
|
||||||
if (JniJSModulesUnbundle::isUnbundle(manager, sourceURL)) {
|
if (JniJSModulesUnbundle::isUnbundle(manager, sourceURL)) {
|
||||||
auto script = react::loadScriptFromAssets(manager, sourceURL);
|
|
||||||
instance_->loadUnbundle(
|
instance_->loadUnbundle(
|
||||||
folly::make_unique<JniJSModulesUnbundle>(manager, sourceURL),
|
folly::make_unique<JniJSModulesUnbundle>(manager, sourceURL),
|
||||||
std::move(script),
|
std::move(script),
|
||||||
sourceURL);
|
sourceURL);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
#ifdef WITH_FBJSCEXTENSIONS
|
|
||||||
if (useLazyBundle) {
|
|
||||||
try {
|
|
||||||
auto script = loadScriptFromCache(manager, sourceURL);
|
|
||||||
instance_->loadScriptFromString(std::move(script), sourceURL);
|
|
||||||
return;
|
|
||||||
} catch (...) {
|
|
||||||
LOG(WARNING) << "Failed to load bundle as Source Code";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
auto script = react::loadScriptFromAssets(manager, sourceURL);
|
|
||||||
instance_->loadScriptFromString(std::move(script), sourceURL);
|
instance_->loadScriptFromString(std::move(script), sourceURL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -287,6 +175,14 @@ void CatalystInstanceImpl::loadScriptFromFile(jni::alias_ref<jstring> fileName,
|
|||||||
sourceURL);
|
sourceURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CatalystInstanceImpl::loadScriptFromOptimizedBundle(const std::string& bundlePath,
|
||||||
|
const std::string& sourceURL,
|
||||||
|
jint flags) {
|
||||||
|
return instance_->loadScriptFromOptimizedBundle(std::move(bundlePath),
|
||||||
|
std::move(sourceURL),
|
||||||
|
flags);
|
||||||
|
}
|
||||||
|
|
||||||
void CatalystInstanceImpl::callJSFunction(
|
void CatalystInstanceImpl::callJSFunction(
|
||||||
JExecutorToken* token, std::string module, std::string method, NativeArray* arguments) {
|
JExecutorToken* token, std::string module, std::string method, NativeArray* arguments) {
|
||||||
// We want to share the C++ code, and on iOS, modules pass module/method
|
// We want to share the C++ code, and on iOS, modules pass module/method
|
||||||
|
@ -47,8 +47,9 @@ class CatalystInstanceImpl : public jni::HybridClass<CatalystInstanceImpl> {
|
|||||||
jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue,
|
jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue,
|
||||||
jni::alias_ref<JavaMessageQueueThread::javaobject> moduleQueue,
|
jni::alias_ref<JavaMessageQueueThread::javaobject> moduleQueue,
|
||||||
ModuleRegistryHolder* mrh);
|
ModuleRegistryHolder* mrh);
|
||||||
void loadScriptFromAssets(jobject assetManager, const std::string& assetURL, bool useLazyBundle);
|
void loadScriptFromAssets(jobject assetManager, const std::string& assetURL);
|
||||||
void loadScriptFromFile(jni::alias_ref<jstring> fileName, const std::string& sourceURL);
|
void loadScriptFromFile(jni::alias_ref<jstring> fileName, const std::string& sourceURL);
|
||||||
|
void loadScriptFromOptimizedBundle(const std::string& bundlePath, const std::string& sourceURL, jint flags);
|
||||||
void callJSFunction(JExecutorToken* token, std::string module, std::string method, NativeArray* arguments);
|
void callJSFunction(JExecutorToken* token, std::string module, std::string method, NativeArray* arguments);
|
||||||
void callJSCallback(JExecutorToken* token, jint callbackId, NativeArray* arguments);
|
void callJSCallback(JExecutorToken* token, jint callbackId, NativeArray* arguments);
|
||||||
local_ref<JExecutorToken::JavaPart> getMainExecutorToken();
|
local_ref<JExecutorToken::JavaPart> getMainExecutorToken();
|
||||||
|
@ -51,6 +51,10 @@ static std::string getApplicationDir(const char* methodName) {
|
|||||||
return getAbsolutePathMethod(dirObj)->toStdString();
|
return getAbsolutePathMethod(dirObj)->toStdString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string getApplicationCacheDir() {
|
||||||
|
return getApplicationDir("getCacheDir");
|
||||||
|
}
|
||||||
|
|
||||||
static std::string getApplicationPersistentDir() {
|
static std::string getApplicationPersistentDir() {
|
||||||
return getApplicationDir("getFilesDir");
|
return getApplicationDir("getFilesDir");
|
||||||
}
|
}
|
||||||
@ -158,10 +162,6 @@ class JReactMarker : public JavaClass<JReactMarker> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getApplicationCacheDir() {
|
|
||||||
return getApplicationDir("getCacheDir");
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||||
return initialize(vm, [] {
|
return initialize(vm, [] {
|
||||||
// Inject some behavior into react/
|
// Inject some behavior into react/
|
||||||
|
@ -10,6 +10,5 @@ namespace facebook {
|
|||||||
namespace react {
|
namespace react {
|
||||||
|
|
||||||
jmethodID getLogMarkerMethod();
|
jmethodID getLogMarkerMethod();
|
||||||
std::string getApplicationCacheDir();
|
|
||||||
} // namespace react
|
} // namespace react
|
||||||
} // namespace facebook
|
} // namespace facebook
|
||||||
|
@ -102,9 +102,10 @@ public class UnpackingJSBundleLoaderTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testCallsAppropriateInstanceMethod() throws IOException {
|
public void testCallsAppropriateInstanceMethod() throws IOException {
|
||||||
mBuilder.build().loadScript(mCatalystInstanceImpl);
|
mBuilder.build().loadScript(mCatalystInstanceImpl);
|
||||||
verify(mCatalystInstanceImpl).loadScriptFromFile(
|
verify(mCatalystInstanceImpl).loadScriptFromOptimizedBundle(
|
||||||
eq(new File(mDestinationPath, "bundle.js").getPath()),
|
eq(mDestinationPath.getPath()),
|
||||||
eq(URL));
|
eq(URL),
|
||||||
|
eq(UnpackingJSBundleLoader.UNPACKED_JS_SOURCE));
|
||||||
verifyNoMoreInteractions(mCatalystInstanceImpl);
|
verifyNoMoreInteractions(mCatalystInstanceImpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ include $(CLEAR_VARS)
|
|||||||
LOCAL_MODULE := libreactnativefb
|
LOCAL_MODULE := libreactnativefb
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
|
Executor.cpp \
|
||||||
Instance.cpp \
|
Instance.cpp \
|
||||||
JSCExecutor.cpp \
|
JSCExecutor.cpp \
|
||||||
JSCHelpers.cpp \
|
JSCHelpers.cpp \
|
||||||
|
@ -109,6 +109,7 @@ react_library(
|
|||||||
force_static = True,
|
force_static = True,
|
||||||
srcs = [
|
srcs = [
|
||||||
'CxxMessageQueue.cpp',
|
'CxxMessageQueue.cpp',
|
||||||
|
'Executor.cpp',
|
||||||
'Instance.cpp',
|
'Instance.cpp',
|
||||||
'JSCExecutor.cpp',
|
'JSCExecutor.cpp',
|
||||||
'JSCHelpers.cpp',
|
'JSCHelpers.cpp',
|
||||||
|
77
ReactCommon/cxxreact/Executor.cpp
Normal file
77
ReactCommon/cxxreact/Executor.cpp
Normal 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
|
@ -16,6 +16,13 @@
|
|||||||
namespace facebook {
|
namespace facebook {
|
||||||
namespace react {
|
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 JSExecutor;
|
||||||
class MessageQueueThread;
|
class MessageQueueThread;
|
||||||
|
|
||||||
@ -190,6 +197,8 @@ public:
|
|||||||
return m_encoding;
|
return m_encoding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<const JSBigMmapString> fromOptimizedBundle(const std::string& bundlePath);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_fd;
|
int m_fd;
|
||||||
size_t m_size;
|
size_t m_size;
|
||||||
@ -206,6 +215,11 @@ public:
|
|||||||
virtual void loadApplicationScript(std::unique_ptr<const JSBigString> script,
|
virtual void loadApplicationScript(std::unique_ptr<const JSBigString> script,
|
||||||
std::string sourceURL) = 0;
|
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
|
* Add an application "unbundle" file
|
||||||
*/
|
*/
|
||||||
@ -245,4 +259,6 @@ public:
|
|||||||
virtual ~JSExecutor() {}
|
virtual ~JSExecutor() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<const JSBigMmapString> readJSBundle(const std::string& path);
|
||||||
|
|
||||||
} }
|
} }
|
||||||
|
@ -75,6 +75,16 @@ void Instance::loadScriptFromFile(const std::string& filename,
|
|||||||
loadScriptFromString(std::move(buf), sourceURL);
|
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,
|
void Instance::loadUnbundle(std::unique_ptr<JSModulesUnbundle> unbundle,
|
||||||
std::unique_ptr<const JSBigString> startupScript,
|
std::unique_ptr<const JSBigString> startupScript,
|
||||||
std::string startupScriptSourceURL) {
|
std::string startupScriptSourceURL) {
|
||||||
|
@ -36,6 +36,7 @@ class Instance {
|
|||||||
std::shared_ptr<ModuleRegistry> moduleRegistry);
|
std::shared_ptr<ModuleRegistry> moduleRegistry);
|
||||||
void loadScriptFromString(std::unique_ptr<const JSBigString> string, std::string sourceURL);
|
void loadScriptFromString(std::unique_ptr<const JSBigString> string, std::string sourceURL);
|
||||||
void loadScriptFromFile(const std::string& filename, const 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(
|
void loadUnbundle(
|
||||||
std::unique_ptr<JSModulesUnbundle> unbundle,
|
std::unique_ptr<JSModulesUnbundle> unbundle,
|
||||||
std::unique_ptr<const JSBigString> startupScript,
|
std::unique_ptr<const JSBigString> startupScript,
|
||||||
|
@ -254,15 +254,37 @@ void JSCExecutor::terminateOnJSVMThread() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_FBJSCEXTENSIONS
|
#ifdef WITH_FBJSCEXTENSIONS
|
||||||
static void loadApplicationSource(
|
void JSCExecutor::loadApplicationScript(
|
||||||
const JSGlobalContextRef context,
|
std::string bundlePath,
|
||||||
const JSBigMmapString* script,
|
std::string sourceURL,
|
||||||
const 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) {
|
||||||
|
throw std::runtime_error("Optimized bundle needs to be ascii encoded");
|
||||||
|
}
|
||||||
|
|
||||||
String jsSourceURL(sourceURL.c_str());
|
String jsSourceURL(sourceURL.c_str());
|
||||||
bool is8bit = script->encoding() == JSBigMmapString::Encoding::Ascii || script->encoding() == JSBigMmapString::Encoding::Utf8;
|
JSSourceCodeRef sourceCode = JSCreateSourceCode(
|
||||||
JSSourceCodeRef sourceCode = JSCreateSourceCode(script->fd(), script->size(), jsSourceURL, script->hash(), is8bit);
|
jsScriptBigString->fd(),
|
||||||
evaluateSourceCode(context, sourceCode, jsSourceURL);
|
jsScriptBigString->size(),
|
||||||
JSReleaseSourceCode(sourceCode);
|
jsSourceURL,
|
||||||
|
jsScriptBigString->hash(),
|
||||||
|
true);
|
||||||
|
SCOPE_EXIT { JSReleaseSourceCode(sourceCode); };
|
||||||
|
|
||||||
|
evaluateSourceCode(m_context, sourceCode, jsSourceURL);
|
||||||
|
|
||||||
|
bindBridge();
|
||||||
|
|
||||||
|
flush();
|
||||||
|
ReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -270,16 +292,6 @@ void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> scrip
|
|||||||
SystraceSection s("JSCExecutor::loadApplicationScript",
|
SystraceSection s("JSCExecutor::loadApplicationScript",
|
||||||
"sourceURL", sourceURL);
|
"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
|
#ifdef WITH_FBSYSTRACE
|
||||||
fbsystrace_begin_section(
|
fbsystrace_begin_section(
|
||||||
TRACE_TAG_REACT_CXX_BRIDGE,
|
TRACE_TAG_REACT_CXX_BRIDGE,
|
||||||
|
@ -59,6 +59,12 @@ public:
|
|||||||
virtual void loadApplicationScript(
|
virtual void loadApplicationScript(
|
||||||
std::unique_ptr<const JSBigString> script,
|
std::unique_ptr<const JSBigString> script,
|
||||||
std::string sourceURL) throw(JSException) override;
|
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(
|
virtual void setJSModulesUnbundle(
|
||||||
std::unique_ptr<JSModulesUnbundle> unbundle) override;
|
std::unique_ptr<JSModulesUnbundle> unbundle) override;
|
||||||
virtual void callFunction(
|
virtual void callFunction(
|
||||||
|
@ -124,6 +124,20 @@ void NativeToJsBridge::loadApplicationScript(std::unique_ptr<const JSBigString>
|
|||||||
m_mainExecutor->loadApplicationScript(std::move(script), std::move(sourceURL));
|
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(
|
void NativeToJsBridge::loadApplicationUnbundle(
|
||||||
std::unique_ptr<JSModulesUnbundle> unbundle,
|
std::unique_ptr<JSModulesUnbundle> unbundle,
|
||||||
std::unique_ptr<const JSBigString> startupScript,
|
std::unique_ptr<const JSBigString> startupScript,
|
||||||
|
@ -84,6 +84,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
void loadApplicationScript(std::unique_ptr<const JSBigString> script, std::string sourceURL);
|
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
|
* An "unbundle" is a backend that stores and injects JavaScript modules as
|
||||||
* individual scripts, rather than bundling all of them into a single scrupt.
|
* individual scripts, rather than bundling all of them into a single scrupt.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user