Remove JsToNativeBridge's nativeQueue

Reviewed By: mhorowitz

Differential Revision: D4589737

fbshipit-source-id: 3b2730417d99c4f98cfaad386bc50328f2551592
This commit is contained in:
Pieter De Baets 2017-03-17 06:55:37 -07:00 committed by Facebook Github Bot
parent fbf6d1aaeb
commit d7b37c4050
13 changed files with 142 additions and 180 deletions

View File

@ -101,70 +101,25 @@ namespace {
// is not the JS thread. C++ modules don't use RCTNativeModule, so this little // is not the JS thread. C++ modules don't use RCTNativeModule, so this little
// adapter does the work. // adapter does the work.
class QueueNativeModule : public NativeModule { class DispatchMessageQueueThread : public MessageQueueThread {
public: public:
QueueNativeModule(RCTCxxBridge *bridge, DispatchMessageQueueThread(RCTModuleData *moduleData)
std::unique_ptr<NativeModule> module) : moduleData_(moduleData) {}
: bridge_(bridge)
, module_(std::move(module))
// Create new queue (store queueName, as it isn't retained by dispatch_queue)
, queueName_("com.facebook.react." + module_->getName() + "Queue")
, queue_(dispatch_queue_create(queueName_.c_str(), DISPATCH_QUEUE_SERIAL)) {}
std::string getName() override { void runOnQueue(std::function<void()>&& func) override {
return module_->getName(); dispatch_async(moduleData_.methodQueue, [func=std::move(func)] {
} func();
std::vector<MethodDescriptor> getMethods() override {
return module_->getMethods();
}
folly::dynamic getConstants() override {
return module_->getConstants();
}
bool supportsWebWorkers() override {
return module_->supportsWebWorkers();
}
void invoke(ExecutorToken token, unsigned int reactMethodId,
folly::dynamic &&params) override {
__weak RCTCxxBridge *bridge = bridge_;
auto module = module_;
auto cparams = std::make_shared<folly::dynamic>(std::move(params));
dispatch_async(queue_, ^{
if (!bridge || !bridge.valid) {
return;
}
module->invoke(token, reactMethodId, std::move(*cparams));
}); });
} }
void runOnQueueSync(std::function<void()>&& func) override {
MethodCallResult callSerializableNativeHook( LOG(FATAL) << "Unsupported operation";
ExecutorToken token, unsigned int reactMethodId, }
folly::dynamic &&args) override { void quitSynchronous() override {
return module_->callSerializableNativeHook(token, reactMethodId, std::move(args)); LOG(FATAL) << "Unsupported operation";
} }
private: private:
RCTCxxBridge *bridge_; RCTModuleData *moduleData_;
std::shared_ptr<NativeModule> module_;
std::string queueName_;
dispatch_queue_t queue_;
};
// This is a temporary hack. The cxx bridge assumes a single native
// queue handles all native method calls, but that's false on ios. So
// this is a no-thread passthrough, and queues are handled in
// RCTNativeModule. A similar refactoring should be done on the Java
// bridge.
class InlineMessageQueueThread : public MessageQueueThread {
public:
void runOnQueue(std::function<void()>&& func) override { func(); }
void runOnQueueSync(std::function<void()>&& func) override { func(); }
void quitSynchronous() override {}
}; };
} }
@ -551,12 +506,13 @@ struct RCTInstanceCallback : public InstanceCallback {
if (![moduleData hasInstance]) { if (![moduleData hasInstance]) {
continue; continue;
} }
modules.emplace_back( modules.emplace_back(std::make_unique<CxxNativeModule>(
new QueueNativeModule(self, std::make_unique<CxxNativeModule>( _reactInstance,
_reactInstance, [moduleData.name UTF8String], [moduleData.name UTF8String],
[moduleData] { return [(RCTCxxModule *)(moduleData.instance) move]; }))); [moduleData] { return [(RCTCxxModule *)(moduleData.instance) move]; },
std::make_shared<DispatchMessageQueueThread>(moduleData)));
} else { } else {
modules.emplace_back(new RCTNativeModule(self, moduleData)); modules.emplace_back(std::make_unique<RCTNativeModule>(self, moduleData));
} }
} }
@ -586,7 +542,6 @@ struct RCTInstanceCallback : public InstanceCallback {
std::unique_ptr<RCTInstanceCallback>(new RCTInstanceCallback(self)), std::unique_ptr<RCTInstanceCallback>(new RCTInstanceCallback(self)),
executorFactory, executorFactory,
_jsMessageThread, _jsMessageThread,
std::unique_ptr<MessageQueueThread>(new InlineMessageQueueThread),
std::move([self _createModuleRegistry])); std::move([self _createModuleRegistry]));
#if RCT_PROFILE #if RCT_PROFILE

