Remove JsToNativeBridge's nativeQueue
Reviewed By: mhorowitz Differential Revision: D4589737 fbshipit-source-id: 3b2730417d99c4f98cfaad386bc50328f2551592
This commit is contained in:
parent
fbf6d1aaeb
commit
d7b37c4050
|
@ -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 &¶ms) 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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue