Refactor JSIExecutor to use runtimeInstaller for injecting the logger instance
Summary: This is based on the work done in D8686586. Removed the logger instance from JSIExecutor constructor and installed it into the runtimeInstaller at all call sites. Reviewed By: mhorowitz Differential Revision: D14444120 fbshipit-source-id: 0476fda4230c467573ea04102a12101bcdf36c53
This commit is contained in:
Родитель
9db347fabc
Коммит
64f3a87c9d
|
@ -14,18 +14,25 @@ namespace facebook {
|
|||
namespace react {
|
||||
|
||||
std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(
|
||||
std::shared_ptr<ExecutorDelegate> delegate,
|
||||
std::shared_ptr<MessageQueueThread> __unused jsQueue) {
|
||||
return folly::make_unique<JSIExecutor>(
|
||||
facebook::jsc::makeJSCRuntime(),
|
||||
delegate,
|
||||
[](const std::string &message, unsigned int logLevel) {
|
||||
std::shared_ptr<ExecutorDelegate> delegate,
|
||||
std::shared_ptr<MessageQueueThread> __unused jsQueue) {
|
||||
auto installBindings = [runtimeInstaller=runtimeInstaller_](jsi::Runtime &runtime) {
|
||||
react::Logger iosLoggingBinder = [](const std::string &message, unsigned int logLevel) {
|
||||
_RCTLogJavaScriptInternal(
|
||||
static_cast<RCTLogLevel>(logLevel),
|
||||
[NSString stringWithUTF8String:message.c_str()]);
|
||||
},
|
||||
JSIExecutor::defaultTimeoutInvoker,
|
||||
std::move(runtimeInstaller_));
|
||||
};
|
||||
react::bindNativeLogger(runtime, iosLoggingBinder);
|
||||
// Wrap over the original runtimeInstaller
|
||||
if (runtimeInstaller) {
|
||||
runtimeInstaller(runtime);
|
||||
}
|
||||
};
|
||||
return folly::make_unique<JSIExecutor>(
|
||||
facebook::jsc::makeJSCRuntime(),
|
||||
delegate,
|
||||
JSIExecutor::defaultTimeoutInvoker,
|
||||
std::move(installBindings));
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
// Copyright (c) Facebook, Inc. and its affiliates.
|
||||
//
|
||||
// This source code is licensed under the MIT license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
|
||||
#include <fb/fbjni.h>
|
||||
#include <folly/Memory.h>
|
||||
#include <jsi/JSCRuntime.h>
|
||||
#include <jsireact/JSIExecutor.h>
|
||||
#include <react/jni/JavaScriptExecutorHolder.h>
|
||||
#include <react/jni/JReactMarker.h>
|
||||
#include <react/jni/JSLogging.h>
|
||||
#include <react/jni/JavaScriptExecutorHolder.h>
|
||||
#include <react/jni/ReadableNativeMap.h>
|
||||
|
||||
namespace facebook {
|
||||
|
@ -18,32 +18,37 @@ namespace react {
|
|||
namespace {
|
||||
|
||||
class JSCExecutorFactory : public JSExecutorFactory {
|
||||
public:
|
||||
public:
|
||||
std::unique_ptr<JSExecutor> createJSExecutor(
|
||||
std::shared_ptr<ExecutorDelegate> delegate,
|
||||
std::shared_ptr<MessageQueueThread> jsQueue) override {
|
||||
auto installBindings = [](jsi::Runtime &runtime) {
|
||||
react::Logger androidLogger =
|
||||
static_cast<void (*)(const std::string &, unsigned int)>(
|
||||
&reactAndroidLoggingHook);
|
||||
react::bindNativeLogger(runtime, androidLogger);
|
||||
};
|
||||
return folly::make_unique<JSIExecutor>(
|
||||
jsc::makeJSCRuntime(),
|
||||
delegate,
|
||||
[](const std::string& message, unsigned int logLevel) {
|
||||
reactAndroidLoggingHook(message, logLevel);
|
||||
},
|
||||
JSIExecutor::defaultTimeoutInvoker,
|
||||
nullptr);
|
||||
jsc::makeJSCRuntime(),
|
||||
delegate,
|
||||
JSIExecutor::defaultTimeoutInvoker,
|
||||
installBindings);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// This is not like JSCJavaScriptExecutor, which calls JSC directly. This uses
|
||||
// JSIExecutor with JSCRuntime.
|
||||
class JSCExecutorHolder
|
||||
: public jni::HybridClass<JSCExecutorHolder, JavaScriptExecutorHolder> {
|
||||
public:
|
||||
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/jscexecutor/JSCExecutor;";
|
||||
static constexpr auto kJavaDescriptor =
|
||||
"Lcom/facebook/react/jscexecutor/JSCExecutor;";
|
||||
|
||||
static jni::local_ref<jhybriddata> initHybrid(
|
||||
jni::alias_ref<jclass>, ReadableNativeMap*) {
|
||||
jni::alias_ref<jclass>,
|
||||
ReadableNativeMap *) {
|
||||
// This is kind of a weird place for stuff, but there's no other
|
||||
// good place for initialization which is specific to JSC on
|
||||
// Android.
|
||||
|
@ -54,7 +59,7 @@ class JSCExecutorHolder
|
|||
|
||||
static void registerNatives() {
|
||||
registerHybrid({
|
||||
makeNativeMethod("initHybrid", JSCExecutorHolder::initHybrid),
|
||||
makeNativeMethod("initHybrid", JSCExecutorHolder::initHybrid),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -66,8 +71,7 @@ class JSCExecutorHolder
|
|||
} // namespace react
|
||||
} // namespace facebook
|
||||
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
return facebook::jni::initialize(vm, [] {
|
||||
facebook::react::JSCExecutorHolder::registerNatives();
|
||||
});
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
return facebook::jni::initialize(
|
||||
vm, [] { facebook::react::JSCExecutorHolder::registerNatives(); });
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) Facebook, Inc. and its affiliates.
|
||||
//
|
||||
// This source code is licensed under the MIT license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
|
||||
#include "jsireact/JSIExecutor.h"
|
||||
|
||||
|
@ -24,9 +24,9 @@ namespace react {
|
|||
|
||||
class JSIExecutor::NativeModuleProxy : public jsi::HostObject {
|
||||
public:
|
||||
NativeModuleProxy(JSIExecutor& executor) : executor_(executor) {}
|
||||
NativeModuleProxy(JSIExecutor &executor) : executor_(executor) {}
|
||||
|
||||
Value get(Runtime& rt, const PropNameID& name) override {
|
||||
Value get(Runtime &rt, const PropNameID &name) override {
|
||||
if (name.utf8(rt) == "name") {
|
||||
return jsi::String::createFromAscii(rt, "NativeModules");
|
||||
}
|
||||
|
@ -34,19 +34,19 @@ class JSIExecutor::NativeModuleProxy : public jsi::HostObject {
|
|||
return executor_.nativeModules_.getModule(rt, name);
|
||||
}
|
||||
|
||||
void set(Runtime&, const PropNameID&, const Value&) override {
|
||||
void set(Runtime &, const PropNameID &, const Value &) override {
|
||||
throw std::runtime_error(
|
||||
"Unable to put on NativeModules: Operation unsupported");
|
||||
}
|
||||
|
||||
private:
|
||||
JSIExecutor& executor_;
|
||||
JSIExecutor &executor_;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
// basename_r isn't in all iOS SDKs, so use this simple version instead.
|
||||
std::string simpleBasename(const std::string& path) {
|
||||
std::string simpleBasename(const std::string &path) {
|
||||
size_t pos = path.rfind("/");
|
||||
return (pos != std::string::npos) ? path.substr(pos) : path;
|
||||
}
|
||||
|
@ -56,13 +56,11 @@ std::string simpleBasename(const std::string& path) {
|
|||
JSIExecutor::JSIExecutor(
|
||||
std::shared_ptr<jsi::Runtime> runtime,
|
||||
std::shared_ptr<ExecutorDelegate> delegate,
|
||||
Logger logger,
|
||||
const JSIScopedTimeoutInvoker& scopedTimeoutInvoker,
|
||||
const JSIScopedTimeoutInvoker &scopedTimeoutInvoker,
|
||||
RuntimeInstaller runtimeInstaller)
|
||||
: runtime_(runtime),
|
||||
delegate_(delegate),
|
||||
nativeModules_(delegate ? delegate->getModuleRegistry() : nullptr),
|
||||
logger_(logger),
|
||||
scopedTimeoutInvoker_(scopedTimeoutInvoker),
|
||||
runtimeInstaller_(runtimeInstaller) {
|
||||
runtime_->global().setProperty(
|
||||
|
@ -90,9 +88,9 @@ void JSIExecutor::loadApplicationScript(
|
|||
PropNameID::forAscii(*runtime_, "nativeFlushQueueImmediate"),
|
||||
1,
|
||||
[this](
|
||||
jsi::Runtime&,
|
||||
const jsi::Value&,
|
||||
const jsi::Value* args,
|
||||
jsi::Runtime &,
|
||||
const jsi::Value &,
|
||||
const jsi::Value *args,
|
||||
size_t count) {
|
||||
if (count != 1) {
|
||||
throw std::invalid_argument(
|
||||
|
@ -110,36 +108,11 @@ void JSIExecutor::loadApplicationScript(
|
|||
PropNameID::forAscii(*runtime_, "nativeCallSyncHook"),
|
||||
1,
|
||||
[this](
|
||||
jsi::Runtime&,
|
||||
const jsi::Value&,
|
||||
const jsi::Value* args,
|
||||
jsi::Runtime &,
|
||||
const jsi::Value &,
|
||||
const jsi::Value *args,
|
||||
size_t count) { return nativeCallSyncHook(args, count); }));
|
||||
|
||||
if (logger_) {
|
||||
// Only inject the logging function if it was supplied by the caller.
|
||||
runtime_->global().setProperty(
|
||||
*runtime_,
|
||||
"nativeLoggingHook",
|
||||
Function::createFromHostFunction(
|
||||
*runtime_,
|
||||
PropNameID::forAscii(*runtime_, "nativeLoggingHook"),
|
||||
2,
|
||||
[this](
|
||||
jsi::Runtime&,
|
||||
const jsi::Value&,
|
||||
const jsi::Value* args,
|
||||
size_t count) {
|
||||
if (count != 2) {
|
||||
throw std::invalid_argument(
|
||||
"nativeLoggingHook takes 2 arguments");
|
||||
}
|
||||
logger_(
|
||||
args[0].asString(*runtime_).utf8(*runtime_),
|
||||
folly::to<unsigned int>(args[1].asNumber()));
|
||||
return Value::undefined();
|
||||
}));
|
||||
}
|
||||
|
||||
if (runtimeInstaller_) {
|
||||
runtimeInstaller_(*runtime_);
|
||||
}
|
||||
|
@ -170,9 +143,9 @@ void JSIExecutor::setBundleRegistry(std::unique_ptr<RAMBundleRegistry> r) {
|
|||
PropNameID::forAscii(*runtime_, "nativeRequire"),
|
||||
2,
|
||||
[this](
|
||||
__unused Runtime& rt,
|
||||
const facebook::jsi::Value&,
|
||||
const facebook::jsi::Value* args,
|
||||
__unused Runtime &rt,
|
||||
const facebook::jsi::Value &,
|
||||
const facebook::jsi::Value *args,
|
||||
size_t count) { return nativeRequire(args, count); }));
|
||||
}
|
||||
bundleRegistry_ = std::move(r);
|
||||
|
@ -180,7 +153,7 @@ void JSIExecutor::setBundleRegistry(std::unique_ptr<RAMBundleRegistry> r) {
|
|||
|
||||
void JSIExecutor::registerBundle(
|
||||
uint32_t bundleId,
|
||||
const std::string& bundlePath) {
|
||||
const std::string &bundlePath) {
|
||||
const auto tag = folly::to<std::string>(bundleId);
|
||||
ReactMarker::logTaggedMarker(
|
||||
ReactMarker::REGISTER_JS_SEGMENT_START, tag.c_str());
|
||||
|
@ -197,9 +170,9 @@ void JSIExecutor::registerBundle(
|
|||
}
|
||||
|
||||
void JSIExecutor::callFunction(
|
||||
const std::string& moduleId,
|
||||
const std::string& methodId,
|
||||
const folly::dynamic& arguments) {
|
||||
const std::string &moduleId,
|
||||
const std::string &methodId,
|
||||
const folly::dynamic &arguments) {
|
||||
SystraceSection s(
|
||||
"JSIExecutor::callFunction", "moduleId", moduleId, "methodId", methodId);
|
||||
if (!callFunctionReturnFlushedQueue_) {
|
||||
|
@ -237,7 +210,7 @@ void JSIExecutor::callFunction(
|
|||
|
||||
void JSIExecutor::invokeCallback(
|
||||
const double callbackId,
|
||||
const folly::dynamic& arguments) {
|
||||
const folly::dynamic &arguments) {
|
||||
SystraceSection s("JSIExecutor::invokeCallback", "callbackId", callbackId);
|
||||
if (!invokeCallbackAndReturnFlushedQueue_) {
|
||||
bindBridge();
|
||||
|
@ -263,7 +236,7 @@ void JSIExecutor::setGlobalVariable(
|
|||
propName.c_str(),
|
||||
Value::createFromJsonUtf8(
|
||||
*runtime_,
|
||||
reinterpret_cast<const uint8_t*>(jsonValue->c_str()),
|
||||
reinterpret_cast<const uint8_t *>(jsonValue->c_str()),
|
||||
jsonValue->size()));
|
||||
}
|
||||
|
||||
|
@ -271,7 +244,7 @@ std::string JSIExecutor::getDescription() {
|
|||
return "JSI " + runtime_->description();
|
||||
}
|
||||
|
||||
void* JSIExecutor::getJavaScriptContext() {
|
||||
void *JSIExecutor::getJavaScriptContext() {
|
||||
return runtime_.get();
|
||||
}
|
||||
|
||||
|
@ -286,7 +259,7 @@ void JSIExecutor::bindBridge() {
|
|||
runtime_->global().getProperty(*runtime_, "__fbBatchedBridge");
|
||||
if (batchedBridgeValue.isUndefined()) {
|
||||
throw JSINativeException(
|
||||
"Could not get BatchedBridge, make sure your bundle is packaged correctly");
|
||||
"Could not get BatchedBridge, make sure your bundle is packaged correctly");
|
||||
}
|
||||
|
||||
Object batchedBridge = batchedBridgeValue.asObject(*runtime_);
|
||||
|
@ -302,7 +275,7 @@ void JSIExecutor::bindBridge() {
|
|||
});
|
||||
}
|
||||
|
||||
void JSIExecutor::callNativeModules(const Value& queue, bool isEndOfBatch) {
|
||||
void JSIExecutor::callNativeModules(const Value &queue, bool isEndOfBatch) {
|
||||
SystraceSection s("JSIExecutor::callNativeModules");
|
||||
// If this fails, you need to pass a fully functional delegate with a
|
||||
// module registry to the factory/ctor.
|
||||
|
@ -345,7 +318,7 @@ void JSIExecutor::flush() {
|
|||
}
|
||||
}
|
||||
|
||||
Value JSIExecutor::nativeRequire(const Value* args, size_t count) {
|
||||
Value JSIExecutor::nativeRequire(const Value *args, size_t count) {
|
||||
if (count > 2 || count == 0) {
|
||||
throw std::invalid_argument("Got wrong number of args");
|
||||
}
|
||||
|
@ -359,7 +332,7 @@ Value JSIExecutor::nativeRequire(const Value* args, size_t count) {
|
|||
return facebook::jsi::Value();
|
||||
}
|
||||
|
||||
Value JSIExecutor::nativeCallSyncHook(const Value* args, size_t count) {
|
||||
Value JSIExecutor::nativeCallSyncHook(const Value *args, size_t count) {
|
||||
if (count != 3) {
|
||||
throw std::invalid_argument("nativeCallSyncHook arg count must be 3");
|
||||
}
|
||||
|
@ -381,5 +354,29 @@ Value JSIExecutor::nativeCallSyncHook(const Value* args, size_t count) {
|
|||
return valueFromDynamic(*runtime_, result.value());
|
||||
}
|
||||
|
||||
void bindNativeLogger(Runtime &runtime, Logger logger) {
|
||||
runtime.global().setProperty(
|
||||
runtime,
|
||||
"nativeLoggingHook",
|
||||
Function::createFromHostFunction(
|
||||
runtime,
|
||||
PropNameID::forAscii(runtime, "nativeLoggingHook"),
|
||||
2,
|
||||
[logger = std::move(logger)](
|
||||
jsi::Runtime &runtime,
|
||||
const jsi::Value &,
|
||||
const jsi::Value *args,
|
||||
size_t count) {
|
||||
if (count != 2) {
|
||||
throw std::invalid_argument(
|
||||
"nativeLoggingHook takes 2 arguments");
|
||||
}
|
||||
logger(
|
||||
args[0].asString(runtime).utf8(runtime),
|
||||
folly::to<unsigned int>(args[1].asNumber()));
|
||||
return Value::undefined();
|
||||
}));
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) Facebook, Inc. and its affiliates.
|
||||
//
|
||||
// This source code is licensed under the MIT license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
|
||||
#pragma once
|
||||
|
||||
|
@ -46,7 +46,7 @@ namespace react {
|
|||
// })
|
||||
//
|
||||
using JSIScopedTimeoutInvoker = std::function<void(
|
||||
const std::function<void()>& invokee,
|
||||
const std::function<void()> &invokee,
|
||||
std::function<std::string()> errorMessageProducer)>;
|
||||
|
||||
class BigStringBuffer : public jsi::Buffer {
|
||||
|
@ -58,8 +58,8 @@ class BigStringBuffer : public jsi::Buffer {
|
|||
return script_->size();
|
||||
}
|
||||
|
||||
const uint8_t* data() const override {
|
||||
return reinterpret_cast<const uint8_t*>(script_->c_str());
|
||||
const uint8_t *data() const override {
|
||||
return reinterpret_cast<const uint8_t *>(script_->c_str());
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -68,40 +68,36 @@ class BigStringBuffer : public jsi::Buffer {
|
|||
|
||||
class JSIExecutor : public JSExecutor {
|
||||
public:
|
||||
using Logger =
|
||||
std::function<void(const std::string& message, unsigned int logLevel)>;
|
||||
|
||||
using RuntimeInstaller = std::function<void(jsi::Runtime& runtime)>;
|
||||
using RuntimeInstaller = std::function<void(jsi::Runtime &runtime)>;
|
||||
|
||||
JSIExecutor(
|
||||
std::shared_ptr<jsi::Runtime> runtime,
|
||||
std::shared_ptr<ExecutorDelegate> delegate,
|
||||
Logger logger,
|
||||
const JSIScopedTimeoutInvoker& timeoutInvoker,
|
||||
const JSIScopedTimeoutInvoker &timeoutInvoker,
|
||||
RuntimeInstaller runtimeInstaller);
|
||||
void loadApplicationScript(
|
||||
std::unique_ptr<const JSBigString> script,
|
||||
std::string sourceURL) override;
|
||||
void setBundleRegistry(std::unique_ptr<RAMBundleRegistry>) override;
|
||||
void registerBundle(uint32_t bundleId, const std::string& bundlePath)
|
||||
void registerBundle(uint32_t bundleId, const std::string &bundlePath)
|
||||
override;
|
||||
void callFunction(
|
||||
const std::string& moduleId,
|
||||
const std::string& methodId,
|
||||
const folly::dynamic& arguments) override;
|
||||
void invokeCallback(const double callbackId, const folly::dynamic& arguments)
|
||||
const std::string &moduleId,
|
||||
const std::string &methodId,
|
||||
const folly::dynamic &arguments) override;
|
||||
void invokeCallback(const double callbackId, const folly::dynamic &arguments)
|
||||
override;
|
||||
void setGlobalVariable(
|
||||
std::string propName,
|
||||
std::unique_ptr<const JSBigString> jsonValue) override;
|
||||
std::string getDescription() override;
|
||||
void* getJavaScriptContext() override;
|
||||
void *getJavaScriptContext() override;
|
||||
bool isInspectable() override;
|
||||
|
||||
// An implementation of JSIScopedTimeoutInvoker that simply runs the
|
||||
// invokee, with no timeout.
|
||||
static void defaultTimeoutInvoker(
|
||||
const std::function<void()>& invokee,
|
||||
const std::function<void()> &invokee,
|
||||
std::function<std::string()> errorMessageProducer) {
|
||||
(void)errorMessageProducer;
|
||||
invokee();
|
||||
|
@ -112,16 +108,15 @@ class JSIExecutor : public JSExecutor {
|
|||
|
||||
void flush();
|
||||
void bindBridge();
|
||||
void callNativeModules(const jsi::Value& queue, bool isEndOfBatch);
|
||||
jsi::Value nativeCallSyncHook(const jsi::Value* args, size_t count);
|
||||
jsi::Value nativeRequire(const jsi::Value* args, size_t count);
|
||||
void callNativeModules(const jsi::Value &queue, bool isEndOfBatch);
|
||||
jsi::Value nativeCallSyncHook(const jsi::Value *args, size_t count);
|
||||
jsi::Value nativeRequire(const jsi::Value *args, size_t count);
|
||||
|
||||
std::shared_ptr<jsi::Runtime> runtime_;
|
||||
std::shared_ptr<ExecutorDelegate> delegate_;
|
||||
JSINativeModules nativeModules_;
|
||||
std::once_flag bindFlag_;
|
||||
std::unique_ptr<RAMBundleRegistry> bundleRegistry_;
|
||||
Logger logger_;
|
||||
JSIScopedTimeoutInvoker scopedTimeoutInvoker_;
|
||||
RuntimeInstaller runtimeInstaller_;
|
||||
|
||||
|
@ -131,5 +126,8 @@ class JSIExecutor : public JSExecutor {
|
|||
folly::Optional<jsi::Function> callFunctionReturnResultAndFlushedQueue_;
|
||||
};
|
||||
|
||||
using Logger =
|
||||
std::function<void(const std::string &message, unsigned int logLevel)>;
|
||||
void bindNativeLogger(jsi::Runtime &runtime, Logger logger);
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
|
|
Загрузка…
Ссылка в новой задаче