View File

@ -41,13 +41,17 @@ class Exception : public jni::JavaClass<Exception> {
class JInstanceCallback : public InstanceCallback { class JInstanceCallback : public InstanceCallback {
public: public:
explicit JInstanceCallback(alias_ref<ReactCallback::javaobject> jobj) explicit JInstanceCallback(
: jobj_(make_global(jobj)) {} alias_ref<ReactCallback::javaobject> jobj,
std::shared_ptr<JMessageQueueThread> messageQueueThread)
: jobj_(make_global(jobj)), messageQueueThread_(std::move(messageQueueThread)) {}
void onBatchComplete() override { void onBatchComplete() override {
static auto method = messageQueueThread_->runOnQueue([this] {
ReactCallback::javaClassStatic()->getMethod<void()>("onBatchComplete"); static auto method =
method(jobj_); ReactCallback::javaClassStatic()->getMethod<void()>("onBatchComplete");
method(jobj_);
});
} }
void incrementPendingJSCalls() override { void incrementPendingJSCalls() override {
@ -61,6 +65,7 @@ class JInstanceCallback : public InstanceCallback {
} }
void decrementPendingJSCalls() override { void decrementPendingJSCalls() override {
jni::ThreadScope guard;
static auto method = static auto method =
ReactCallback::javaClassStatic()->getMethod<void()>("decrementPendingJSCalls"); ReactCallback::javaClassStatic()->getMethod<void()>("decrementPendingJSCalls");
method(jobj_); method(jobj_);
@ -81,12 +86,11 @@ class JInstanceCallback : public InstanceCallback {
return jobj->cthis()->getExecutorToken(jobj); return jobj->cthis()->getExecutorToken(jobj);
} }
void onExecutorStopped(ExecutorToken) override { void onExecutorStopped(ExecutorToken) override {}
// TODO(cjhopman): implement this.
}
private: private:
global_ref<ReactCallback::javaobject> jobj_; global_ref<ReactCallback::javaobject> jobj_;
std::shared_ptr<JMessageQueueThread> messageQueueThread_;
}; };
} }
@ -97,7 +101,12 @@ jni::local_ref<CatalystInstanceImpl::jhybriddata> CatalystInstanceImpl::initHybr
} }
CatalystInstanceImpl::CatalystInstanceImpl() CatalystInstanceImpl::CatalystInstanceImpl()
: instance_(folly::make_unique<Instance>()) {} : instance_(folly::make_unique<Instance>()) {}
CatalystInstanceImpl::~CatalystInstanceImpl() {
// TODO: 16669252: this prevents onCatalystInstanceDestroy from being called
moduleMessageQueue_->quitSynchronous();
}
void CatalystInstanceImpl::registerNatives() { void CatalystInstanceImpl::registerNatives() {
registerHybrid({ registerHybrid({
@ -127,11 +136,12 @@ void CatalystInstanceImpl::initializeBridge(
// This executor is actually a factory holder. // This executor is actually a factory holder.
JavaScriptExecutorHolder* jseh, JavaScriptExecutorHolder* jseh,
jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue, jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue,
jni::alias_ref<JavaMessageQueueThread::javaobject> moduleQueue, jni::alias_ref<JavaMessageQueueThread::javaobject> nativeModulesQueue,
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules, jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules) { jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules) {
// TODO mhorowitz: how to assert here? // TODO mhorowitz: how to assert here?
// Assertions.assertCondition(mBridge == null, "initializeBridge should be called once"); // Assertions.assertCondition(mBridge == null, "initializeBridge should be called once");
moduleMessageQueue_ = std::make_shared<JMessageQueueThread>(nativeModulesQueue);
// This used to be: // This used to be:
// //
@ -149,12 +159,12 @@ void CatalystInstanceImpl::initializeBridge(
// don't need jsModuleDescriptions any more, all the way up and down the // don't need jsModuleDescriptions any more, all the way up and down the
// stack. // stack.
instance_->initializeBridge(folly::make_unique<JInstanceCallback>(callback), instance_->initializeBridge(
jseh->getExecutorFactory(), folly::make_unique<JInstanceCallback>(callback, moduleMessageQueue_),
folly::make_unique<JMessageQueueThread>(jsQueue), jseh->getExecutorFactory(),
folly::make_unique<JMessageQueueThread>(moduleQueue), folly::make_unique<JMessageQueueThread>(jsQueue),
buildModuleRegistry(std::weak_ptr<Instance>(instance_), buildModuleRegistry(
javaModules, cxxModules)); std::weak_ptr<Instance>(instance_), javaModules, cxxModules, moduleMessageQueue_));
} }
void CatalystInstanceImpl::jniSetSourceURL(const std::string& sourceURL) { void CatalystInstanceImpl::jniSetSourceURL(const std::string& sourceURL) {

View File

@ -28,6 +28,7 @@ class CatalystInstanceImpl : public jni::HybridClass<CatalystInstanceImpl> {
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/cxxbridge/CatalystInstanceImpl;"; static constexpr auto kJavaDescriptor = "Lcom/facebook/react/cxxbridge/CatalystInstanceImpl;";
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>); static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jclass>);
~CatalystInstanceImpl() override;
static void registerNatives(); static void registerNatives();
@ -74,6 +75,7 @@ class CatalystInstanceImpl : public jni::HybridClass<CatalystInstanceImpl> {
// This should be the only long-lived strong reference, but every C++ class // This should be the only long-lived strong reference, but every C++ class
// will have a weak reference. // will have a weak reference.
std::shared_ptr<Instance> instance_; std::shared_ptr<Instance> instance_;
std::shared_ptr<JMessageQueueThread> moduleMessageQueue_;
}; };
}} }}

View File

@ -87,30 +87,36 @@ bool JavaNativeModule::supportsWebWorkers() {
} }
void JavaNativeModule::invoke(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) { void JavaNativeModule::invoke(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) {
static auto invokeMethod = messageQueueThread_->runOnQueue([this, token, reactMethodId, params=std::move(params)] {
wrapper_->getClass()->getMethod<void(JExecutorToken::javaobject, jint, ReadableNativeArray::javaobject)>("invoke"); static auto invokeMethod = wrapper_->getClass()->
invokeMethod(wrapper_, JExecutorToken::extractJavaPartFromToken(token).get(), static_cast<jint>(reactMethodId), getMethod<void(JExecutorToken::javaobject, jint, ReadableNativeArray::javaobject)>("invoke");
ReadableNativeArray::newObjectCxxArgs(std::move(params)).get()); invokeMethod(wrapper_,
JExecutorToken::extractJavaPartFromToken(token).get(),
static_cast<jint>(reactMethodId),
ReadableNativeArray::newObjectCxxArgs(std::move(params)).get());
});
} }
MethodCallResult JavaNativeModule::callSerializableNativeHook(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) { MethodCallResult JavaNativeModule::callSerializableNativeHook(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) {
// TODO: evaluate whether calling through invoke is potentially faster // TODO: evaluate whether calling through invoke is potentially faster
if (reactMethodId >= syncMethods_.size()) { if (reactMethodId >= syncMethods_.size()) {
throw std::invalid_argument( throw std::invalid_argument(
folly::to<std::string>("methodId ", reactMethodId, " out of range [0..", syncMethods_.size(), "]")); folly::to<std::string>("methodId ", reactMethodId, " out of range [0..", syncMethods_.size(), "]"));
} }
auto& method = syncMethods_[reactMethodId]; auto& method = syncMethods_[reactMethodId];
CHECK(method.hasValue() && method->isSyncHook()) << "Trying to invoke a asynchronous method as synchronous hook"; CHECK(method.hasValue() && method->isSyncHook()) << "Trying to invoke a asynchronous method as synchronous hook";
return method->invoke(instance_, wrapper_->getModule(), token, params); return method->invoke(instance_, wrapper_->getModule(), token, params);
} }
NewJavaNativeModule::NewJavaNativeModule( NewJavaNativeModule::NewJavaNativeModule(
std::weak_ptr<Instance> instance, std::weak_ptr<Instance> instance,
jni::alias_ref<JavaModuleWrapper::javaobject> wrapper) jni::alias_ref<JavaModuleWrapper::javaobject> wrapper,
: instance_(std::move(instance)), std::shared_ptr<MessageQueueThread> messageQueueThread)
wrapper_(make_global(wrapper)), : instance_(std::move(instance))
module_(make_global(wrapper->getModule())) { , wrapper_(make_global(wrapper))
, module_(make_global(wrapper->getModule()))
, messageQueueThread_(std::move(messageQueueThread)) {
auto descs = wrapper_->getMethodDescriptors(); auto descs = wrapper_->getMethodDescriptors();
std::string moduleName = getName(); std::string moduleName = getName();
methods_.reserve(descs->size()); methods_.reserve(descs->size());
@ -161,7 +167,9 @@ void NewJavaNativeModule::invoke(ExecutorToken token, unsigned int reactMethodId
folly::to<std::string>("methodId ", reactMethodId, " out of range [0..", methods_.size(), "]")); folly::to<std::string>("methodId ", reactMethodId, " out of range [0..", methods_.size(), "]"));
} }
CHECK(!methods_[reactMethodId].isSyncHook()) << "Trying to invoke a synchronous hook asynchronously"; CHECK(!methods_[reactMethodId].isSyncHook()) << "Trying to invoke a synchronous hook asynchronously";
invokeInner(token, reactMethodId, std::move(params)); messageQueueThread_->runOnQueue([this, token, reactMethodId, params=std::move(params)] () mutable {
invokeInner(token, reactMethodId, std::move(params));
});
} }
MethodCallResult NewJavaNativeModule::callSerializableNativeHook(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) { MethodCallResult NewJavaNativeModule::callSerializableNativeHook(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) {

View File

@ -12,6 +12,7 @@ namespace facebook {
namespace react { namespace react {
class Instance; class Instance;
class MessageQueueThread;
struct JMethodDescriptor : public jni::JavaClass<JMethodDescriptor> { struct JMethodDescriptor : public jni::JavaClass<JMethodDescriptor> {
static constexpr auto kJavaDescriptor = static constexpr auto kJavaDescriptor =
@ -44,8 +45,11 @@ class JavaNativeModule : public NativeModule {
public: public:
JavaNativeModule( JavaNativeModule(
std::weak_ptr<Instance> instance, std::weak_ptr<Instance> instance,
jni::alias_ref<JavaModuleWrapper::javaobject> wrapper) jni::alias_ref<JavaModuleWrapper::javaobject> wrapper,
: instance_(std::move(instance)), wrapper_(make_global(wrapper)) {} std::shared_ptr<MessageQueueThread> messageQueueThread)
: instance_(std::move(instance))
, wrapper_(make_global(wrapper))
, messageQueueThread_(std::move(messageQueueThread)) {}
std::string getName() override; std::string getName() override;
folly::dynamic getConstants() override; folly::dynamic getConstants() override;
@ -57,6 +61,7 @@ class JavaNativeModule : public NativeModule {
private: private:
std::weak_ptr<Instance> instance_; std::weak_ptr<Instance> instance_;
jni::global_ref<JavaModuleWrapper::javaobject> wrapper_; jni::global_ref<JavaModuleWrapper::javaobject> wrapper_;
std::shared_ptr<MessageQueueThread> messageQueueThread_;
std::vector<folly::Optional<MethodInvoker>> syncMethods_; std::vector<folly::Optional<MethodInvoker>> syncMethods_;
}; };
@ -65,7 +70,8 @@ class NewJavaNativeModule : public NativeModule {
public: public:
NewJavaNativeModule( NewJavaNativeModule(
std::weak_ptr<Instance> instance, std::weak_ptr<Instance> instance,
jni::alias_ref<JavaModuleWrapper::javaobject> wrapper); jni::alias_ref<JavaModuleWrapper::javaobject> wrapper,
std::shared_ptr<MessageQueueThread> messageQueueThread);
std::string getName() override; std::string getName() override;
std::vector<MethodDescriptor> getMethods() override; std::vector<MethodDescriptor> getMethods() override;
@ -78,6 +84,7 @@ class NewJavaNativeModule : public NativeModule {
std::weak_ptr<Instance> instance_; std::weak_ptr<Instance> instance_;
jni::global_ref<JavaModuleWrapper::javaobject> wrapper_; jni::global_ref<JavaModuleWrapper::javaobject> wrapper_;
jni::global_ref<JBaseJavaModule::javaobject> module_; jni::global_ref<JBaseJavaModule::javaobject> module_;
std::shared_ptr<MessageQueueThread> messageQueueThread_;
std::vector<MethodInvoker> methods_; std::vector<MethodInvoker> methods_;
std::vector<MethodDescriptor> methodDescriptors_; std::vector<MethodDescriptor> methodDescriptors_;

View File

@ -32,14 +32,16 @@ xplat::module::CxxModule::Provider ModuleHolder::getProvider() const {
std::unique_ptr<ModuleRegistry> buildModuleRegistry( std::unique_ptr<ModuleRegistry> buildModuleRegistry(
std::weak_ptr<Instance> winstance, std::weak_ptr<Instance> winstance,
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules, jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules) { jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules,
std::shared_ptr<MessageQueueThread> moduleMessageQueue) {
std::vector<std::unique_ptr<NativeModule>> modules; std::vector<std::unique_ptr<NativeModule>> modules;
for (const auto& jm : *javaModules) { for (const auto& jm : *javaModules) {
modules.emplace_back(folly::make_unique<JavaNativeModule>(winstance, jm)); modules.emplace_back(folly::make_unique<JavaNativeModule>(
winstance, jm, moduleMessageQueue));
} }
for (const auto& cm : *cxxModules) { for (const auto& cm : *cxxModules) {
modules.emplace_back( modules.emplace_back(folly::make_unique<CxxNativeModule>(
folly::make_unique<CxxNativeModule>(winstance, cm->getName(), cm->getProvider())); winstance, cm->getName(), cm->getProvider(), moduleMessageQueue));
} }
if (modules.empty()) { if (modules.empty()) {
return nullptr; return nullptr;

View File

@ -12,6 +12,8 @@
namespace facebook { namespace facebook {
namespace react { namespace react {
class MessageQueueThread;
class ModuleHolder : public jni::JavaClass<ModuleHolder> { class ModuleHolder : public jni::JavaClass<ModuleHolder> {
public: public:
static auto constexpr kJavaDescriptor = static auto constexpr kJavaDescriptor =
@ -24,7 +26,8 @@ class ModuleHolder : public jni::JavaClass<ModuleHolder> {
std::unique_ptr<ModuleRegistry> buildModuleRegistry( std::unique_ptr<ModuleRegistry> buildModuleRegistry(
std::weak_ptr<Instance> winstance, std::weak_ptr<Instance> winstance,
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules, jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules); jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules,
std::shared_ptr<MessageQueueThread> moduleMessageQueue);
} }
} }

View File

@ -46,13 +46,6 @@ CxxModule::Callback convertCallback(
} }
CxxNativeModule::CxxNativeModule(std::weak_ptr<Instance> instance,
std::string name,
CxxModule::Provider provider)
: instance_(instance)
, name_(std::move(name))
, provider_(provider) {}
std::string CxxNativeModule::getName() { std::string CxxNativeModule::getName() {
return name_; return name_;
} }
@ -85,8 +78,8 @@ bool CxxNativeModule::supportsWebWorkers() {
void CxxNativeModule::invoke(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) { void CxxNativeModule::invoke(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) {
if (reactMethodId >= methods_.size()) { if (reactMethodId >= methods_.size()) {
throw std::invalid_argument( throw std::invalid_argument(folly::to<std::string>("methodId ", reactMethodId,
folly::to<std::string>("methodId ", reactMethodId, " out of range [0..", methods_.size(), "]")); " out of range [0..", methods_.size(), "]"));
} }
if (!params.isArray()) { if (!params.isArray()) {
throw std::invalid_argument( throw std::invalid_argument(
@ -99,25 +92,20 @@ void CxxNativeModule::invoke(ExecutorToken token, unsigned int reactMethodId, fo
const auto& method = methods_[reactMethodId]; const auto& method = methods_[reactMethodId];
if (!method.func) { if (!method.func) {
throw std::runtime_error( throw std::runtime_error(folly::to<std::string>("Method ", method.name,
folly::to<std::string>("Method ", method.name, " is synchronous but invoked asynchronously"));
" is synchronous but invoked asynchronously"));
} }
if (params.size() < method.callbacks) { if (params.size() < method.callbacks) {
throw std::invalid_argument( throw std::invalid_argument(folly::to<std::string>("Expected ", method.callbacks,
folly::to<std::string>("Expected ", method.callbacks, " callbacks, but only ", " callbacks, but only ", params.size(), " parameters provided"));
params.size(), " parameters provided"));
} }
if (method.callbacks == 1) { if (method.callbacks == 1) {
first = convertCallback( first = convertCallback(makeCallback(instance_, token, params[params.size() - 1]));
makeCallback(instance_, token, params[params.size() - 1]));
} else if (method.callbacks == 2) { } else if (method.callbacks == 2) {
first = convertCallback( first = convertCallback(makeCallback(instance_, token, params[params.size() - 2]));
makeCallback(instance_, token, params[params.size() - 2])); second = convertCallback(makeCallback(instance_, token, params[params.size() - 1]));
second = convertCallback(
makeCallback(instance_, token, params[params.size() - 1]));
} }
params.resize(params.size() - method.callbacks); params.resize(params.size() - method.callbacks);
@ -141,16 +129,18 @@ void CxxNativeModule::invoke(ExecutorToken token, unsigned int reactMethodId, fo
// stack. I'm told that will be possible in the future. TODO // stack. I'm told that will be possible in the future. TODO
// mhorowitz #7128529: convert C++ exceptions to Java // mhorowitz #7128529: convert C++ exceptions to Java
try { messageQueueThread_->runOnQueue([method, params=std::move(params), first, second] () {
method.func(std::move(params), first, second); try {
} catch (const facebook::xplat::JsArgumentException& ex) { method.func(std::move(params), first, second);
// This ends up passed to the onNativeException callback. } catch (const facebook::xplat::JsArgumentException& ex) {
throw; // This ends up passed to the onNativeException callback.
} catch (...) { throw;
// This means some C++ code is buggy. As above, we fail hard so the C++ } catch (...) {
// developer can debug and fix it. // This means some C++ code is buggy. As above, we fail hard so the C++
std::terminate(); // developer can debug and fix it.
} std::terminate();
}
});
} }
MethodCallResult CxxNativeModule::callSerializableNativeHook( MethodCallResult CxxNativeModule::callSerializableNativeHook(

View File

@ -15,8 +15,14 @@ std::function<void(folly::dynamic)> makeCallback(
class CxxNativeModule : public NativeModule { class CxxNativeModule : public NativeModule {
public: public:
CxxNativeModule(std::weak_ptr<Instance> instance, std::string name, CxxNativeModule(std::weak_ptr<Instance> instance,
xplat::module::CxxModule::Provider provider); std::string name,
xplat::module::CxxModule::Provider provider,
std::shared_ptr<MessageQueueThread> messageQueueThread)
: instance_(instance)
, name_(std::move(name))
, provider_(provider)
, messageQueueThread_(messageQueueThread) {}
std::string getName() override; std::string getName() override;
std::vector<MethodDescriptor> getMethods() override; std::vector<MethodDescriptor> getMethods() override;
@ -32,6 +38,7 @@ private:
std::weak_ptr<Instance> instance_; std::weak_ptr<Instance> instance_;
std::string name_; std::string name_;
xplat::module::CxxModule::Provider provider_; xplat::module::CxxModule::Provider provider_;
std::shared_ptr<MessageQueueThread> messageQueueThread_;
std::unique_ptr<xplat::module::CxxModule> module_; std::unique_ptr<xplat::module::CxxModule> module_;
std::vector<xplat::module::CxxModule::Method> methods_; std::vector<xplat::module::CxxModule::Method> methods_;
}; };

View File

@ -33,24 +33,14 @@ void Instance::initializeBridge(
std::unique_ptr<InstanceCallback> callback, std::unique_ptr<InstanceCallback> callback,
std::shared_ptr<JSExecutorFactory> jsef, std::shared_ptr<JSExecutorFactory> jsef,
std::shared_ptr<MessageQueueThread> jsQueue, std::shared_ptr<MessageQueueThread> jsQueue,
std::unique_ptr<MessageQueueThread> nativeQueue,
std::shared_ptr<ModuleRegistry> moduleRegistry) { std::shared_ptr<ModuleRegistry> moduleRegistry) {
callback_ = std::move(callback); callback_ = std::move(callback);
if (!nativeQueue) {
// TODO pass down a thread/queue from java, instead of creating our own.
auto queue = folly::make_unique<CxxMessageQueue>();
std::thread t(queue->getUnregisteredRunLoop());
t.detach();
nativeQueue = std::move(queue);
}
jsQueue->runOnQueueSync( jsQueue->runOnQueueSync(
[this, &jsef, moduleRegistry, jsQueue, [this, &jsef, moduleRegistry, jsQueue] () mutable {
nativeQueue=folly::makeMoveWrapper(std::move(nativeQueue))] () mutable {
nativeToJsBridge_ = folly::make_unique<NativeToJsBridge>( nativeToJsBridge_ = folly::make_unique<NativeToJsBridge>(
jsef.get(), moduleRegistry, jsQueue, nativeQueue.move(), callback_); jsef.get(), moduleRegistry, jsQueue, callback_);
std::lock_guard<std::mutex> lock(m_syncMutex); std::lock_guard<std::mutex> lock(m_syncMutex);
m_syncReady = true; m_syncReady = true;

View File

@ -31,7 +31,6 @@ class Instance {
std::unique_ptr<InstanceCallback> callback, std::unique_ptr<InstanceCallback> callback,
std::shared_ptr<JSExecutorFactory> jsef, std::shared_ptr<JSExecutorFactory> jsef,
std::shared_ptr<MessageQueueThread> jsQueue, std::shared_ptr<MessageQueueThread> jsQueue,
std::unique_ptr<MessageQueueThread> nativeQueue,
std::shared_ptr<ModuleRegistry> moduleRegistry); std::shared_ptr<ModuleRegistry> moduleRegistry);
void setSourceURL(std::string sourceURL); void setSourceURL(std::string sourceURL);

View File

@ -24,11 +24,9 @@ class JsToNativeBridge : public react::ExecutorDelegate {
public: public:
JsToNativeBridge(NativeToJsBridge* nativeToJs, JsToNativeBridge(NativeToJsBridge* nativeToJs,
std::shared_ptr<ModuleRegistry> registry, std::shared_ptr<ModuleRegistry> registry,
std::unique_ptr<MessageQueueThread> nativeQueue,
std::shared_ptr<InstanceCallback> callback) std::shared_ptr<InstanceCallback> callback)
: m_nativeToJs(nativeToJs) : m_nativeToJs(nativeToJs)
, m_registry(registry) , m_registry(registry)
, m_nativeQueue(std::move(nativeQueue))
, m_callback(callback) {} , m_callback(callback) {}
void registerExecutor(std::unique_ptr<JSExecutor> executor, void registerExecutor(std::unique_ptr<JSExecutor> executor,
@ -51,24 +49,25 @@ public:
CHECK(m_registry || calls.empty()) << CHECK(m_registry || calls.empty()) <<
"native module calls cannot be completed with no native modules"; "native module calls cannot be completed with no native modules";
ExecutorToken token = m_nativeToJs->getTokenForExecutor(executor); ExecutorToken token = m_nativeToJs->getTokenForExecutor(executor);
m_nativeQueue->runOnQueue([this, token, calls=std::move(calls), isEndOfBatch] () mutable { m_batchHadNativeModuleCalls = m_batchHadNativeModuleCalls || !calls.empty();
m_batchHadNativeModuleCalls = m_batchHadNativeModuleCalls || !calls.empty();
// An exception anywhere in here stops processing of the batch. This // An exception anywhere in here stops processing of the batch. This
// was the behavior of the Android bridge, and since exception handling // was the behavior of the Android bridge, and since exception handling
// terminates the whole bridge, there's not much point in continuing. // terminates the whole bridge, there's not much point in continuing.
for (auto& call : react::parseMethodCalls(std::move(calls))) { for (auto& call : parseMethodCalls(std::move(calls))) {
m_registry->callNativeMethod( m_registry->callNativeMethod(
token, call.moduleId, call.methodId, std::move(call.arguments), call.callId); token, call.moduleId, call.methodId, std::move(call.arguments), call.callId);
}
if (isEndOfBatch) {
// onBatchComplete will be called on the native (module) queue, but
// decrementPendingJSCalls will be called sync. Be aware that the bridge may still
// be processing native calls when the birdge idle signaler fires.
if (m_batchHadNativeModuleCalls) {
m_callback->onBatchComplete();
m_batchHadNativeModuleCalls = false;
} }
if (isEndOfBatch) { m_callback->decrementPendingJSCalls();
if (m_batchHadNativeModuleCalls) { }
m_callback->onBatchComplete();
m_batchHadNativeModuleCalls = false;
}
m_callback->decrementPendingJSCalls();
}
});
} }
MethodCallResult callSerializableNativeHook( MethodCallResult callSerializableNativeHook(
@ -78,10 +77,6 @@ public:
return m_registry->callSerializableNativeHook(token, moduleId, methodId, std::move(args)); return m_registry->callSerializableNativeHook(token, moduleId, methodId, std::move(args));
} }
void quitQueueSynchronous() {
m_nativeQueue->quitSynchronous();
}
private: private:
// These methods are always invoked from an Executor. The NativeToJsBridge // These methods are always invoked from an Executor. The NativeToJsBridge
@ -91,7 +86,6 @@ private:
// valid object during a call to a delegate method from an exectuto. // valid object during a call to a delegate method from an exectuto.
NativeToJsBridge* m_nativeToJs; NativeToJsBridge* m_nativeToJs;
std::shared_ptr<ModuleRegistry> m_registry; std::shared_ptr<ModuleRegistry> m_registry;
std::unique_ptr<MessageQueueThread> m_nativeQueue;
std::shared_ptr<InstanceCallback> m_callback; std::shared_ptr<InstanceCallback> m_callback;
bool m_batchHadNativeModuleCalls = false; bool m_batchHadNativeModuleCalls = false;
}; };
@ -100,12 +94,10 @@ NativeToJsBridge::NativeToJsBridge(
JSExecutorFactory* jsExecutorFactory, JSExecutorFactory* jsExecutorFactory,
std::shared_ptr<ModuleRegistry> registry, std::shared_ptr<ModuleRegistry> registry,
std::shared_ptr<MessageQueueThread> jsQueue, std::shared_ptr<MessageQueueThread> jsQueue,
std::unique_ptr<MessageQueueThread> nativeQueue,
std::shared_ptr<InstanceCallback> callback) std::shared_ptr<InstanceCallback> callback)
: m_destroyed(std::make_shared<bool>(false)) : m_destroyed(std::make_shared<bool>(false))
, m_mainExecutorToken(callback->createExecutorToken()) , m_mainExecutorToken(callback->createExecutorToken())
, m_delegate(std::make_shared<JsToNativeBridge>( , m_delegate(std::make_shared<JsToNativeBridge>(this, registry, callback)) {
this, registry, std::move(nativeQueue), callback)) {
std::unique_ptr<JSExecutor> mainExecutor = std::unique_ptr<JSExecutor> mainExecutor =
jsExecutorFactory->createJSExecutor(m_delegate, jsQueue); jsExecutorFactory->createJSExecutor(m_delegate, jsQueue);
// cached to avoid locked map lookup in the common case // cached to avoid locked map lookup in the common case
@ -129,7 +121,6 @@ void NativeToJsBridge::loadApplication(
startupScript=folly::makeMoveWrapper(std::move(startupScript)), startupScript=folly::makeMoveWrapper(std::move(startupScript)),
startupScriptSourceURL=std::move(startupScriptSourceURL)] startupScriptSourceURL=std::move(startupScriptSourceURL)]
(JSExecutor* executor) mutable { (JSExecutor* executor) mutable {
auto unbundle = unbundleWrap.move(); auto unbundle = unbundleWrap.move();
if (unbundle) { if (unbundle) {
executor->setJSModulesUnbundle(std::move(unbundle)); executor->setJSModulesUnbundle(std::move(unbundle));
@ -322,7 +313,6 @@ ExecutorToken NativeToJsBridge::getTokenForExecutor(JSExecutor& executor) {
} }
void NativeToJsBridge::destroy() { void NativeToJsBridge::destroy() {
m_delegate->quitQueueSynchronous();
auto* executorMessageQueueThread = getMessageQueueThread(m_mainExecutorToken); auto* executorMessageQueueThread = getMessageQueueThread(m_mainExecutorToken);
// All calls made through runOnExecutorQueue have an early exit if // All calls made through runOnExecutorQueue have an early exit if
// m_destroyed is true. Setting this before the runOnQueueSync will cause // m_destroyed is true. Setting this before the runOnQueueSync will cause
@ -331,7 +321,7 @@ void NativeToJsBridge::destroy() {
executorMessageQueueThread->runOnQueueSync([this, executorMessageQueueThread] { executorMessageQueueThread->runOnQueueSync([this, executorMessageQueueThread] {
m_mainExecutor->destroy(); m_mainExecutor->destroy();
executorMessageQueueThread->quitSynchronous(); executorMessageQueueThread->quitSynchronous();
unregisterExecutor(*m_mainExecutor); m_delegate->unregisterExecutor(*m_mainExecutor);
m_mainExecutor = nullptr; m_mainExecutor = nullptr;
}); });
} }

View File

@ -61,7 +61,6 @@ public:
JSExecutorFactory* jsExecutorFactory, JSExecutorFactory* jsExecutorFactory,
std::shared_ptr<ModuleRegistry> registry, std::shared_ptr<ModuleRegistry> registry,
std::shared_ptr<MessageQueueThread> jsQueue, std::shared_ptr<MessageQueueThread> jsQueue,
std::unique_ptr<MessageQueueThread> nativeQueue,
std::shared_ptr<InstanceCallback> callback); std::shared_ptr<InstanceCallback> callback);
virtual ~NativeToJsBridge(); virtual ~NativeToJsBridge();