Skip to content

Commit

Permalink
WebWorkers: Pass Bridge to JSExecutors
Browse files Browse the repository at this point in the history
Reviewed By: cjhopman

Differential Revision: D2921840

fb-gh-sync-id: f89f9ffe2c3bb0dabce7e8cbb9c7dc8b5062e267
shipit-source-id: f89f9ffe2c3bb0dabce7e8cbb9c7dc8b5062e267
  • Loading branch information
astreet authored and facebook-github-bot-5 committed Feb 12, 2016
1 parent 0f850b4 commit cf7a97c
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 101 deletions.
34 changes: 12 additions & 22 deletions ReactAndroid/src/main/jni/react/Bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,9 @@ namespace facebook {
namespace react {

Bridge::Bridge(JSExecutorFactory* jsExecutorFactory, Callback callback) :
m_callback(std::move(callback)),
m_destroyed(std::shared_ptr<bool>(new bool(false)))
{
auto destroyed = m_destroyed;
m_jsExecutor = jsExecutorFactory->createJSExecutor([this, destroyed] (std::string queueJSON, bool isEndOfBatch) {
if (*destroyed) {
return;
}
m_callback(parseMethodCalls(queueJSON), isEndOfBatch);
});
m_callback(std::move(callback)),
m_destroyed(std::shared_ptr<bool>(new bool(false))) {
m_jsExecutor = jsExecutorFactory->createJSExecutor(this);
}

// This must be called on the same thread on which the constructor was called.
Expand All @@ -40,23 +33,14 @@ void Bridge::loadApplicationUnbundle(
m_jsExecutor->loadApplicationUnbundle(std::move(unbundle), startupCode, sourceURL);
}

void Bridge::flush() {
if (*m_destroyed) {
return;
}
auto returnedJSON = m_jsExecutor->flush();
m_callback(parseMethodCalls(returnedJSON), true /* = isEndOfBatch */);
}

void Bridge::callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {
if (*m_destroyed) {
return;
}
#ifdef WITH_FBSYSTRACE
FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "Bridge.callFunction");
#endif
auto returnedJSON = m_jsExecutor->callFunction(moduleId, methodId, arguments);
m_callback(parseMethodCalls(returnedJSON), true /* = isEndOfBatch */);
m_jsExecutor->callFunction(moduleId, methodId, arguments);
}

void Bridge::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
Expand All @@ -66,8 +50,7 @@ void Bridge::invokeCallback(const double callbackId, const folly::dynamic& argum
#ifdef WITH_FBSYSTRACE
FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "Bridge.invokeCallback");
#endif
auto returnedJSON = m_jsExecutor->invokeCallback(callbackId, arguments);
m_callback(parseMethodCalls(returnedJSON), true /* = isEndOfBatch */);
m_jsExecutor->invokeCallback(callbackId, arguments);
}

void Bridge::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
Expand All @@ -94,4 +77,11 @@ void Bridge::handleMemoryPressureCritical() {
m_jsExecutor->handleMemoryPressureCritical();
}

void Bridge::callNativeModules(const std::string& callJSON, bool isEndOfBatch) {
if (*m_destroyed) {
return;
}
m_callback(parseMethodCalls(callJSON), isEndOfBatch);
}

} }
13 changes: 7 additions & 6 deletions ReactAndroid/src/main/jni/react/Bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
#include <functional>
#include <map>
#include <vector>
#include "Value.h"

#include "Executor.h"
#include "MethodCall.h"
#include "JSModulesUnbundle.h"
#include "Value.h"

