reformat JSCExecutor.cpp

Reviewed By: fromcelticpark

Differential Revision: D7803913

fbshipit-source-id: fc4637d0f9ab8c01f2f257e34e435c9573ecf948
This commit is contained in:
Marc Horowitz 2018-05-09 22:01:48 -07:00 committed by Facebook Github Bot
parent d1d09c208a
commit 09f3d7ab49
1 changed files with 658 additions and 581 deletions

View File

@ -2,22 +2,22 @@
#include "JSCExecutor.h" #include "JSCExecutor.h"
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <algorithm> #include <algorithm>
#include <condition_variable> #include <condition_variable>
#include <fcntl.h>
#include <mutex> #include <mutex>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <sys/time.h>
#include <sys/socket.h>
#include <system_error> #include <system_error>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <folly/Conv.h> #include <folly/Conv.h>
#include <folly/Exception.h> #include <folly/Exception.h>
#include <folly/json.h>
#include <folly/Memory.h> #include <folly/Memory.h>
#include <folly/String.h> #include <folly/String.h>
#include <folly/json.h>
#include <glog/logging.h> #include <glog/logging.h>
#include <jschelpers/JSCHelpers.h> #include <jschelpers/JSCHelpers.h>
#include <jschelpers/Value.h> #include <jschelpers/Value.h>
@ -60,7 +60,8 @@ namespace facebook {
JSValueRef* exception) { JSValueRef* exception) {
try { try {
auto executor = Object::getGlobalObject(ctx).getPrivate<JSCExecutor>(); auto executor = Object::getGlobalObject(ctx).getPrivate<JSCExecutor>();
if (executor && executor->getJavaScriptContext()) { // Executor not invalidated if (executor &&
executor->getJavaScriptContext()) { // Executor not invalidated
return (executor->*method)(argumentCount, arguments); return (executor->*method)(argumentCount, arguments);
} }
} catch (...) { } catch (...) {
@ -73,7 +74,8 @@ namespace facebook {
return &funcWrapper::call; return &funcWrapper::call;
} }
template<JSValueRef (JSCExecutor::*method)(JSObjectRef object, JSStringRef propertyName)> template <JSValueRef (
JSCExecutor::*method)(JSObjectRef object, JSStringRef propertyName)>
inline JSObjectGetPropertyCallback exceptionWrapMethod() { inline JSObjectGetPropertyCallback exceptionWrapMethod() {
struct funcWrapper { struct funcWrapper {
static JSValueRef call( static JSValueRef call(
@ -83,7 +85,8 @@ namespace facebook {
JSValueRef* exception) { JSValueRef* exception) {
try { try {
auto executor = Object::getGlobalObject(ctx).getPrivate<JSCExecutor>(); auto executor = Object::getGlobalObject(ctx).getPrivate<JSCExecutor>();
if (executor && executor->getJavaScriptContext()) { // Executor not invalidated if (executor &&
executor->getJavaScriptContext()) { // Executor not invalidated
return (executor->*method)(object, propertyName); return (executor->*method)(object, propertyName);
} }
} catch (...) { } catch (...) {
@ -96,7 +99,7 @@ namespace facebook {
return &funcWrapper::call; return &funcWrapper::call;
} }
} } // namespace
#if DEBUG #if DEBUG
static JSValueRef nativeInjectHMRUpdate( static JSValueRef nativeInjectHMRUpdate(
@ -114,15 +117,18 @@ namespace facebook {
#endif #endif
std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor( std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(
std::shared_ptr<ExecutorDelegate> delegate, std::shared_ptr<MessageQueueThread> jsQueue) { std::shared_ptr<ExecutorDelegate> delegate,
return folly::make_unique<JSCExecutor>(delegate, jsQueue, m_jscConfig, m_nativeExtensionsProvider); std::shared_ptr<MessageQueueThread> jsQueue) {
return folly::make_unique<JSCExecutor>(
delegate, jsQueue, m_jscConfig, m_nativeExtensionsProvider);
} }
JSCExecutor::JSCExecutor(std::shared_ptr<ExecutorDelegate> delegate, JSCExecutor::JSCExecutor(
std::shared_ptr<ExecutorDelegate> delegate,
std::shared_ptr<MessageQueueThread> messageQueueThread, std::shared_ptr<MessageQueueThread> messageQueueThread,
const folly::dynamic& jscConfig, const folly::dynamic& jscConfig,
NativeExtensionsProvider nativeExtensionsProvider) throw(JSException) : NativeExtensionsProvider nativeExtensionsProvider) throw(JSException)
m_delegate(delegate), : m_delegate(delegate),
m_messageQueueThread(messageQueueThread), m_messageQueueThread(messageQueueThread),
m_nativeModules(delegate ? delegate->getModuleRegistry() : nullptr), m_nativeModules(delegate ? delegate->getModuleRegistry() : nullptr),
m_jscConfig(jscConfig), m_jscConfig(jscConfig),
@ -131,25 +137,28 @@ namespace facebook {
{ {
SystraceSection s("nativeModuleProxy object"); SystraceSection s("nativeModuleProxy object");
installGlobalProxy(m_context, "nativeModuleProxy", installGlobalProxy(
m_context,
"nativeModuleProxy",
exceptionWrapMethod<&JSCExecutor::getNativeModule>()); exceptionWrapMethod<&JSCExecutor::getNativeModule>());
} }
if (nativeExtensionsProvider) { if (nativeExtensionsProvider) {
installGlobalProxy(m_context, "nativeExtensions", installGlobalProxy(
m_context,
"nativeExtensions",
exceptionWrapMethod<&JSCExecutor::getNativeExtension>()); exceptionWrapMethod<&JSCExecutor::getNativeExtension>());
} }
} }
JSCExecutor::~JSCExecutor() { JSCExecutor::~JSCExecutor() {
CHECK(*m_isDestroyed) << "JSCExecutor::destroy() must be called before its destructor!"; CHECK(*m_isDestroyed)
<< "JSCExecutor::destroy() must be called before its destructor!";
} }
void JSCExecutor::destroy() { void JSCExecutor::destroy() {
*m_isDestroyed = true; *m_isDestroyed = true;
if (m_messageQueueThread.get()) { if (m_messageQueueThread.get()) {
m_messageQueueThread->runOnQueueSync([this] () { m_messageQueueThread->runOnQueueSync([this]() { terminateOnJSVMThread(); });
terminateOnJSVMThread();
});
} else { } else {
terminateOnJSVMThread(); terminateOnJSVMThread();
} }
@ -184,7 +193,8 @@ namespace facebook {
SystraceSection s("JSCExecutor::initOnJSVMThread"); SystraceSection s("JSCExecutor::initOnJSVMThread");
#if defined(__APPLE__) #if defined(__APPLE__)
const bool useCustomJSC = m_jscConfig.getDefault("UseCustomJSC", false).getBool(); const bool useCustomJSC =
m_jscConfig.getDefault("UseCustomJSC", false).getBool();
if (useCustomJSC) { if (useCustomJSC) {
JSC_configureJSCForIOS(true, toJson(m_jscConfig)); JSC_configureJSCForIOS(true, toJson(m_jscConfig));
} }
@ -196,7 +206,8 @@ namespace facebook {
configureJSCForAndroid(m_jscConfig); configureJSCForAndroid(m_jscConfig);
#endif #endif
// Create a custom global class, so we can store data in it later using JSObjectSetPrivate // Create a custom global class, so we can store data in it later using
// JSObjectSetPrivate
JSClassRef globalClass = nullptr; JSClassRef globalClass = nullptr;
{ {
SystraceSection s_("JSClassCreate"); SystraceSection s_("JSClassCreate");
@ -206,7 +217,8 @@ namespace facebook {
} }
{ {
SystraceSection s_("JSGlobalContextCreateInGroup"); SystraceSection s_("JSGlobalContextCreateInGroup");
m_context = JSC_JSGlobalContextCreateInGroup(useCustomJSC, nullptr, globalClass); m_context =
JSC_JSGlobalContextCreateInGroup(useCustomJSC, nullptr, globalClass);
} }
JSC_JSClassRelease(useCustomJSC, globalClass); JSC_JSClassRelease(useCustomJSC, globalClass);
@ -214,25 +226,33 @@ namespace facebook {
Object::getGlobalObject(m_context).setPrivate(this); Object::getGlobalObject(m_context).setPrivate(this);
if (canUseInspector(m_context)) { if (canUseInspector(m_context)) {
const std::string ownerId = m_jscConfig.getDefault("OwnerIdentity", "unknown").getString(); const std::string ownerId =
const std::string appId = m_jscConfig.getDefault("AppIdentity", "unknown").getString(); m_jscConfig.getDefault("OwnerIdentity", "unknown").getString();
const std::string deviceId = m_jscConfig.getDefault("DeviceIdentity", "unknown").getString(); const std::string appId =
m_jscConfig.getDefault("AppIdentity", "unknown").getString();
const std::string deviceId =
m_jscConfig.getDefault("DeviceIdentity", "unknown").getString();
auto checkIsInspectedRemote = [ownerId, appId, deviceId]() { auto checkIsInspectedRemote = [ownerId, appId, deviceId]() {
return isNetworkInspected(ownerId, appId, deviceId); return isNetworkInspected(ownerId, appId, deviceId);
}; };
auto& globalInspector = facebook::react::getInspectorInstance(); auto& globalInspector = facebook::react::getInspectorInstance();
JSC_JSGlobalContextEnableDebugger(m_context, globalInspector, ownerId.c_str(), checkIsInspectedRemote); JSC_JSGlobalContextEnableDebugger(
m_context, globalInspector, ownerId.c_str(), checkIsInspectedRemote);
} }
installNativeHook<&JSCExecutor::nativeFlushQueueImmediate>("nativeFlushQueueImmediate"); installNativeHook<&JSCExecutor::nativeFlushQueueImmediate>(
"nativeFlushQueueImmediate");
installNativeHook<&JSCExecutor::nativeCallSyncHook>("nativeCallSyncHook"); installNativeHook<&JSCExecutor::nativeCallSyncHook>("nativeCallSyncHook");
installGlobalFunction(m_context, "nativeLoggingHook", JSCNativeHooks::loggingHook); installGlobalFunction(
installGlobalFunction(m_context, "nativePerformanceNow", JSCNativeHooks::nowHook); m_context, "nativeLoggingHook", JSCNativeHooks::loggingHook);
installGlobalFunction(
m_context, "nativePerformanceNow", JSCNativeHooks::nowHook);
#if DEBUG #if DEBUG
installGlobalFunction(m_context, "nativeInjectHMRUpdate", nativeInjectHMRUpdate); installGlobalFunction(
m_context, "nativeInjectHMRUpdate", nativeInjectHMRUpdate);
#endif #endif
addNativeTracingHooks(m_context); addNativeTracingHooks(m_context);
@ -247,7 +267,10 @@ namespace facebook {
} }
} }
bool JSCExecutor::isNetworkInspected(const std::string &owner, const std::string &app, const std::string &device) { bool JSCExecutor::isNetworkInspected(
const std::string& owner,
const std::string& app,
const std::string& device) {
#ifdef WITH_FB_DBG_ATTACH_BEFORE_EXEC #ifdef WITH_FB_DBG_ATTACH_BEFORE_EXEC
auto connect_socket = [](int socket_desc, std::string address, int port) { auto connect_socket = [](int socket_desc, std::string address, int port) {
if (socket_desc < 0) { if (socket_desc < 0) {
@ -258,13 +281,23 @@ namespace facebook {
struct timeval tv; struct timeval tv;
tv.tv_sec = 1; tv.tv_sec = 1;
tv.tv_usec = 0; tv.tv_usec = 0;
auto sock_opt_rcv_resp = setsockopt(socket_desc, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(struct timeval)); auto sock_opt_rcv_resp = setsockopt(
socket_desc,
SOL_SOCKET,
SO_RCVTIMEO,
(const char*)&tv,
sizeof(struct timeval));
if (sock_opt_rcv_resp < 0) { if (sock_opt_rcv_resp < 0) {
::close(socket_desc); ::close(socket_desc);
return false; return false;
} }
auto sock_opt_snd_resp = setsockopt(socket_desc, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof(struct timeval)); auto sock_opt_snd_resp = setsockopt(
socket_desc,
SOL_SOCKET,
SO_SNDTIMEO,
(const char*)&tv,
sizeof(struct timeval));
if (sock_opt_snd_resp < 0) { if (sock_opt_snd_resp < 0) {
::close(socket_desc); ::close(socket_desc);
return false; return false;
@ -274,7 +307,8 @@ namespace facebook {
server.sin_addr.s_addr = inet_addr(address.c_str()); server.sin_addr.s_addr = inet_addr(address.c_str());
server.sin_family = AF_INET; server.sin_family = AF_INET;
server.sin_port = htons(port); server.sin_port = htons(port);
auto connect_resp = ::connect(socket_desc, (struct sockaddr *)&server, sizeof(server)); auto connect_resp =
::connect(socket_desc, (struct sockaddr*)&server, sizeof(server));
if (connect_resp < 0) { if (connect_resp < 0) {
::close(socket_desc); ::close(socket_desc);
return false; return false;
@ -299,13 +333,19 @@ namespace facebook {
#endif // defined(__ANDROID__) #endif // defined(__ANDROID__)
} }
std::string escapedOwner = folly::uriEscape<std::string>(owner, folly::UriEscapeMode::QUERY); std::string escapedOwner =
std::string escapedApp = folly::uriEscape<std::string>(app, folly::UriEscapeMode::QUERY); folly::uriEscape<std::string>(owner, folly::UriEscapeMode::QUERY);
std::string escapedDevice = folly::uriEscape<std::string>(device, folly::UriEscapeMode::QUERY); std::string escapedApp =
folly::uriEscape<std::string>(app, folly::UriEscapeMode::QUERY);
std::string escapedDevice =
folly::uriEscape<std::string>(device, folly::UriEscapeMode::QUERY);
std::string msg = folly::to<std::string>( std::string msg = folly::to<std::string>(
"GET /autoattach?title=", escapedOwner, "GET /autoattach?title=",
"&app=" , escapedApp, escapedOwner,
"&device=" , escapedDevice, "&app=",
escapedApp,
"&device=",
escapedDevice,
" HTTP/1.1\r\n\r\n"); " HTTP/1.1\r\n\r\n");
auto send_resp = ::send(socket_desc, msg.c_str(), msg.length(), 0); auto send_resp = ::send(socket_desc, msg.c_str(), msg.length(), 0);
if (send_resp < 0) { if (send_resp < 0) {
@ -315,8 +355,8 @@ namespace facebook {
char server_reply[200]; char server_reply[200];
server_reply[199] = '\0'; server_reply[199] = '\0';
auto recv_resp = ::recv(socket_desc, server_reply, auto recv_resp =
sizeof(server_reply) - 1, 0); ::recv(socket_desc, server_reply, sizeof(server_reply) - 1, 0);
if (recv_resp < 0) { if (recv_resp < 0) {
::close(socket_desc); ::close(socket_desc);
return false; return false;
@ -328,7 +368,8 @@ namespace facebook {
return false; return false;
} }
auto responseCandidate = response.substr(response.size() - 25); auto responseCandidate = response.substr(response.size() - 25);
auto found = responseCandidate.find("{\"autoattach\":true}") != std::string::npos; auto found =
responseCandidate.find("{\"autoattach\":true}") != std::string::npos;
::close(socket_desc); ::close(socket_desc);
return found; return found;
#else //! WITH_FB_DBG_ATTACH_BEFORE_EXEC #else //! WITH_FB_DBG_ATTACH_BEFORE_EXEC
@ -377,12 +418,15 @@ namespace facebook {
return (pos != std::string::npos) ? path.substr(pos) : path; return (pos != std::string::npos) ? path.substr(pos) : path;
} }
void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> script, std::string sourceURL) { void JSCExecutor::loadApplicationScript(
SystraceSection s("JSCExecutor::loadApplicationScript", std::unique_ptr<const JSBigString> script,
"sourceURL", sourceURL); std::string sourceURL) {
SystraceSection s(
"JSCExecutor::loadApplicationScript", "sourceURL", sourceURL);
std::string scriptName = simpleBasename(sourceURL); std::string scriptName = simpleBasename(sourceURL);
ReactMarker::logTaggedMarker(ReactMarker::RUN_JS_BUNDLE_START, scriptName.c_str()); ReactMarker::logTaggedMarker(
ReactMarker::RUN_JS_BUNDLE_START, scriptName.c_str());
String jsSourceURL(m_context, sourceURL.c_str()); String jsSourceURL(m_context, sourceURL.c_str());
// TODO t15069155: reduce the number of overrides here // TODO t15069155: reduce the number of overrides here
@ -390,7 +434,8 @@ namespace facebook {
if (auto fileStr = dynamic_cast<const JSBigFileString*>(script.get())) { if (auto fileStr = dynamic_cast<const JSBigFileString*>(script.get())) {
JSContextLock lock(m_context); JSContextLock lock(m_context);
JSLoadSourceStatus jsStatus; JSLoadSourceStatus jsStatus;
auto bcSourceCode = JSCreateSourceCodeFromFile(fileStr->fd(), jsSourceURL, nullptr, &jsStatus); auto bcSourceCode = JSCreateSourceCodeFromFile(
fileStr->fd(), jsSourceURL, nullptr, &jsStatus);
switch (jsStatus) { switch (jsStatus) {
case JSLoadSourceIsCompiled: case JSLoadSourceIsCompiled:
@ -402,7 +447,8 @@ namespace facebook {
flush(); flush();
ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP); ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP);
ReactMarker::logTaggedMarker(ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str()); ReactMarker::logTaggedMarker(
ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str());
return; return;
case JSLoadSourceErrorVersionMismatch: case JSLoadSourceErrorVersionMismatch:
@ -416,7 +462,8 @@ namespace facebook {
} }
#elif defined(__APPLE__) #elif defined(__APPLE__)
BundleHeader header; BundleHeader header;
memcpy(&header, script->c_str(), std::min(script->size(), sizeof(BundleHeader))); memcpy(
&header, script->c_str(), std::min(script->size(), sizeof(BundleHeader)));
auto scriptTag = parseTypeFromHeader(header); auto scriptTag = parseTypeFromHeader(header);
if (scriptTag == ScriptTag::BCBundle) { if (scriptTag == ScriptTag::BCBundle) {
@ -425,7 +472,8 @@ namespace facebook {
int sourceFD = fileno(source.get()); int sourceFD = fileno(source.get());
JSValueRef jsError; JSValueRef jsError;
JSValueRef result = JSC_JSEvaluateBytecodeBundle(m_context, NULL, sourceFD, jsSourceURL, &jsError); JSValueRef result = JSC_JSEvaluateBytecodeBundle(
m_context, NULL, sourceFD, jsSourceURL, &jsError);
if (result == nullptr) { if (result == nullptr) {
throw JSException(m_context, jsError, jsSourceURL); throw JSException(m_context, jsError, jsSourceURL);
} }
@ -435,7 +483,8 @@ namespace facebook {
String jsScript; String jsScript;
JSContextLock lock(m_context); JSContextLock lock(m_context);
{ {
SystraceSection s_("JSCExecutor::loadApplicationScript-createExpectingAscii"); SystraceSection s_(
"JSCExecutor::loadApplicationScript-createExpectingAscii");
ReactMarker::logMarker(ReactMarker::JS_BUNDLE_STRING_CONVERT_START); ReactMarker::logMarker(ReactMarker::JS_BUNDLE_STRING_CONVERT_START);
jsScript = adoptString(std::move(script)); jsScript = adoptString(std::move(script));
ReactMarker::logMarker(ReactMarker::JS_BUNDLE_STRING_CONVERT_STOP); ReactMarker::logMarker(ReactMarker::JS_BUNDLE_STRING_CONVERT_STOP);
@ -448,10 +497,12 @@ namespace facebook {
flush(); flush();
ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP); ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP);
ReactMarker::logTaggedMarker(ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str()); ReactMarker::logTaggedMarker(
ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str());
} }
void JSCExecutor::setBundleRegistry(std::unique_ptr<RAMBundleRegistry> bundleRegistry) { void JSCExecutor::setBundleRegistry(
std::unique_ptr<RAMBundleRegistry> bundleRegistry) {
if (!m_bundleRegistry) { if (!m_bundleRegistry) {
installNativeHook<&JSCExecutor::nativeRequire>("nativeRequire"); installNativeHook<&JSCExecutor::nativeRequire>("nativeRequire");
} }
@ -477,20 +528,27 @@ namespace facebook {
auto global = Object::getGlobalObject(m_context); auto global = Object::getGlobalObject(m_context);
auto batchedBridgeValue = global.getProperty("__fbBatchedBridge"); auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");
if (batchedBridgeValue.isUndefined()) { if (batchedBridgeValue.isUndefined()) {
auto requireBatchedBridge = global.getProperty("__fbRequireBatchedBridge"); auto requireBatchedBridge =
global.getProperty("__fbRequireBatchedBridge");
if (!requireBatchedBridge.isUndefined()) { if (!requireBatchedBridge.isUndefined()) {
batchedBridgeValue = requireBatchedBridge.asObject().callAsFunction({}); batchedBridgeValue = requireBatchedBridge.asObject().callAsFunction({});
} }
if (batchedBridgeValue.isUndefined()) { if (batchedBridgeValue.isUndefined()) {
throw JSException("Could not get BatchedBridge, make sure your bundle is packaged correctly"); throw JSException(
"Could not get BatchedBridge, make sure your bundle is packaged correctly");
} }
} }
auto batchedBridge = batchedBridgeValue.asObject(); auto batchedBridge = batchedBridgeValue.asObject();
m_callFunctionReturnFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnFlushedQueue").asObject(); m_callFunctionReturnFlushedQueueJS =
m_invokeCallbackAndReturnFlushedQueueJS = batchedBridge.getProperty("invokeCallbackAndReturnFlushedQueue").asObject(); batchedBridge.getProperty("callFunctionReturnFlushedQueue").asObject();
m_invokeCallbackAndReturnFlushedQueueJS =
batchedBridge.getProperty("invokeCallbackAndReturnFlushedQueue")
.asObject();
m_flushedQueueJS = batchedBridge.getProperty("flushedQueue").asObject(); m_flushedQueueJS = batchedBridge.getProperty("flushedQueue").asObject();
m_callFunctionReturnResultAndFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnResultAndFlushedQueue").asObject(); m_callFunctionReturnResultAndFlushedQueueJS =
batchedBridge.getProperty("callFunctionReturnResultAndFlushedQueue")
.asObject();
}); });
} }
@ -543,7 +601,10 @@ namespace facebook {
} }
} }
void JSCExecutor::callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) { void JSCExecutor::callFunction(
const std::string& moduleId,
const std::string& methodId,
const folly::dynamic& arguments) {
SystraceSection s("JSCExecutor::callFunction"); SystraceSection s("JSCExecutor::callFunction");
// This weird pattern is because Value is not default constructible. // This weird pattern is because Value is not default constructible.
// The lambda is inlined, so there's no overhead. // The lambda is inlined, so there's no overhead.
@ -553,11 +614,10 @@ namespace facebook {
if (!m_callFunctionReturnResultAndFlushedQueueJS) { if (!m_callFunctionReturnResultAndFlushedQueueJS) {
bindBridge(); bindBridge();
} }
return m_callFunctionReturnFlushedQueueJS->callAsFunction({ return m_callFunctionReturnFlushedQueueJS->callAsFunction(
Value(m_context, String::createExpectingAscii(m_context, moduleId)), {Value(m_context, String::createExpectingAscii(m_context, moduleId)),
Value(m_context, String::createExpectingAscii(m_context, methodId)), Value(m_context, String::createExpectingAscii(m_context, methodId)),
Value::fromDynamic(m_context, std::move(arguments)) Value::fromDynamic(m_context, std::move(arguments))});
});
} catch (...) { } catch (...) {
std::throw_with_nested( std::throw_with_nested(
std::runtime_error("Error calling " + moduleId + "." + methodId)); std::runtime_error("Error calling " + moduleId + "." + methodId));
@ -566,7 +626,9 @@ namespace facebook {
callNativeModules(std::move(result)); callNativeModules(std::move(result));
} }
void JSCExecutor::invokeCallback(const double callbackId, const folly::dynamic& arguments) { void JSCExecutor::invokeCallback(
const double callbackId,
const folly::dynamic& arguments) {
SystraceSection s("JSCExecutor::invokeCallback"); SystraceSection s("JSCExecutor::invokeCallback");
auto result = [&] { auto result = [&] {
JSContextLock lock(m_context); JSContextLock lock(m_context);
@ -574,25 +636,28 @@ namespace facebook {
if (!m_invokeCallbackAndReturnFlushedQueueJS) { if (!m_invokeCallbackAndReturnFlushedQueueJS) {
bindBridge(); bindBridge();
} }
return m_invokeCallbackAndReturnFlushedQueueJS->callAsFunction({ return m_invokeCallbackAndReturnFlushedQueueJS->callAsFunction(
Value::makeNumber(m_context, callbackId), {Value::makeNumber(m_context, callbackId),
Value::fromDynamic(m_context, std::move(arguments)) Value::fromDynamic(m_context, std::move(arguments))});
});
} catch (...) { } catch (...) {
std::throw_with_nested( std::throw_with_nested(std::runtime_error(
std::runtime_error(folly::to<std::string>("Error invoking callback ", callbackId))); folly::to<std::string>("Error invoking callback ", callbackId)));
} }
}(); }();
callNativeModules(std::move(result)); callNativeModules(std::move(result));
} }
void JSCExecutor::setGlobalVariable(std::string propName, std::unique_ptr<const JSBigString> jsonValue) { void JSCExecutor::setGlobalVariable(
std::string propName,
std::unique_ptr<const JSBigString> jsonValue) {
try { try {
SystraceSection s("JSCExecutor::setGlobalVariable", "propName", propName); SystraceSection s("JSCExecutor::setGlobalVariable", "propName", propName);
auto valueToInject = Value::fromJSON(adoptString(std::move(jsonValue))); auto valueToInject = Value::fromJSON(adoptString(std::move(jsonValue)));
Object::getGlobalObject(m_context).setProperty(propName.c_str(), valueToInject); Object::getGlobalObject(m_context).setProperty(
propName.c_str(), valueToInject);
} catch (...) { } catch (...) {
std::throw_with_nested(std::runtime_error("Error setting global variable: " + propName)); std::throw_with_nested(
std::runtime_error("Error setting global variable: " + propName));
} }
} }
@ -611,7 +676,8 @@ namespace facebook {
String JSCExecutor::adoptString(std::unique_ptr<const JSBigString> script) { String JSCExecutor::adoptString(std::unique_ptr<const JSBigString> script) {
#if defined(WITH_FBJSCEXTENSIONS) #if defined(WITH_FBJSCEXTENSIONS)
const JSBigString* string = script.release(); const JSBigString* string = script.release();
auto jsString = JSStringCreateAdoptingExternal(string->c_str(), string->size(), (void*)string, [](void* s) { auto jsString = JSStringCreateAdoptingExternal(
string->c_str(), string->size(), (void*)string, [](void* s) {
delete static_cast<JSBigString*>(s); delete static_cast<JSBigString*>(s);
}); });
return String::adopt(m_context, jsString); return String::adopt(m_context, jsString);
@ -632,7 +698,8 @@ namespace facebook {
#ifdef WITH_JSC_MEMORY_PRESSURE #ifdef WITH_JSC_MEMORY_PRESSURE
void JSCExecutor::handleMemoryPressure(int pressureLevel) { void JSCExecutor::handleMemoryPressure(int pressureLevel) {
JSHandleMemoryPressure(this, m_context, static_cast<JSMemoryPressure>(pressureLevel)); JSHandleMemoryPressure(
this, m_context, static_cast<JSMemoryPressure>(pressureLevel));
} }
#endif #endif
@ -644,7 +711,8 @@ namespace facebook {
void JSCExecutor::loadModule(uint32_t bundleId, uint32_t moduleId) { void JSCExecutor::loadModule(uint32_t bundleId, uint32_t moduleId) {
auto module = m_bundleRegistry->getModule(bundleId, moduleId); auto module = m_bundleRegistry->getModule(bundleId, moduleId);
auto sourceUrl = String::createExpectingAscii(m_context, module.name); auto sourceUrl = String::createExpectingAscii(m_context, module.name);
auto source = adoptString(std::unique_ptr<JSBigString>(new JSBigStdString(module.code))); auto source = adoptString(
std::unique_ptr<JSBigString>(new JSBigStdString(module.code)));
evaluateScript(m_context, source, sourceUrl); evaluateScript(m_context, source, sourceUrl);
} }
@ -654,7 +722,9 @@ namespace facebook {
installGlobalFunction(m_context, name, exceptionWrapMethod<method>()); installGlobalFunction(m_context, name, exceptionWrapMethod<method>());
} }
JSValueRef JSCExecutor::getNativeModule(JSObjectRef object, JSStringRef propertyName) { JSValueRef JSCExecutor::getNativeModule(
JSObjectRef object,
JSStringRef propertyName) {
if (JSC_JSStringIsEqualToUTF8CString(m_context, propertyName, "name")) { if (JSC_JSStringIsEqualToUTF8CString(m_context, propertyName, "name")) {
return Value(m_context, String(m_context, "NativeModules")); return Value(m_context, String(m_context, "NativeModules"));
} }
@ -662,21 +732,29 @@ namespace facebook {
return m_nativeModules.getModule(m_context, propertyName); return m_nativeModules.getModule(m_context, propertyName);
} }
JSValueRef JSCExecutor::getNativeExtension(JSObjectRef object, JSStringRef propertyName) { JSValueRef JSCExecutor::getNativeExtension(
JSObjectRef object,
JSStringRef propertyName) {
if (m_nativeExtensionsProvider) { if (m_nativeExtensionsProvider) {
folly::dynamic value = m_nativeExtensionsProvider(String::ref(m_context, propertyName).str()); folly::dynamic value =
m_nativeExtensionsProvider(String::ref(m_context, propertyName).str());
return Value::fromDynamic(m_context, std::move(value)); return Value::fromDynamic(m_context, std::move(value));
} }
return JSC_JSValueMakeUndefined(m_context); return JSC_JSValueMakeUndefined(m_context);
} }
JSValueRef JSCExecutor::nativeRequire(size_t count, const JSValueRef arguments[]) { JSValueRef JSCExecutor::nativeRequire(
size_t count,
const JSValueRef arguments[]) {
if (count > 2 || count == 0) { if (count > 2 || count == 0) {
throw std::invalid_argument("Got wrong number of args"); throw std::invalid_argument("Got wrong number of args");
} }
uint32_t moduleId = folly::to<uint32_t>(Value(m_context, arguments[0]).getNumberOrThrow()); uint32_t moduleId =
uint32_t bundleId = count == 2 ? folly::to<uint32_t>(Value(m_context, arguments[1]).getNumberOrThrow()) : 0; folly::to<uint32_t>(Value(m_context, arguments[0]).getNumberOrThrow());
uint32_t bundleId = count == 2
? folly::to<uint32_t>(Value(m_context, arguments[1]).getNumberOrThrow())
: 0;
ReactMarker::logMarker(ReactMarker::NATIVE_REQUIRE_START); ReactMarker::logMarker(ReactMarker::NATIVE_REQUIRE_START);
loadModule(bundleId, moduleId); loadModule(bundleId, moduleId);
@ -704,22 +782,21 @@ namespace facebook {
unsigned int moduleId = Value(m_context, arguments[0]).asUnsignedInteger(); unsigned int moduleId = Value(m_context, arguments[0]).asUnsignedInteger();
unsigned int methodId = Value(m_context, arguments[1]).asUnsignedInteger(); unsigned int methodId = Value(m_context, arguments[1]).asUnsignedInteger();
folly::dynamic args = folly::parseJson(Value(m_context, arguments[2]).toJSONString()); folly::dynamic args =
folly::parseJson(Value(m_context, arguments[2]).toJSONString());
if (!args.isArray()) { if (!args.isArray()) {
throw std::invalid_argument( throw std::invalid_argument(folly::to<std::string>(
folly::to<std::string>("method parameters should be array, but are ", args.typeName())); "method parameters should be array, but are ", args.typeName()));
} }
MethodCallResult result = m_delegate->callSerializableNativeHook( MethodCallResult result = m_delegate->callSerializableNativeHook(
*this, *this, moduleId, methodId, std::move(args));
moduleId,
methodId,
std::move(args));
if (!result.hasValue()) { if (!result.hasValue()) {
return Value::makeUndefined(m_context); return Value::makeUndefined(m_context);
} }
return Value::fromDynamic(m_context, result.value()); return Value::fromDynamic(m_context, result.value());
} }
} } } // namespace react
} // namespace facebook