From 6bc0c108ebd87216b327dbafc6f3f7c7d72e1222 Mon Sep 17 00:00:00 2001 From: Eric Williamson Date: Thu, 1 Aug 2019 21:55:45 -0700 Subject: [PATCH] Revert D16589168: [RN][TurboModule] Delete jsi::Functions before jsi::Runtime gets deleted Differential Revision: D16589168 Original commit changeset: a1c0786999c2 fbshipit-source-id: 8048d62e958c0b58aface00dae8447b8c2d5d2dc --- .../react/bridge/CatalystInstanceImpl.java | 48 ++--- .../react/bridge/JSIModuleRegistry.java | 10 +- .../turbomodule/core/TurboCxxModule.cpp | 101 +++------- .../turbomodule/core/TurboModuleUtils.h | 65 +----- .../core/platform/android/JavaTurboModule.cpp | 62 ++---- .../core/platform/android/JavaTurboModule.h | 30 +-- .../core/platform/ios/RCTTurboModule.mm | 187 +++++++----------- 7 files changed, 145 insertions(+), 358 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java index d15c0d37d59..e96d24270e5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java @@ -359,40 +359,24 @@ public class CatalystInstanceImpl implements CatalystInstance { listener.onBridgeDestroyed(); } } + AsyncTask.execute( + new Runnable() { + @Override + public void run() { + // Kill non-UI threads from neutral third party + // potentially expensive, so don't run on UI thread - final JSIModule turboModuleManager = - mJSIModuleRegistry.getModule(JSIModuleType.TurboModuleManager); + // contextHolder is used as a lock to guard against other users of the JS VM + // having + // the VM destroyed underneath them, so notify them before we resetNative + mJavaScriptContextHolder.clear(); - mReactQueueConfiguration - .getJSQueueThread() - .runOnQueue( - new Runnable() { - @Override - public void run() { - // We need to destroy the TurboModuleManager on the JS Thread - turboModuleManager.onCatalystInstanceDestroy(); - - AsyncTask.execute( - new Runnable() { - @Override - public void run() { - // Kill non-UI threads from neutral third party - // potentially expensive, so don't run on UI thread - - // contextHolder is used as a lock to guard against other users of - // the JS VM having the VM destroyed underneath them, so notify - // them before we resetNative - mJavaScriptContextHolder.clear(); - - mHybridData.resetNative(); - getReactQueueConfiguration().destroy(); - Log.d(ReactConstants.TAG, "CatalystInstanceImpl.destroy() end"); - ReactMarker.logMarker( - ReactMarkerConstants.DESTROY_CATALYST_INSTANCE_END); - } - }); - } - }); + mHybridData.resetNative(); + getReactQueueConfiguration().destroy(); + Log.d(ReactConstants.TAG, "CatalystInstanceImpl.destroy() end"); + ReactMarker.logMarker(ReactMarkerConstants.DESTROY_CATALYST_INSTANCE_END); + } + }); } }); diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSIModuleRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSIModuleRegistry.java index 1a27b446375..7c4ded025f8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSIModuleRegistry.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSIModuleRegistry.java @@ -32,15 +32,7 @@ public class JSIModuleRegistry { } public void notifyJSInstanceDestroy() { - for (Map.Entry entry : mModules.entrySet()) { - JSIModuleType moduleType = entry.getKey(); - - // Don't call TurboModuleManager.onCatalystInstanceDestroy - if (moduleType == JSIModuleType.TurboModuleManager) { - continue; - } - - JSIModuleHolder moduleHolder = entry.getValue(); + for (JSIModuleHolder moduleHolder : mModules.values()) { moduleHolder.notifyJSInstanceDestroy(); } } diff --git a/ReactCommon/turbomodule/core/TurboCxxModule.cpp b/ReactCommon/turbomodule/core/TurboCxxModule.cpp index 267b5179edb..56663ccc99a 100644 --- a/ReactCommon/turbomodule/core/TurboCxxModule.cpp +++ b/ReactCommon/turbomodule/core/TurboCxxModule.cpp @@ -22,49 +22,35 @@ static CxxModule::Callback makeTurboCxxModuleCallback( jsi::Runtime &runtime, std::shared_ptr callbackWrapper) { return [callbackWrapper](std::vector args) { - callbackWrapper->jsInvoker().invokeAsync([callbackWrapper, args]() { + callbackWrapper->jsInvoker->invokeAsync([callbackWrapper, args]() { std::vector innerArgs; for (auto &a : args) { - innerArgs.push_back( - jsi::valueFromDynamic(callbackWrapper->runtime(), a)); + innerArgs.push_back(jsi::valueFromDynamic(callbackWrapper->runtime, a)); } - callbackWrapper->callback().call( - callbackWrapper->runtime(), - (const jsi::Value *)innerArgs.data(), - innerArgs.size()); + callbackWrapper->callback.call(callbackWrapper->runtime, (const jsi::Value *)innerArgs.data(), innerArgs.size()); }); }; } -TurboCxxModule::TurboCxxModule( - std::unique_ptr cxxModule, - std::shared_ptr jsInvoker) - : TurboModule(cxxModule->getName(), jsInvoker), - cxxMethods_(cxxModule->getMethods()), - cxxModule_(std::move(cxxModule)) {} +TurboCxxModule::TurboCxxModule(std::unique_ptr cxxModule, std::shared_ptr jsInvoker) + : TurboModule(cxxModule->getName(), jsInvoker), + cxxMethods_(cxxModule->getMethods()), + cxxModule_(std::move(cxxModule)) {} -jsi::Value TurboCxxModule::get( - jsi::Runtime &runtime, - const jsi::PropNameID &propName) { +jsi::Value TurboCxxModule::get(jsi::Runtime& runtime, const jsi::PropNameID& propName) { std::string propNameUtf8 = propName.utf8(runtime); if (propNameUtf8 == "getConstants") { - // This is special cased because `getConstants()` is already a part of - // CxxModule. + // This is special cased because `getConstants()` is already a part of CxxModule. return jsi::Function::createFromHostFunction( runtime, propName, 0, - [this]( - jsi::Runtime &rt, - const jsi::Value &thisVal, - const jsi::Value *args, - size_t count) { + [this](jsi::Runtime &rt, const jsi::Value &thisVal, const jsi::Value *args, size_t count) { jsi::Object result(rt); auto constants = cxxModule_->getConstants(); for (auto &pair : constants) { - result.setProperty( - rt, pair.first.c_str(), jsi::valueFromDynamic(rt, pair.second)); + result.setProperty(rt, pair.first.c_str(), jsi::valueFromDynamic(rt, pair.second)); } return result; }); @@ -76,11 +62,7 @@ jsi::Value TurboCxxModule::get( runtime, propName, 0, - [this, propNameUtf8]( - jsi::Runtime &rt, - const jsi::Value &thisVal, - const jsi::Value *args, - size_t count) { + [this, propNameUtf8](jsi::Runtime &rt, const jsi::Value &thisVal, const jsi::Value *args, size_t count) { return invokeMethod(rt, VoidKind, propNameUtf8, args, count); }); } @@ -95,6 +77,7 @@ jsi::Value TurboCxxModule::invokeMethod( const std::string &methodName, const jsi::Value *args, size_t count) { + auto it = cxxMethods_.begin(); for (; it != cxxMethods_.end(); it++) { auto method = *it; @@ -104,8 +87,7 @@ jsi::Value TurboCxxModule::invokeMethod( } if (it == cxxMethods_.end()) { - throw std::runtime_error( - "Function '" + methodName + "' cannot be found on cxxmodule: " + name_); + throw std::runtime_error("Function '" + methodName + "' cannot be found on cxxmodule: " + name_); } auto method = *it; @@ -115,37 +97,23 @@ jsi::Value TurboCxxModule::invokeMethod( for (size_t i = 0; i < count; i++) { innerArgs.push_back(jsi::dynamicFromValue(runtime, args[i])); } - return jsi::valueFromDynamic( - runtime, method.syncFunc(std::move(innerArgs))); + return jsi::valueFromDynamic(runtime, method.syncFunc(std::move(innerArgs))); } else if (method.func && !method.isPromise) { // Async method. CxxModule::Callback first; CxxModule::Callback second; if (count < method.callbacks) { - throw std::invalid_argument(folly::to( - "Expected ", - method.callbacks, - " callbacks, but only ", - count, - " parameters provided")); + throw std::invalid_argument(folly::to("Expected ", method.callbacks, + " callbacks, but only ", count, " parameters provided")); } if (method.callbacks == 1) { - auto wrapper = std::make_shared( - args[count - 1].getObject(runtime).getFunction(runtime), - runtime, - jsInvoker_); + auto wrapper = std::make_shared(args[count - 1].getObject(runtime).getFunction(runtime), runtime, jsInvoker_); first = makeTurboCxxModuleCallback(runtime, wrapper); } else if (method.callbacks == 2) { - auto wrapper1 = std::make_shared( - args[count - 2].getObject(runtime).getFunction(runtime), - runtime, - jsInvoker_); - auto wrapper2 = std::make_shared( - args[count - 1].getObject(runtime).getFunction(runtime), - runtime, - jsInvoker_); + auto wrapper1 = std::make_shared(args[count - 2].getObject(runtime).getFunction(runtime), runtime, jsInvoker_); + auto wrapper2 = std::make_shared(args[count - 1].getObject(runtime).getFunction(runtime), runtime, jsInvoker_); first = makeTurboCxxModuleCallback(runtime, wrapper1); second = makeTurboCxxModuleCallback(runtime, wrapper2); } @@ -157,26 +125,19 @@ jsi::Value TurboCxxModule::invokeMethod( method.func(std::move(innerArgs), first, second); } else if (method.isPromise) { - return createPromiseAsJSIValue( - runtime, - [method, args, count, this]( - jsi::Runtime &rt, std::shared_ptr promise) { - auto resolveWrapper = std::make_shared( - promise->resolve_.getFunction(rt), rt, jsInvoker_); - auto rejectWrapper = std::make_shared( - promise->reject_.getFunction(rt), rt, jsInvoker_); - CxxModule::Callback resolve = - makeTurboCxxModuleCallback(rt, resolveWrapper); - CxxModule::Callback reject = - makeTurboCxxModuleCallback(rt, rejectWrapper); + return createPromiseAsJSIValue(runtime, [method, args, count, this](jsi::Runtime &rt, std::shared_ptr promise) { + auto resolveWrapper = std::make_shared(promise->resolve_.getFunction(rt), rt, jsInvoker_); + auto rejectWrapper = std::make_shared(promise->reject_.getFunction(rt), rt, jsInvoker_); + CxxModule::Callback resolve = makeTurboCxxModuleCallback(rt, resolveWrapper); + CxxModule::Callback reject = makeTurboCxxModuleCallback(rt, rejectWrapper); - auto innerArgs = folly::dynamic::array(); - for (size_t i = 0; i < count; i++) { - innerArgs.push_back(jsi::dynamicFromValue(rt, args[i])); - } + auto innerArgs = folly::dynamic::array(); + for (size_t i = 0; i < count; i++) { + innerArgs.push_back(jsi::dynamicFromValue(rt, args[i])); + } - method.func(std::move(innerArgs), resolve, reject); - }); + method.func(std::move(innerArgs), resolve, reject); + }); } return jsi::Value::undefined(); diff --git a/ReactCommon/turbomodule/core/TurboModuleUtils.h b/ReactCommon/turbomodule/core/TurboModuleUtils.h index ee26f199fe1..b998aa05c31 100644 --- a/ReactCommon/turbomodule/core/TurboModuleUtils.h +++ b/ReactCommon/turbomodule/core/TurboModuleUtils.h @@ -7,10 +7,8 @@ #pragma once -#include #include -#include #include #include @@ -34,61 +32,18 @@ struct Promise { jsi::Function reject_; }; -using PromiseSetupFunctionType = - std::function)>; -jsi::Value createPromiseAsJSIValue( - jsi::Runtime &rt, - const PromiseSetupFunctionType func); +using PromiseSetupFunctionType = std::function)>; +jsi::Value createPromiseAsJSIValue(jsi::Runtime &rt, const PromiseSetupFunctionType func); // Helper for passing jsi::Function arg to other methods. -class CallbackWrapper { - private: - struct Data { - Data( - jsi::Function callback, - jsi::Runtime &runtime, - std::shared_ptr jsInvoker) - : callback(std::move(callback)), - runtime(runtime), - jsInvoker(std::move(jsInvoker)) {} - - jsi::Function callback; - jsi::Runtime &runtime; - std::shared_ptr jsInvoker; - }; - - folly::Optional data_; - - public: - CallbackWrapper( - jsi::Function callback, - jsi::Runtime &runtime, - std::shared_ptr jsInvoker) - : data_(Data{std::move(callback), runtime, jsInvoker}) {} - - // Delete the enclosed jsi::Function - void destroy() { - data_ = folly::none; - } - - bool isDestroyed() { - return !data_.hasValue(); - } - - jsi::Function &callback() { - assert(!isDestroyed()); - return data_->callback; - } - - jsi::Runtime &runtime() { - assert(!isDestroyed()); - return data_->runtime; - } - - react::JSCallInvoker &jsInvoker() { - assert(!isDestroyed()); - return *(data_->jsInvoker); - } +struct CallbackWrapper { + CallbackWrapper(jsi::Function callback, jsi::Runtime &runtime, std::shared_ptr jsInvoker) + : callback(std::move(callback)), + runtime(runtime), + jsInvoker(jsInvoker) {} + jsi::Function callback; + jsi::Runtime &runtime; + std::shared_ptr jsInvoker; }; } // namespace react diff --git a/ReactCommon/turbomodule/core/platform/android/JavaTurboModule.cpp b/ReactCommon/turbomodule/core/platform/android/JavaTurboModule.cpp index 9c97fe2c052..86a01ef0729 100644 --- a/ReactCommon/turbomodule/core/platform/android/JavaTurboModule.cpp +++ b/ReactCommon/turbomodule/core/platform/android/JavaTurboModule.cpp @@ -13,7 +13,9 @@ #include #include +#include #include +#include #include #include #include @@ -29,69 +31,35 @@ JavaTurboModule::JavaTurboModule( std::shared_ptr jsInvoker) : TurboModule(name, jsInvoker), instance_(jni::make_global(instance)) {} -jni::local_ref -JavaTurboModule::createJavaCallbackFromJSIFunction( +jni::local_ref createJavaCallbackFromJSIFunction( jsi::Function &function, jsi::Runtime &rt, std::shared_ptr jsInvoker) { auto wrapper = std::make_shared( std::move(function), rt, jsInvoker); - callbackWrappers_.insert(wrapper); - - std::function fn = [this, - wrapper](folly::dynamic responses) { - if (wrapper->isDestroyed()) { + std::function fn = [wrapper](folly::dynamic responses) { + if (wrapper == nullptr) { throw std::runtime_error("callback arg cannot be called more than once"); } - - wrapper->jsInvoker().invokeAsync([this, wrapper, responses]() { - if (wrapper->isDestroyed()) { - return; - } - + std::shared_ptr rw = wrapper; + wrapper->jsInvoker->invokeAsync([rw, responses]() { // TODO (T43155926) valueFromDynamic already returns a Value array. Don't // iterate again - jsi::Value args = jsi::valueFromDynamic(wrapper->runtime(), responses); - auto argsArray = - args.getObject(wrapper->runtime()).asArray(wrapper->runtime()); + jsi::Value args = jsi::valueFromDynamic(rw->runtime, responses); + auto argsArray = args.getObject(rw->runtime).asArray(rw->runtime); std::vector result; - for (size_t i = 0; i < argsArray.size(wrapper->runtime()); i++) { + for (size_t i = 0; i < argsArray.size(rw->runtime); i++) { result.emplace_back( - wrapper->runtime(), - argsArray.getValueAtIndex(wrapper->runtime(), i)); + rw->runtime, argsArray.getValueAtIndex(rw->runtime, i)); } - wrapper->callback().call( - wrapper->runtime(), (const jsi::Value *)result.data(), result.size()); - - /** - * Eagerly destroy the jsi::Function since it's already been invoked. - * TODO(T48128233) Do we want callbacks to be invoked only once? - * - * NOTE: ~JavaTurboModule and this function run on the same thread. - * If you reach this point, you know that the destructor wasn't run - * because the current wrapper wasn't destroyed. Therefore, it's - * safe to access callbackWrappers_. - */ - wrapper->destroy(); - callbackWrappers_.erase(wrapper); + rw->callback.call( + rw->runtime, (const jsi::Value *)result.data(), result.size()); }); }; + wrapper = nullptr; return JCxxCallbackImpl::newObjectCxxArgs(fn); } -JavaTurboModule::~JavaTurboModule() { - /** - * Delete all jsi::Functions that haven't yet been invoked by Java. - * So long as nothing else aside from the JS heap is holding on to this - * JavaTurboModule, this destructor is guaranteed to execute before the - * jsi::Runtime is deleted. - */ - for (auto it = callbackWrappers_.begin(); it != callbackWrappers_.end(); - it++) { - (*it)->destroy(); - } -} - namespace { template @@ -216,7 +184,7 @@ std::vector getMethodArgTypesFromSignature( // needs to be done again // TODO (axe) Reuse existing implementation as needed - the exist in // MethodInvoker.cpp -std::vector JavaTurboModule::convertJSIArgsToJNIArgs( +std::vector convertJSIArgsToJNIArgs( JNIEnv *env, jsi::Runtime &rt, std::string methodName, diff --git a/ReactCommon/turbomodule/core/platform/android/JavaTurboModule.h b/ReactCommon/turbomodule/core/platform/android/JavaTurboModule.h index e0889437546..9e3648bcfcf 100644 --- a/ReactCommon/turbomodule/core/platform/android/JavaTurboModule.h +++ b/ReactCommon/turbomodule/core/platform/android/JavaTurboModule.h @@ -8,13 +8,10 @@ #pragma once #include -#include #include -#include #include #include -#include namespace facebook { namespace react { @@ -38,34 +35,9 @@ class JSI_EXPORT JavaTurboModule : public TurboModule { const jsi::Value *args, size_t count); - /** - * This dtor must be called from the JS Thread, since it accesses - * callbackWrappers_, which createJavaCallbackFromJSIFunction also accesses - * from the JS Thread. - */ - virtual ~JavaTurboModule(); - private: jni::global_ref instance_; - std::unordered_set> callbackWrappers_; - - /** - * This method must be called from the JS Thread, since it accesses - * callbackWrappers_. - */ - jni::local_ref createJavaCallbackFromJSIFunction( - jsi::Function &function, - jsi::Runtime &rt, - std::shared_ptr jsInvoker); - std::vector convertJSIArgsToJNIArgs( - JNIEnv *env, - jsi::Runtime &rt, - std::string methodName, - std::vector methodArgTypes, - const jsi::Value *args, - size_t count, - std::shared_ptr jsInvoker, - TurboModuleMethodValueKind valueKind); + jclass findClass(JNIEnv *env) const; }; } // namespace react diff --git a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModule.mm b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModule.mm index af31001e760..5d5e4ecb59e 100644 --- a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModule.mm +++ b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModule.mm @@ -28,24 +28,20 @@ using namespace facebook; /** * All static helper functions are ObjC++ specific. */ -static jsi::Value convertNSNumberToJSIBoolean(jsi::Runtime &runtime, NSNumber *value) -{ +static jsi::Value convertNSNumberToJSIBoolean(jsi::Runtime &runtime, NSNumber *value) { return jsi::Value((bool)[value boolValue]); } -static jsi::Value convertNSNumberToJSINumber(jsi::Runtime &runtime, NSNumber *value) -{ +static jsi::Value convertNSNumberToJSINumber(jsi::Runtime &runtime, NSNumber *value) { return jsi::Value([value doubleValue]); } -static jsi::String convertNSStringToJSIString(jsi::Runtime &runtime, NSString *value) -{ +static jsi::String convertNSStringToJSIString(jsi::Runtime &runtime, NSString *value) { return jsi::String::createFromUtf8(runtime, [value UTF8String] ?: ""); } static jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value); -static jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime &runtime, NSDictionary *value) -{ +static jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime &runtime, NSDictionary *value) { jsi::Object result = jsi::Object(runtime); for (NSString *k in value) { result.setProperty(runtime, [k UTF8String], convertObjCObjectToJSIValue(runtime, value[k])); @@ -53,8 +49,7 @@ static jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime &runtime, NSDicti return result; } -static jsi::Array convertNSArrayToJSIArray(jsi::Runtime &runtime, NSArray *value) -{ +static jsi::Array convertNSArrayToJSIArray(jsi::Runtime &runtime, NSArray *value) { jsi::Array result = jsi::Array(runtime, value.count); for (size_t i = 0; i < value.count; i++) { result.setValueAtIndex(runtime, i, convertObjCObjectToJSIValue(runtime, value[i])); @@ -62,8 +57,7 @@ static jsi::Array convertNSArrayToJSIArray(jsi::Runtime &runtime, NSArray *value return result; } -static std::vector convertNSArrayToStdVector(jsi::Runtime &runtime, NSArray *value) -{ +static std::vector convertNSArrayToStdVector(jsi::Runtime &runtime, NSArray *value) { std::vector result; for (size_t i = 0; i < value.count; i++) { result.emplace_back(convertObjCObjectToJSIValue(runtime, value[i])); @@ -71,8 +65,7 @@ static std::vector convertNSArrayToStdVector(jsi::Runtime &runtime, return result; } -static jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value) -{ +static jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value) { if ([value isKindOfClass:[NSString class]]) { return convertNSStringToJSIString(runtime, (NSString *)value); } else if ([value isKindOfClass:[NSNumber class]]) { @@ -90,35 +83,22 @@ static jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value) return jsi::Value::undefined(); } -static id convertJSIValueToObjCObject( - jsi::Runtime &runtime, - const jsi::Value &value, - std::shared_ptr jsInvoker); -static NSString *convertJSIStringToNSString(jsi::Runtime &runtime, const jsi::String &value) -{ +static id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value, std::shared_ptr jsInvoker); +static NSString *convertJSIStringToNSString(jsi::Runtime &runtime, const jsi::String &value) { return [NSString stringWithUTF8String:value.utf8(runtime).c_str()]; } -static NSArray *convertJSIArrayToNSArray( - jsi::Runtime &runtime, - const jsi::Array &value, - std::shared_ptr jsInvoker) -{ +static NSArray *convertJSIArrayToNSArray(jsi::Runtime &runtime, const jsi::Array &value, std::shared_ptr jsInvoker) { size_t size = value.size(runtime); NSMutableArray *result = [NSMutableArray new]; for (size_t i = 0; i < size; i++) { // Insert kCFNull when it's `undefined` value to preserve the indices. - [result - addObject:convertJSIValueToObjCObject(runtime, value.getValueAtIndex(runtime, i), jsInvoker) ?: (id)kCFNull]; + [result addObject:convertJSIValueToObjCObject(runtime, value.getValueAtIndex(runtime, i), jsInvoker) ?: (id)kCFNull]; } return [result copy]; } -static NSDictionary *convertJSIObjectToNSDictionary( - jsi::Runtime &runtime, - const jsi::Object &value, - std::shared_ptr jsInvoker) -{ +static NSDictionary *convertJSIObjectToNSDictionary(jsi::Runtime &runtime, const jsi::Object &value, std::shared_ptr jsInvoker) { jsi::Array propertyNames = value.getPropertyNames(runtime); size_t size = propertyNames.size(runtime); NSMutableDictionary *result = [NSMutableDictionary new]; @@ -133,15 +113,8 @@ static NSDictionary *convertJSIObjectToNSDictionary( return [result copy]; } -static RCTResponseSenderBlock convertJSIFunctionToCallback( - jsi::Runtime &runtime, - const jsi::Function &value, - std::shared_ptr jsInvoker); -static id convertJSIValueToObjCObject( - jsi::Runtime &runtime, - const jsi::Value &value, - std::shared_ptr jsInvoker) -{ +static RCTResponseSenderBlock convertJSIFunctionToCallback(jsi::Runtime &runtime, const jsi::Function &value, std::shared_ptr jsInvoker); +static id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value, std::shared_ptr jsInvoker) { if (value.isUndefined() || value.isNull()) { return nil; } @@ -168,11 +141,7 @@ static id convertJSIValueToObjCObject( throw std::runtime_error("Unsupported jsi::jsi::Value kind"); } -static RCTResponseSenderBlock convertJSIFunctionToCallback( - jsi::Runtime &runtime, - const jsi::Function &value, - std::shared_ptr jsInvoker) -{ +static RCTResponseSenderBlock convertJSIFunctionToCallback(jsi::Runtime &runtime, const jsi::Function &value, std::shared_ptr jsInvoker) { __block auto wrapper = std::make_shared(value.getFunction(runtime), runtime, jsInvoker); return ^(NSArray *responses) { if (wrapper == nullptr) { @@ -180,9 +149,9 @@ static RCTResponseSenderBlock convertJSIFunctionToCallback( } std::shared_ptr rw = wrapper; - wrapper->jsInvoker().invokeAsync([rw, responses]() { - std::vector args = convertNSArrayToStdVector(rw->runtime(), responses); - rw->callback().call(rw->runtime(), (const jsi::Value *)args.data(), args.size()); + wrapper->jsInvoker->invokeAsync([rw, responses]() { + std::vector args = convertNSArrayToStdVector(rw->runtime, responses); + rw->callback.call(rw->runtime, (const jsi::Value *)args.data(), args.size()); }); // The callback is single-use, so force release it here. @@ -198,8 +167,7 @@ struct PromiseWrapper : public react::LongLivedObject { jsi::Function resolve, jsi::Function reject, jsi::Runtime &runtime, - std::shared_ptr jsInvoker) - { + std::shared_ptr jsInvoker) { auto instance = std::make_shared(std::move(resolve), std::move(reject), runtime, jsInvoker); // This instance needs to live longer than the caller's scope, since the resolve/reject functions may not // be called immediately. Doing so keeps it alive at least until resolve/reject is called, or when the @@ -213,15 +181,12 @@ struct PromiseWrapper : public react::LongLivedObject { jsi::Function reject, jsi::Runtime &runtime, std::shared_ptr jsInvoker) - : resolveWrapper(std::make_shared(std::move(resolve), runtime, jsInvoker)), - rejectWrapper(std::make_shared(std::move(reject), runtime, jsInvoker)), - runtime(runtime), - jsInvoker(jsInvoker) - { - } + : resolveWrapper(std::make_shared(std::move(resolve), runtime, jsInvoker)), + rejectWrapper(std::make_shared(std::move(reject), runtime, jsInvoker)), + runtime(runtime), + jsInvoker(jsInvoker) {} - RCTPromiseResolveBlock resolveBlock() - { + RCTPromiseResolveBlock resolveBlock() { return ^(id result) { if (resolveWrapper == nullptr) { throw std::runtime_error("Promise resolve arg cannot be called more than once"); @@ -230,9 +195,9 @@ struct PromiseWrapper : public react::LongLivedObject { // Retain the resolveWrapper so that it stays alive inside the lambda. std::shared_ptr retainedWrapper = resolveWrapper; jsInvoker->invokeAsync([retainedWrapper, result]() { - jsi::Runtime &rt = retainedWrapper->runtime(); + jsi::Runtime &rt = retainedWrapper->runtime; jsi::Value arg = convertObjCObjectToJSIValue(rt, result); - retainedWrapper->callback().call(rt, arg); + retainedWrapper->callback.call(rt, arg); }); // Prevent future invocation of the same resolve() function. @@ -240,8 +205,7 @@ struct PromiseWrapper : public react::LongLivedObject { }; } - RCTPromiseRejectBlock rejectBlock() - { + RCTPromiseRejectBlock rejectBlock() { return ^(NSString *code, NSString *message, NSError *error) { // TODO: There is a chance `this` is no longer valid when this block executes. if (rejectWrapper == nullptr) { @@ -252,9 +216,9 @@ struct PromiseWrapper : public react::LongLivedObject { std::shared_ptr retainedWrapper = rejectWrapper; NSDictionary *jsError = RCTJSErrorFromCodeMessageAndNSError(code, message, error); jsInvoker->invokeAsync([retainedWrapper, jsError]() { - jsi::Runtime &rt = retainedWrapper->runtime(); + jsi::Runtime &rt = retainedWrapper->runtime; jsi::Value arg = convertNSDictionaryToJSIObject(rt, jsError); - retainedWrapper->callback().call(rt, arg); + retainedWrapper->callback.call(rt, arg); }); // Prevent future invocation of the same resolve() function. @@ -262,26 +226,23 @@ struct PromiseWrapper : public react::LongLivedObject { }; } - void cleanup() - { + void cleanup() { resolveWrapper = nullptr; rejectWrapper = nullptr; allowRelease(); } - // CallbackWrapper is used here instead of just holding on the jsi jsi::Function in order to force release it after - // either the resolve() or the reject() is called. jsi jsi::Function does not support explicit releasing, so we need - // an extra mechanism to control that lifecycle. + // CallbackWrapper is used here instead of just holding on the jsi jsi::Function in order to force release it after either + // the resolve() or the reject() is called. jsi jsi::Function does not support explicit releasing, so we need an extra + // mechanism to control that lifecycle. std::shared_ptr resolveWrapper; std::shared_ptr rejectWrapper; jsi::Runtime &runtime; std::shared_ptr jsInvoker; }; -using PromiseInvocationBlock = void (^)(jsi::Runtime &rt, std::shared_ptr wrapper); -static jsi::Value -createPromise(jsi::Runtime &runtime, std::shared_ptr jsInvoker, PromiseInvocationBlock invoke) -{ +using PromiseInvocationBlock = void (^)(jsi::Runtime& rt, std::shared_ptr wrapper); +static jsi::Value createPromise(jsi::Runtime &runtime, std::shared_ptr jsInvoker, PromiseInvocationBlock invoke) { if (!invoke) { return jsi::Value::undefined(); } @@ -332,8 +293,8 @@ jsi::Value performMethodInvocation( TurboModuleMethodValueKind valueKind, const id module, std::shared_ptr jsInvoker, - NSMutableArray *retainedObjectsForInvocation) -{ + NSMutableArray *retainedObjectsForInvocation) { + __block id result; jsi::Runtime *rt = &runtime; void (^block)() = ^{ @@ -409,8 +370,7 @@ jsi::Value performMethodInvocation( * Note: This is only being introduced for backward compatibility. It will be removed * in the future. */ -NSString *ObjCTurboModule::getArgumentTypeName(NSString *methodName, int argIndex) -{ +NSString* ObjCTurboModule::getArgumentTypeName(NSString* methodName, int argIndex) { if (!methodArgumentTypeNames_) { NSMutableDictionary *> *methodArgumentTypeNames = [NSMutableDictionary new]; @@ -421,7 +381,7 @@ NSString *ObjCTurboModule::getArgumentTypeName(NSString *methodName, int argInde if (methods) { for (unsigned int i = 0; i < numberOfMethods; i++) { SEL s = method_getName(methods[i]); - NSString *mName = NSStringFromSelector(s); + NSString* mName = NSStringFromSelector(s); if (![mName hasPrefix:@"__rct_export__"]) { continue; } @@ -433,7 +393,7 @@ NSString *ObjCTurboModule::getArgumentTypeName(NSString *methodName, int argInde NSArray *arguments; NSString *otherMethodName = RCTParseMethodSignature(methodInfo->objcName, &arguments); - NSMutableArray *argumentTypes = [NSMutableArray arrayWithCapacity:[arguments count]]; + NSMutableArray* argumentTypes = [NSMutableArray arrayWithCapacity:[arguments count]]; for (int j = 0; j < [arguments count]; j += 1) { [argumentTypes addObject:arguments[j].type]; } @@ -457,18 +417,16 @@ NSString *ObjCTurboModule::getArgumentTypeName(NSString *methodName, int argInde } NSInvocation *ObjCTurboModule::getMethodInvocation( - jsi::Runtime &runtime, - TurboModuleMethodValueKind valueKind, - const id module, - std::shared_ptr jsInvoker, - const std::string &methodName, - SEL selector, - const jsi::Value *args, - size_t count, - NSMutableArray *retainedObjectsForInvocation) -{ - NSInvocation *inv = - [NSInvocation invocationWithMethodSignature:[[module class] instanceMethodSignatureForSelector:selector]]; + jsi::Runtime &runtime, + TurboModuleMethodValueKind valueKind, + const id module, + std::shared_ptr jsInvoker, + const std::string& methodName, + SEL selector, + const jsi::Value *args, + size_t count, + NSMutableArray *retainedObjectsForInvocation) { + NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[[module class] instanceMethodSignatureForSelector:selector]]; [inv setSelector:selector]; NSMethodSignature *methodSignature = [[module class] instanceMethodSignatureForSelector:selector]; @@ -546,7 +504,7 @@ NSInvocation *ObjCTurboModule::getMethodInvocation( * Convert objects using RCTConvert. */ if (objCArgType[0] == _C_ID) { - NSString *argumentType = getArgumentTypeName(methodNameNSString, i); + NSString* argumentType = getArgumentTypeName(methodNameNSString, i); if (argumentType != nil) { NSString *rctConvertMethodName = [NSString stringWithFormat:@"%@:", argumentType]; SEL rctConvertSelector = NSSelectorFromString(rctConvertMethodName); @@ -598,9 +556,8 @@ ObjCTurboModule::ObjCTurboModule( const std::string &name, id instance, std::shared_ptr jsInvoker) - : TurboModule(name, jsInvoker), instance_(instance) -{ -} + : TurboModule(name, jsInvoker), + instance_(instance) {} jsi::Value ObjCTurboModule::invokeObjCMethod( jsi::Runtime &runtime, @@ -611,41 +568,39 @@ jsi::Value ObjCTurboModule::invokeObjCMethod( size_t count) { NSMutableArray *retainedObjectsForInvocation = [NSMutableArray arrayWithCapacity:count + 2]; - NSInvocation *inv = getMethodInvocation( - runtime, valueKind, instance_, jsInvoker_, methodName, selector, args, count, retainedObjectsForInvocation); + NSInvocation *inv = getMethodInvocation(runtime, valueKind, instance_, jsInvoker_, methodName, selector, args, count, retainedObjectsForInvocation); if (valueKind == PromiseKind) { // Promise return type is special cased today, i.e. it needs extra 2 function args for resolve() and reject(), to // be passed to the actual ObjC++ class method. - return createPromise(runtime, jsInvoker_, ^(jsi::Runtime &rt, std::shared_ptr wrapper) { - RCTPromiseResolveBlock resolveBlock = wrapper->resolveBlock(); - RCTPromiseRejectBlock rejectBlock = wrapper->rejectBlock(); - [inv setArgument:(void *)&resolveBlock atIndex:count + 2]; - [inv setArgument:(void *)&rejectBlock atIndex:count + 3]; - [retainedObjectsForInvocation addObject:resolveBlock]; - [retainedObjectsForInvocation addObject:rejectBlock]; - // The return type becomes void in the ObjC side. - performMethodInvocation(rt, inv, VoidKind, instance_, jsInvoker_, retainedObjectsForInvocation); - }); + return createPromise( + runtime, + jsInvoker_, + ^(jsi::Runtime &rt, std::shared_ptr wrapper) { + RCTPromiseResolveBlock resolveBlock = wrapper->resolveBlock(); + RCTPromiseRejectBlock rejectBlock = wrapper->rejectBlock(); + [inv setArgument:(void *)&resolveBlock atIndex:count + 2]; + [inv setArgument:(void *)&rejectBlock atIndex:count + 3]; + [retainedObjectsForInvocation addObject:resolveBlock]; + [retainedObjectsForInvocation addObject:rejectBlock]; + // The return type becomes void in the ObjC side. + performMethodInvocation(rt, inv, VoidKind, instance_, jsInvoker_, retainedObjectsForInvocation); + }); } return performMethodInvocation(runtime, inv, valueKind, instance_, jsInvoker_, retainedObjectsForInvocation); } -BOOL ObjCTurboModule::hasMethodArgConversionSelector(NSString *methodName, int argIndex) -{ - return methodArgConversionSelectors_ && methodArgConversionSelectors_[methodName] && - ![methodArgConversionSelectors_[methodName][argIndex] isEqual:[NSNull null]]; +BOOL ObjCTurboModule::hasMethodArgConversionSelector(NSString *methodName, int argIndex) { + return methodArgConversionSelectors_ && methodArgConversionSelectors_[methodName] && ![methodArgConversionSelectors_[methodName][argIndex] isEqual:[NSNull null]]; } -SEL ObjCTurboModule::getMethodArgConversionSelector(NSString *methodName, int argIndex) -{ +SEL ObjCTurboModule::getMethodArgConversionSelector(NSString *methodName, int argIndex) { assert(hasMethodArgConversionSelector(methodName, argIndex)); return (SEL)((NSValue *)methodArgConversionSelectors_[methodName][argIndex]).pointerValue; } -void ObjCTurboModule::setMethodArgConversionSelector(NSString *methodName, int argIndex, NSString *fnName) -{ +void ObjCTurboModule::setMethodArgConversionSelector(NSString *methodName, int argIndex, NSString *fnName) { if (!methodArgConversionSelectors_) { methodArgConversionSelectors_ = [NSMutableDictionary new]; }