namespace folly {

Expand All @@ -26,11 +27,6 @@ class Bridge {
Bridge(JSExecutorFactory* jsExecutorFactory, Callback callback);
virtual ~Bridge();

/**
* Flush get the next queue of changes.
*/
void flush();

/**
* Executes a function with the module ID and method ID and any additional
* arguments in JS.
Expand Down Expand Up @@ -62,6 +58,11 @@ class Bridge {
void stopProfiler(const std::string& title, const std::string& filename);
void handleMemoryPressureModerate();
void handleMemoryPressureCritical();

/**
* TODO: get rid of isEndOfBatch
*/
void callNativeModules(const std::string& callJSON, bool isEndOfBatch);
private:
Callback m_callback;
// This is used to avoid a race condition where a proxyCallback gets queued after ~Bridge(),
Expand Down
24 changes: 10 additions & 14 deletions ReactAndroid/src/main/jni/react/Executor.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string>
#include <vector>
#include <memory>

#include "JSModulesUnbundle.h"

namespace folly {
Expand All @@ -16,13 +17,11 @@ struct dynamic;
namespace facebook {
namespace react {

class Bridge;
class JSExecutor;

typedef std::function<void(std::string, bool)> FlushImmediateCallback;

class JSExecutorFactory {
public:
virtual std::unique_ptr<JSExecutor> createJSExecutor(FlushImmediateCallback cb) = 0;
virtual std::unique_ptr<JSExecutor> createJSExecutor(Bridge *bridge) = 0;
virtual ~JSExecutorFactory() {};
};

Expand All @@ -43,23 +42,20 @@ class JSExecutor {
const std::string& startupCode,
const std::string& sourceURL) = 0;

/**
* Executes BatchedBridge.flushedQueue in JS to get the next queue of changes.
*/
virtual std::string flush() = 0;

/**
* Executes BatchedBridge.callFunctionReturnFlushedQueue with the module ID,
* method ID and optional additional arguments in JS, and returns the next
* queue.
* method ID and optional additional arguments in JS. The executor is responsible
* for using Bridge->callNativeModules to invoke any necessary native modules methods.
*/
virtual std::string callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) = 0;
virtual void callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) = 0;

/**
* Executes BatchedBridge.invokeCallbackAndReturnFlushedQueue with the cbID,
* and optional additional arguments in JS and returns the next queue.
* and optional additional arguments in JS and returns the next queue. The executor
* is responsible for using Bridge->callNativeModules to invoke any necessary
* native modules methods.
*/
virtual std::string invokeCallback(const double callbackId, const folly::dynamic& arguments) = 0;
virtual void invokeCallback(const double callbackId, const folly::dynamic& arguments) = 0;

virtual void setGlobalVariable(
const std::string& propName,
Expand Down
43 changes: 21 additions & 22 deletions ReactAndroid/src/main/jni/react/JSCExecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@
#include <folly/String.h>
#include <sys/time.h>

#include "Bridge.h"
#include "JSCHelpers.h"
#include "Value.h"
#include "Platform.h"
#include "Value.h"

#ifdef WITH_JSC_EXTRA_TRACING
#include "JSCTracing.h"
Expand Down Expand Up @@ -45,13 +46,6 @@ namespace react {

static std::unordered_map<JSContextRef, JSCExecutor*> s_globalContextRefToJSCExecutor;

static JSValueRef nativeFlushQueueImmediate(
JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
size_t argumentCount,
const JSValueRef arguments[],
JSValueRef *exception);
static JSValueRef nativePerformanceNow(
JSContextRef ctx,
JSObjectRef function,
Expand Down Expand Up @@ -86,14 +80,15 @@ static std::string executeJSCallWithJSC(
return Value(ctx, result).toJSONString();
}

std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(FlushImmediateCallback cb) {
return std::unique_ptr<JSExecutor>(new JSCExecutor(cb, cacheDir_));
std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(Bridge *bridge) {
return std::unique_ptr<JSExecutor>(new JSCExecutor(bridge, cacheDir_));
}

JSCExecutor::JSCExecutor(FlushImmediateCallback cb, const std::string& cacheDir) :
m_flushImmediateCallback(cb), m_deviceCacheDir(cacheDir) {
JSCExecutor::JSCExecutor(Bridge *bridge, const std::string& cacheDir) :
m_bridge(bridge),
m_deviceCacheDir(cacheDir),
m_messageQueueThread(MessageQueues::getCurrentMessageQueueThread()) {
m_context = JSGlobalContextCreateInGroup(nullptr, nullptr);
m_messageQueueThread = MessageQueues::getCurrentMessageQueueThread();
s_globalContextRefToJSCExecutor[m_context] = this;
installGlobalFunction(m_context, "nativeFlushQueueImmediate", nativeFlushQueueImmediate);
installGlobalFunction(m_context, "nativePerformanceNow", nativePerformanceNow);
Expand Down Expand Up @@ -152,6 +147,7 @@ void JSCExecutor::executeApplicationScript(
// in which a cache file for that script will be stored.
evaluateScript(m_context, jsScript, jsSourceURL, m_deviceCacheDir.c_str());
}
flush();
}

void JSCExecutor::loadApplicationUnbundle(
Expand All @@ -165,28 +161,31 @@ void JSCExecutor::loadApplicationUnbundle(
executeApplicationScript(startupCode, sourceURL);
}

std::string JSCExecutor::flush() {
void JSCExecutor::flush() {
// TODO: Make this a first class function instead of evaling. #9317773
return executeJSCallWithJSC(m_context, "flushedQueue", std::vector<folly::dynamic>());
std::string calls = executeJSCallWithJSC(m_context, "flushedQueue", std::vector<folly::dynamic>());
m_bridge->callNativeModules(calls, true);
}

std::string JSCExecutor::callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {
void JSCExecutor::callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {
// TODO: Make this a first class function instead of evaling. #9317773
std::vector<folly::dynamic> call{
(double) moduleId,
(double) methodId,
std::move(arguments),
};
return executeJSCallWithJSC(m_context, "callFunctionReturnFlushedQueue", std::move(call));
std::string calls = executeJSCallWithJSC(m_context, "callFunctionReturnFlushedQueue", std::move(call));
m_bridge->callNativeModules(calls, true);
}

std::string JSCExecutor::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
void JSCExecutor::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
// TODO: Make this a first class function instead of evaling. #9317773
std::vector<folly::dynamic> call{
(double) callbackId,
std::move(arguments)
};
return executeJSCallWithJSC(m_context, "invokeCallbackAndReturnFlushedQueue", std::move(call));
std::string calls = executeJSCallWithJSC(m_context, "invokeCallbackAndReturnFlushedQueue", std::move(call));
m_bridge->callNativeModules(calls, true);
}

void JSCExecutor::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
Expand Down Expand Up @@ -240,7 +239,7 @@ void JSCExecutor::handleMemoryPressureCritical() {
}

void JSCExecutor::flushQueueImmediate(std::string queueJSON) {
m_flushImmediateCallback(queueJSON, false);
m_bridge->callNativeModules(queueJSON, false);
}

void JSCExecutor::loadModule(uint32_t moduleId) {
Expand Down Expand Up @@ -271,7 +270,7 @@ void JSCExecutor::onMessageReceived(int workerId, const std::string& json) {
JSValueRef args[] = { JSCWebWorker::createMessageObject(m_context, json) };
onmessageValue.asObject().callAsFunction(1, args);

m_flushImmediateCallback(flush(), true);
flush();
}

int JSCExecutor::addWebWorker(const std::string& script, JSValueRef workerRef) {
Expand Down Expand Up @@ -348,7 +347,7 @@ static JSValueRef createErrorString(JSContextRef ctx, const char *msg) {
return JSValueMakeString(ctx, String(msg));
}

static JSValueRef nativeFlushQueueImmediate(
JSValueRef JSCExecutor::nativeFlushQueueImmediate(
JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
Expand Down
35 changes: 21 additions & 14 deletions ReactAndroid/src/main/jni/react/JSCExecutor.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class MessageQueueThread;
class JSCExecutorFactory : public JSExecutorFactory {
public:
JSCExecutorFactory(const std::string& cacheDir) : cacheDir_(cacheDir) {}
virtual std::unique_ptr<JSExecutor> createJSExecutor(FlushImmediateCallback cb) override;
virtual std::unique_ptr<JSExecutor> createJSExecutor(Bridge *bridge) override;
private:
std::string cacheDir_;
};
Expand All @@ -28,7 +28,7 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
/**
* Should be invoked from the JS thread.
*/
explicit JSCExecutor(FlushImmediateCallback flushImmediateCallback, const std::string& cacheDir);
explicit JSCExecutor(Bridge *bridge, const std::string& cacheDir);
~JSCExecutor() override;

virtual void executeApplicationScript(
Expand All @@ -38,12 +38,11 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
std::unique_ptr<JSModulesUnbundle> unbundle,
const std::string& startupCode,
const std::string& sourceURL) override;
virtual std::string flush() override;
virtual std::string callFunction(
virtual void callFunction(
const double moduleId,
const double methodId,
const folly::dynamic& arguments) override;
virtual std::string invokeCallback(
virtual void invokeCallback(
const double callbackId,
const folly::dynamic& arguments) override;
virtual void setGlobalVariable(
Expand All @@ -55,25 +54,26 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
virtual void handleMemoryPressureModerate() override;
virtual void handleMemoryPressureCritical() override;

void flushQueueImmediate(std::string queueJSON);
void installNativeHook(const char *name, JSObjectCallAsFunctionCallback callback);
virtual void onMessageReceived(int workerId, const std::string& message) override;
virtual JSGlobalContextRef getContext() override;
virtual std::shared_ptr<MessageQueueThread> getMessageQueueThread() override;

private:
JSGlobalContextRef m_context;
FlushImmediateCallback m_flushImmediateCallback;
std::unordered_map<int, JSCWebWorker> m_webWorkers;
std::unordered_map<int, Object> m_webWorkerJSObjs;
std::shared_ptr<MessageQueueThread> m_messageQueueThread;
Bridge *m_bridge;
std::string m_deviceCacheDir;
std::shared_ptr<MessageQueueThread> m_messageQueueThread;
std::unique_ptr<JSModulesUnbundle> m_unbundle;

int addWebWorker(const std::string& script, JSValueRef workerRef);
void postMessageToWebWorker(int worker, JSValueRef message, JSValueRef *exn);
void flush();
void terminateWebWorker(int worker);
void loadModule(uint32_t moduleId);
void flushQueueImmediate(std::string queueJSON);

static JSValueRef nativeStartWorker(
JSContextRef ctx,
Expand All @@ -97,12 +97,19 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
const JSValueRef arguments[],
JSValueRef *exception);
static JSValueRef nativeRequire(
JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
size_t argumentCount,
const JSValueRef arguments[],
JSValueRef *exception);
JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
size_t argumentCount,
const JSValueRef arguments[],
JSValueRef *exception);
static JSValueRef nativeFlushQueueImmediate(
JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
size_t argumentCount,
const JSValueRef arguments[],
JSValueRef *exception);
};

} }
Loading

0 comments on commit cf7a97c

Please sign in to comment.