diff --git a/React/CxxBridge/JSCExecutorFactory.mm b/React/CxxBridge/JSCExecutorFactory.mm index 87b4bc5229..3f4cbd1799 100644 --- a/React/CxxBridge/JSCExecutorFactory.mm +++ b/React/CxxBridge/JSCExecutorFactory.mm @@ -14,18 +14,25 @@ namespace facebook { namespace react { std::unique_ptr JSCExecutorFactory::createJSExecutor( - std::shared_ptr delegate, - std::shared_ptr __unused jsQueue) { - return folly::make_unique( - facebook::jsc::makeJSCRuntime(), - delegate, - [](const std::string &message, unsigned int logLevel) { + std::shared_ptr delegate, + std::shared_ptr __unused jsQueue) { + auto installBindings = [runtimeInstaller=runtimeInstaller_](jsi::Runtime &runtime) { + react::Logger iosLoggingBinder = [](const std::string &message, unsigned int logLevel) { _RCTLogJavaScriptInternal( static_cast(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( + facebook::jsc::makeJSCRuntime(), + delegate, + JSIExecutor::defaultTimeoutInvoker, + std::move(installBindings)); } } // namespace react diff --git a/ReactAndroid/src/main/java/com/facebook/react/jscexecutor/OnLoad.cpp b/ReactAndroid/src/main/java/com/facebook/react/jscexecutor/OnLoad.cpp index 71e62afe0f..ebf4d22683 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/jscexecutor/OnLoad.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/jscexecutor/OnLoad.cpp @@ -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 #include #include #include -#include #include #include +#include #include namespace facebook { @@ -18,32 +18,37 @@ namespace react { namespace { class JSCExecutorFactory : public JSExecutorFactory { -public: + public: std::unique_ptr createJSExecutor( std::shared_ptr delegate, std::shared_ptr jsQueue) override { + auto installBindings = [](jsi::Runtime &runtime) { + react::Logger androidLogger = + static_cast( + &reactAndroidLoggingHook); + react::bindNativeLogger(runtime, androidLogger); + }; return folly::make_unique( - 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 { public: - static constexpr auto kJavaDescriptor = "Lcom/facebook/react/jscexecutor/JSCExecutor;"; + static constexpr auto kJavaDescriptor = + "Lcom/facebook/react/jscexecutor/JSCExecutor;"; static jni::local_ref initHybrid( - jni::alias_ref, ReadableNativeMap*) { + jni::alias_ref, + 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(); }); } diff --git a/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp b/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp index 8025d9672d..e7ec74077f 100644 --- a/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp +++ b/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp @@ -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 runtime, std::shared_ptr 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(args[1].asNumber())); - return Value::undefined(); - })); - } - if (runtimeInstaller_) { runtimeInstaller_(*runtime_); } @@ -170,9 +143,9 @@ void JSIExecutor::setBundleRegistry(std::unique_ptr 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 r) { void JSIExecutor::registerBundle( uint32_t bundleId, - const std::string& bundlePath) { + const std::string &bundlePath) { const auto tag = folly::to(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(jsonValue->c_str()), + reinterpret_cast(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(args[1].asNumber())); + return Value::undefined(); + })); +} + } // namespace react } // namespace facebook diff --git a/ReactCommon/jsiexecutor/jsireact/JSIExecutor.h b/ReactCommon/jsiexecutor/jsireact/JSIExecutor.h index 27d3b7dce3..1eea5d5bce 100644 --- a/ReactCommon/jsiexecutor/jsireact/JSIExecutor.h +++ b/ReactCommon/jsiexecutor/jsireact/JSIExecutor.h @@ -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& invokee, + const std::function &invokee, std::function 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(script_->c_str()); + const uint8_t *data() const override { + return reinterpret_cast(script_->c_str()); } private: @@ -68,40 +68,36 @@ class BigStringBuffer : public jsi::Buffer { class JSIExecutor : public JSExecutor { public: - using Logger = - std::function; - - using RuntimeInstaller = std::function; + using RuntimeInstaller = std::function; JSIExecutor( std::shared_ptr runtime, std::shared_ptr delegate, - Logger logger, - const JSIScopedTimeoutInvoker& timeoutInvoker, + const JSIScopedTimeoutInvoker &timeoutInvoker, RuntimeInstaller runtimeInstaller); void loadApplicationScript( std::unique_ptr script, std::string sourceURL) override; void setBundleRegistry(std::unique_ptr) 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 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& invokee, + const std::function &invokee, std::function 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 runtime_; std::shared_ptr delegate_; JSINativeModules nativeModules_; std::once_flag bindFlag_; std::unique_ptr bundleRegistry_; - Logger logger_; JSIScopedTimeoutInvoker scopedTimeoutInvoker_; RuntimeInstaller runtimeInstaller_; @@ -131,5 +126,8 @@ class JSIExecutor : public JSExecutor { folly::Optional callFunctionReturnResultAndFlushedQueue_; }; +using Logger = + std::function; +void bindNativeLogger(jsi::Runtime &runtime, Logger logger); } // namespace react } // namespace facebook