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:
Dhaval Kapil 2019-03-25 09:08:47 -07:00 коммит произвёл Facebook Github Bot
Родитель 9db347fabc
Коммит 64f3a87c9d
4 изменённых файлов: 108 добавлений и 102 удалений

Просмотреть файл

@ -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