Support ModuleHolder-based lazy init of C++ modules with C++ bridge on android
Reviewed By: AaaChiuuu Differential Revision: D4614479 fbshipit-source-id: 109ac34b8688f0113675e4a4479d1ddcc6169ed4
This commit is contained in:
parent
6410e256c5
commit
e622d51e20
|
@ -553,7 +553,8 @@ struct RCTInstanceCallback : public InstanceCallback {
|
|||
}
|
||||
modules.emplace_back(
|
||||
new QueueNativeModule(self, std::make_unique<CxxNativeModule>(
|
||||
_reactInstance, [(RCTCxxModule *)(moduleData.instance) move])));
|
||||
_reactInstance, [moduleData.name UTF8String],
|
||||
[moduleData] { return [(RCTCxxModule *)(moduleData.instance) move]; })));
|
||||
} else {
|
||||
modules.emplace_back(new RCTNativeModule(self, moduleData));
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
|||
final JavaScriptModuleRegistry jsModuleRegistry,
|
||||
final JSBundleLoader jsBundleLoader,
|
||||
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
|
||||
FLog.d(ReactConstants.TAG, "Initializing React Xplat Bridge.");
|
||||
FLog.w(ReactConstants.TAG, "Initializing React Xplat Bridge.");
|
||||
mHybridData = initHybrid();
|
||||
|
||||
mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
|
||||
|
@ -123,6 +123,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
|||
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
|
||||
mTraceListener = new JSProfilerTraceListener(this);
|
||||
|
||||
FLog.w(ReactConstants.TAG, "Initializing React Xplat Bridge before initializeBridge");
|
||||
initializeBridge(
|
||||
new BridgeCallback(this),
|
||||
jsExecutor,
|
||||
|
@ -130,6 +131,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
|||
mReactQueueConfiguration.getNativeModulesQueueThread(),
|
||||
mJavaRegistry.getJavaModules(this),
|
||||
mJavaRegistry.getCxxModules());
|
||||
FLog.w(ReactConstants.TAG, "Initializing React Xplat Bridge after initializeBridge");
|
||||
mMainExecutorToken = getMainExecutorToken();
|
||||
}
|
||||
|
||||
|
@ -182,7 +184,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
|
|||
MessageQueueThread jsQueue,
|
||||
MessageQueueThread moduleQueue,
|
||||
Collection<JavaModuleWrapper> javaModules,
|
||||
Collection<CxxModuleWrapper> cxxModules);
|
||||
Collection<ModuleHolder> cxxModules);
|
||||
|
||||
/**
|
||||
* This API is used in situations where the JS bundle is being executed not on
|
||||
|
|
|
@ -53,12 +53,12 @@ public class NativeModuleRegistry {
|
|||
return javaModules;
|
||||
}
|
||||
|
||||
/* package */ Collection<CxxModuleWrapper> getCxxModules() {
|
||||
ArrayList<CxxModuleWrapper> cxxModules = new ArrayList<>();
|
||||
/* package */ Collection<ModuleHolder> getCxxModules() {
|
||||
ArrayList<ModuleHolder> cxxModules = new ArrayList<>();
|
||||
for (Map.Entry<Class<? extends NativeModule>, ModuleHolder> entry : mModules.entrySet()) {
|
||||
Class<?> type = entry.getKey();
|
||||
if (CxxModuleWrapper.class.isAssignableFrom(type)) {
|
||||
cxxModules.add((CxxModuleWrapper) entry.getValue().getModule());
|
||||
cxxModules.add(entry.getValue());
|
||||
}
|
||||
}
|
||||
return cxxModules;
|
||||
|
|
|
@ -15,6 +15,7 @@ LOCAL_SRC_FILES := \
|
|||
JSLogging.cpp \
|
||||
JniJSModulesUnbundle.cpp \
|
||||
MethodInvoker.cpp \
|
||||
ModuleRegistryBuilder.cpp \
|
||||
NativeArray.cpp \
|
||||
NativeCommon.cpp \
|
||||
NativeMap.cpp \
|
||||
|
|
|
@ -6,6 +6,7 @@ EXPORTED_HEADERS = [
|
|||
"JExecutorToken.h",
|
||||
"JSLoader.h",
|
||||
"MethodInvoker.h",
|
||||
"ModuleRegistryBuilder.h",
|
||||
"NativeArray.h",
|
||||
"NativeCommon.h",
|
||||
"NativeMap.h",
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <cxxreact/ModuleRegistry.h>
|
||||
#include <cxxreact/CxxNativeModule.h>
|
||||
|
||||
#include "CxxModuleWrapper.h"
|
||||
#include "JavaScriptExecutorHolder.h"
|
||||
#include "JniJSModulesUnbundle.h"
|
||||
#include "JNativeRunnable.h"
|
||||
|
@ -128,21 +129,10 @@ void CatalystInstanceImpl::initializeBridge(
|
|||
jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue,
|
||||
jni::alias_ref<JavaMessageQueueThread::javaobject> moduleQueue,
|
||||
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
|
||||
jni::alias_ref<jni::JCollection<CxxModuleWrapper::javaobject>::javaobject> cxxModules) {
|
||||
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules) {
|
||||
// TODO mhorowitz: how to assert here?
|
||||
// Assertions.assertCondition(mBridge == null, "initializeBridge should be called once");
|
||||
|
||||
std::vector<std::unique_ptr<NativeModule>> modules;
|
||||
std::weak_ptr<Instance> winstance(instance_);
|
||||
for (const auto& jm : *javaModules) {
|
||||
modules.emplace_back(folly::make_unique<JavaNativeModule>(winstance, jm));
|
||||
}
|
||||
for (const auto& cm : *cxxModules) {
|
||||
modules.emplace_back(
|
||||
folly::make_unique<CxxNativeModule>(winstance, std::move(cthis(cm)->getModule())));
|
||||
}
|
||||
auto moduleRegistry = std::make_shared<ModuleRegistry>(std::move(modules));
|
||||
|
||||
// This used to be:
|
||||
//
|
||||
// Java CatalystInstanceImpl -> C++ CatalystInstanceImpl -> Bridge -> Bridge::Callback
|
||||
|
@ -163,7 +153,8 @@ void CatalystInstanceImpl::initializeBridge(
|
|||
jseh->getExecutorFactory(),
|
||||
folly::make_unique<JMessageQueueThread>(jsQueue),
|
||||
folly::make_unique<JMessageQueueThread>(moduleQueue),
|
||||
moduleRegistry);
|
||||
buildModuleRegistry(std::weak_ptr<Instance>(instance_),
|
||||
javaModules, cxxModules));
|
||||
}
|
||||
|
||||
void CatalystInstanceImpl::jniSetSourceURL(const std::string& sourceURL) {
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "JMessageQueueThread.h"
|
||||
#include "JSLoader.h"
|
||||
#include "JavaModuleWrapper.h"
|
||||
#include "ModuleRegistryBuilder.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
@ -48,7 +49,7 @@ class CatalystInstanceImpl : public jni::HybridClass<CatalystInstanceImpl> {
|
|||
jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue,
|
||||
jni::alias_ref<JavaMessageQueueThread::javaobject> moduleQueue,
|
||||
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
|
||||
jni::alias_ref<jni::JCollection<CxxModuleWrapper::javaobject>::javaobject> cxxModules);
|
||||
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules);
|
||||
|
||||
/**
|
||||
* Sets the source URL of the underlying bridge without loading any JS code.
|
||||
|
|
|
@ -12,7 +12,13 @@
|
|||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class CxxModuleWrapper : public jni::HybridClass<CxxModuleWrapper> {
|
||||
struct JNativeModule : jni::JavaClass<JNativeModule> {
|
||||
constexpr static const char *const kJavaDescriptor =
|
||||
"Lcom/facebook/react/bridge/NativeModule;";
|
||||
};
|
||||
|
||||
class CxxModuleWrapper :
|
||||
public jni::HybridClass<CxxModuleWrapper, JNativeModule> {
|
||||
public:
|
||||
constexpr static const char *const kJavaDescriptor =
|
||||
"Lcom/facebook/react/cxxbridge/CxxModuleWrapper;";
|
||||
|
|
|
@ -27,6 +27,8 @@ struct JavaModuleWrapper : jni::JavaClass<JavaModuleWrapper> {
|
|||
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/cxxbridge/JavaModuleWrapper;";
|
||||
|
||||
jni::local_ref<JBaseJavaModule::javaobject> getModule() {
|
||||
// This is the call which causes a lazy Java module to actually be
|
||||
// created.
|
||||
static auto getModule = javaClassStatic()->getMethod<JBaseJavaModule::javaobject()>("getModule");
|
||||
return getModule(self());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#include "ModuleRegistryBuilder.h"
|
||||
|
||||
#include <cxxreact/CxxNativeModule.h>
|
||||
#include <folly/Memory.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
std::string ModuleHolder::getName() const {
|
||||
static auto method = getClass()->getMethod<jstring()>("getName");
|
||||
return method(self())->toStdString();
|
||||
}
|
||||
|
||||
xplat::module::CxxModule::Provider ModuleHolder::getProvider() const {
|
||||
return [self=jni::make_global(self())] {
|
||||
static auto method =
|
||||
ModuleHolder::javaClassStatic()->getMethod<JNativeModule::javaobject()>(
|
||||
"getModule");
|
||||
// This is the call which uses the lazy Java Provider to instantiate the
|
||||
// Java CxxModuleWrapper which contains the CxxModule.
|
||||
auto module = method(self);
|
||||
CHECK(module->isInstanceOf(CxxModuleWrapper::javaClassStatic()))
|
||||
<< "module isn't a C++ module";
|
||||
auto cxxModule = jni::static_ref_cast<CxxModuleWrapper::javaobject>(module);
|
||||
// Then, we grab the CxxModule from the wrapper, which is no longer needed.
|
||||
return cxxModule->cthis()->getModule();
|
||||
};
|
||||
}
|
||||
|
||||
std::unique_ptr<ModuleRegistry> buildModuleRegistry(
|
||||
std::weak_ptr<Instance> winstance,
|
||||
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
|
||||
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules) {
|
||||
std::vector<std::unique_ptr<NativeModule>> modules;
|
||||
for (const auto& jm : *javaModules) {
|
||||
modules.emplace_back(folly::make_unique<JavaNativeModule>(winstance, jm));
|
||||
}
|
||||
for (const auto& cm : *cxxModules) {
|
||||
modules.emplace_back(
|
||||
folly::make_unique<CxxNativeModule>(winstance, cm->getName(), cm->getProvider()));
|
||||
}
|
||||
if (modules.empty()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return folly::make_unique<ModuleRegistry>(std::move(modules));
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <cxxreact/CxxModule.h>
|
||||
#include <cxxreact/ModuleRegistry.h>
|
||||
#include <fb/fbjni.h>
|
||||
|
||||
#include "CxxModuleWrapper.h"
|
||||
#include "JavaModuleWrapper.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class ModuleHolder : public jni::JavaClass<ModuleHolder> {
|
||||
public:
|
||||
static auto constexpr kJavaDescriptor =
|
||||
"Lcom/facebook/react/cxxbridge/ModuleHolder;";
|
||||
|
||||
std::string getName() const;
|
||||
xplat::module::CxxModule::Provider getProvider() const;
|
||||
};
|
||||
|
||||
std::unique_ptr<ModuleRegistry> buildModuleRegistry(
|
||||
std::weak_ptr<Instance> winstance,
|
||||
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
|
||||
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules);
|
||||
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ include $(CLEAR_VARS)
|
|||
LOCAL_MODULE := libreactnativefb
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
CxxMessageQueue.cpp \
|
||||
CxxNativeModule.cpp \
|
||||
Instance.cpp \
|
||||
JSCExecutor.cpp \
|
||||
|
|
|
@ -50,6 +50,8 @@ class CxxModule {
|
|||
class SyncTagType {};
|
||||
|
||||
public:
|
||||
typedef std::function<std::unique_ptr<CxxModule>()> Provider;
|
||||
|
||||
typedef std::function<void(std::vector<folly::dynamic>)> Callback;
|
||||
|
||||
constexpr static AsyncTagType AsyncTag = AsyncTagType();
|
||||
|
|
|
@ -47,18 +47,19 @@ CxxModule::Callback convertCallback(
|
|||
}
|
||||
|
||||
CxxNativeModule::CxxNativeModule(std::weak_ptr<Instance> instance,
|
||||
std::unique_ptr<CxxModule> module)
|
||||
std::string name,
|
||||
CxxModule::Provider provider)
|
||||
: instance_(instance)
|
||||
, module_(std::move(module))
|
||||
, methods_(module_->getMethods()) {
|
||||
module_->setInstance(instance);
|
||||
}
|
||||
, name_(std::move(name))
|
||||
, provider_(provider) {}
|
||||
|
||||
std::string CxxNativeModule::getName() {
|
||||
return module_->getName();
|
||||
return name_;
|
||||
}
|
||||
|
||||
std::vector<MethodDescriptor> CxxNativeModule::getMethods() {
|
||||
lazyInit();
|
||||
|
||||
std::vector<MethodDescriptor> descs;
|
||||
for (auto& method : methods_) {
|
||||
assert(method.func || method.syncFunc);
|
||||
|
@ -68,6 +69,8 @@ std::vector<MethodDescriptor> CxxNativeModule::getMethods() {
|
|||
}
|
||||
|
||||
folly::dynamic CxxNativeModule::getConstants() {
|
||||
lazyInit();
|
||||
|
||||
folly::dynamic constants = folly::dynamic::object();
|
||||
for (auto& pair : module_->getConstants()) {
|
||||
constants.insert(std::move(pair.first), std::move(pair.second));
|
||||
|
@ -168,5 +171,15 @@ MethodCallResult CxxNativeModule::callSerializableNativeHook(
|
|||
return method.syncFunc(std::move(args));
|
||||
}
|
||||
|
||||
void CxxNativeModule::lazyInit() {
|
||||
if (module_) {
|
||||
return;
|
||||
}
|
||||
|
||||
module_ = provider_();
|
||||
methods_ = module_->getMethods();
|
||||
module_->setInstance(instance_);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ std::function<void(folly::dynamic)> makeCallback(
|
|||
|
||||
class CxxNativeModule : public NativeModule {
|
||||
public:
|
||||
CxxNativeModule(std::weak_ptr<Instance> instance,
|
||||
std::unique_ptr<xplat::module::CxxModule> module);
|
||||
CxxNativeModule(std::weak_ptr<Instance> instance, std::string name,
|
||||
xplat::module::CxxModule::Provider provider);
|
||||
|
||||
std::string getName() override;
|
||||
std::vector<MethodDescriptor> getMethods() override;
|
||||
|
@ -27,7 +27,11 @@ public:
|
|||
ExecutorToken token, unsigned int hookId, folly::dynamic&& args) override;
|
||||
|
||||
private:
|
||||
void lazyInit();
|
||||
|
||||
std::weak_ptr<Instance> instance_;
|
||||
std::string name_;
|
||||
xplat::module::CxxModule::Provider provider_;
|
||||
std::unique_ptr<xplat::module::CxxModule> module_;
|
||||
std::vector<xplat::module::CxxModule::Method> methods_;
|
||||
};
|
||||
|
|
|
@ -40,7 +40,7 @@ void Instance::initializeBridge(
|
|||
if (!nativeQueue) {
|
||||
// TODO pass down a thread/queue from java, instead of creating our own.
|
||||
|
||||
auto queue = std::make_unique<CxxMessageQueue>();
|
||||
auto queue = folly::make_unique<CxxMessageQueue>();
|
||||
std::thread t(queue->getUnregisteredRunLoop());
|
||||
t.detach();
|
||||
nativeQueue = std::move(queue);
|
||||
|
|
|
@ -361,12 +361,8 @@ void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> scrip
|
|||
|
||||
evaluateSourceCode(m_context, bcSourceCode, jsSourceURL);
|
||||
|
||||
// TODO(luk): t13903306 Remove this check once we make native modules
|
||||
// working for java2js
|
||||
if (m_delegate) {
|
||||
bindBridge();
|
||||
flush();
|
||||
}
|
||||
|
||||
ReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
|
||||
ReactMarker::logMarker("RUN_JS_BUNDLE_END");
|
||||
|
@ -416,11 +412,8 @@ void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> scrip
|
|||
evaluateScript(m_context, jsScript, jsSourceURL);
|
||||
}
|
||||
|
||||
// TODO(luk): t13903306 Remove this check once we make native modules working for java2js
|
||||
if (m_delegate) {
|
||||
bindBridge();
|
||||
flush();
|
||||
}
|
||||
|
||||
ReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
|
||||
ReactMarker::logMarker("RUN_JS_BUNDLE_END");
|
||||
|
@ -435,6 +428,9 @@ void JSCExecutor::setJSModulesUnbundle(std::unique_ptr<JSModulesUnbundle> unbund
|
|||
|
||||
void JSCExecutor::bindBridge() throw(JSException) {
|
||||
SystraceSection s("JSCExecutor::bindBridge");
|
||||
if (!m_delegate || !m_delegate->getModuleRegistry()) {
|
||||
return;
|
||||
}
|
||||
auto global = Object::getGlobalObject(m_context);
|
||||
auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");
|
||||
if (batchedBridgeValue.isUndefined()) {
|
||||
|
@ -466,7 +462,18 @@ void JSCExecutor::callNativeModules(Value&& value) {
|
|||
|
||||
void JSCExecutor::flush() {
|
||||
SystraceSection s("JSCExecutor::flush");
|
||||
if (!m_delegate) {
|
||||
// do nothing
|
||||
} else if (!m_delegate->getModuleRegistry()) {
|
||||
callNativeModules(Value::makeNull(m_context));
|
||||
} else {
|
||||
// If this is failing, chances are you have provided a delegate with a
|
||||
// module registry, but haven't loaded the JS which enables native function
|
||||
// queueing. Add BatchedBridge.js to your bundle, pass a nullptr delegate,
|
||||
// or make delegate->getModuleRegistry() return nullptr.
|
||||
CHECK(m_flushedQueueJS) << "Attempting to use native methods without loading BatchedBridge.js";
|
||||
callNativeModules(m_flushedQueueJS->callAsFunction({}));
|
||||
}
|
||||
}
|
||||
|
||||
void JSCExecutor::callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) {
|
||||
|
@ -476,6 +483,9 @@ void JSCExecutor::callFunction(const std::string& moduleId, const std::string& m
|
|||
|
||||
auto result = [&] {
|
||||
try {
|
||||
// See flush()
|
||||
CHECK(m_callFunctionReturnFlushedQueueJS)
|
||||
<< "Attempting to call native methods without loading BatchedBridge.js";
|
||||
return m_callFunctionReturnFlushedQueueJS->callAsFunction({
|
||||
Value(m_context, String::createExpectingAscii(m_context, moduleId)),
|
||||
Value(m_context, String::createExpectingAscii(m_context, methodId)),
|
||||
|
@ -511,6 +521,8 @@ Value JSCExecutor::callFunctionSyncWithValue(
|
|||
const std::string& module, const std::string& method, Value args) {
|
||||
SystraceSection s("JSCExecutor::callFunction");
|
||||
|
||||
// See flush()
|
||||
CHECK(m_callFunctionReturnResultAndFlushedQueueJS);
|
||||
Object result = m_callFunctionReturnResultAndFlushedQueueJS->callAsFunction({
|
||||
Value(m_context, String::createExpectingAscii(m_context, module)),
|
||||
Value(m_context, String::createExpectingAscii(m_context, method)),
|
||||
|
|
|
@ -11,6 +11,10 @@ JSCNativeModules::JSCNativeModules(std::shared_ptr<ModuleRegistry> moduleRegistr
|
|||
m_moduleRegistry(std::move(moduleRegistry)) {}
|
||||
|
||||
JSValueRef JSCNativeModules::getModule(JSContextRef context, JSStringRef jsName) {
|
||||
if (!m_moduleRegistry) {
|
||||
return Value::makeUndefined(context);
|
||||
}
|
||||
|
||||
std::string moduleName = String::ref(context, jsName).str();
|
||||
|
||||
const auto it = m_objects.find(moduleName);
|
||||
|
|
|
@ -47,6 +47,9 @@ public:
|
|||
|
||||
void callNativeModules(
|
||||
JSExecutor& executor, folly::dynamic&& calls, bool isEndOfBatch) override {
|
||||
|
||||
CHECK(m_registry || calls.empty()) <<
|
||||
"native module calls cannot be completed with no native modules";
|
||||
ExecutorToken token = m_nativeToJs->getTokenForExecutor(executor);
|
||||
m_nativeQueue->runOnQueue([this, token, calls=std::move(calls), isEndOfBatch] () mutable {
|
||||
// An exception anywhere in here stops processing of the batch. This
|
||||
|
@ -95,13 +98,8 @@ NativeToJsBridge::NativeToJsBridge(
|
|||
std::shared_ptr<InstanceCallback> callback)
|
||||
: m_destroyed(std::make_shared<bool>(false))
|
||||
, m_mainExecutorToken(callback->createExecutorToken())
|
||||
, m_delegate(registry
|
||||
? std::make_shared<JsToNativeBridge>(
|
||||
this, registry, std::move(nativeQueue), callback)
|
||||
: nullptr) {
|
||||
if (!m_delegate) {
|
||||
nativeQueue->quitSynchronous();
|
||||
}
|
||||
, m_delegate(std::make_shared<JsToNativeBridge>(
|
||||
this, registry, std::move(nativeQueue), callback)) {
|
||||
std::unique_ptr<JSExecutor> mainExecutor =
|
||||
jsExecutorFactory->createJSExecutor(m_delegate, jsQueue);
|
||||
// cached to avoid locked map lookup in the common case
|
||||
|
@ -318,9 +316,7 @@ ExecutorToken NativeToJsBridge::getTokenForExecutor(JSExecutor& executor) {
|
|||
}
|
||||
|
||||
void NativeToJsBridge::destroy() {
|
||||
if (m_delegate) {
|
||||
m_delegate->quitQueueSynchronous();
|
||||
}
|
||||
auto* executorMessageQueueThread = getMessageQueueThread(m_mainExecutorToken);
|
||||
// All calls made through runOnExecutorQueue have an early exit if
|
||||
// m_destroyed is true. Setting this before the runOnQueueSync will cause
|
||||
|
|
|
@ -305,6 +305,10 @@ public:
|
|||
return Value(ctx, JSC_JSValueMakeUndefined(ctx));
|
||||
}
|
||||
|
||||
static Value makeNull(JSContextRef ctx) {
|
||||
return Value(ctx, JSC_JSValueMakeNull(ctx));
|
||||
}
|
||||
|
||||
std::string toJSONString(unsigned indent = 0) const;
|
||||
static Value fromJSON(JSContextRef ctx, const String& json);
|
||||
static JSValueRef fromDynamic(JSContextRef ctx, const folly::dynamic& value);
|
||||
|
|
Loading…
Reference in New Issue