178516026STomasz Sapeta// Copyright 2022-present 650 Industries. All rights reserved. 278516026STomasz Sapeta 378516026STomasz Sapeta#import <ExpoModulesCore/EXJSIUtils.h> 478516026STomasz Sapeta#import <ExpoModulesCore/EXJavaScriptWeakObject.h> 578516026STomasz Sapeta 678516026STomasz Sapeta@implementation EXJavaScriptWeakObject { 778516026STomasz Sapeta /** 878516026STomasz Sapeta Pointer to the `EXJavaScriptRuntime` wrapper. 978516026STomasz Sapeta 1078516026STomasz Sapeta \note It must be weak because only then the original runtime can be safely deallocated 1178516026STomasz Sapeta when the JS engine wants to without unsetting it on each created object. 1278516026STomasz Sapeta */ 1378516026STomasz Sapeta __weak EXJavaScriptRuntime *_runtime; 1478516026STomasz Sapeta 15*2727a9f2STomasz Sapeta#if __has_include(<reacthermes/HermesExecutorFactory.h>) 1678516026STomasz Sapeta /** 17*2727a9f2STomasz Sapeta A weak reference to a JS object. Available only on Hermes engine. 1878516026STomasz Sapeta */ 19*2727a9f2STomasz Sapeta std::shared_ptr<jsi::WeakObject> _weakObject; 20*2727a9f2STomasz Sapeta#else 21*2727a9f2STomasz Sapeta /** 22*2727a9f2STomasz Sapeta Shared pointer to the `WeakRef` JS object. Available only on JSC engine. 23*2727a9f2STomasz Sapeta */ 24*2727a9f2STomasz Sapeta std::shared_ptr<jsi::Object> _weakObject; 25*2727a9f2STomasz Sapeta#endif 2678516026STomasz Sapeta} 2778516026STomasz Sapeta 2878516026STomasz Sapeta- (nonnull instancetype)initWith:(std::shared_ptr<jsi::Object>)jsObject 2978516026STomasz Sapeta runtime:(nonnull EXJavaScriptRuntime *)runtime 3078516026STomasz Sapeta{ 3178516026STomasz Sapeta if (self = [super init]) { 3278516026STomasz Sapeta _runtime = runtime; 3378516026STomasz Sapeta 34*2727a9f2STomasz Sapeta#if __has_include(<reacthermes/HermesExecutorFactory.h>) 35*2727a9f2STomasz Sapeta _weakObject = std::make_shared<jsi::WeakObject>(*[runtime get], *jsObject); 36*2727a9f2STomasz Sapeta#else 3778516026STomasz Sapeta // Check whether the runtime supports `WeakRef` objects. If it does not, 3878516026STomasz Sapeta // we consciously hold a strong reference to the object and cause memory leaks. 39*2727a9f2STomasz Sapeta // This is the case on JSC prior to iOS 14.5. 4078516026STomasz Sapeta if (expo::isWeakRefSupported(*[runtime get])) { 41*2727a9f2STomasz Sapeta _weakObject = expo::createWeakRef(*[runtime get], jsObject); 4278516026STomasz Sapeta } else { 43*2727a9f2STomasz Sapeta _weakObject = jsObject; 4478516026STomasz Sapeta } 45*2727a9f2STomasz Sapeta#endif 4678516026STomasz Sapeta } 4778516026STomasz Sapeta return self; 4878516026STomasz Sapeta} 4978516026STomasz Sapeta 5078516026STomasz Sapeta- (nullable EXJavaScriptObject *)lock 5178516026STomasz Sapeta{ 5278516026STomasz Sapeta jsi::Runtime *runtime = [_runtime get]; 53*2727a9f2STomasz Sapeta 54*2727a9f2STomasz Sapeta#if __has_include(<reacthermes/HermesExecutorFactory.h>) 55*2727a9f2STomasz Sapeta jsi::Value value = _weakObject->lock(*runtime); 56*2727a9f2STomasz Sapeta 57*2727a9f2STomasz Sapeta // `lock` returns an undefined value if the underlying object no longer exists. 58*2727a9f2STomasz Sapeta if (value.isUndefined()) { 59*2727a9f2STomasz Sapeta return nil; 60*2727a9f2STomasz Sapeta } 61*2727a9f2STomasz Sapeta std::shared_ptr<jsi::Object> objectPtr = std::make_shared<jsi::Object>(value.asObject(*runtime)); 62*2727a9f2STomasz Sapeta#else 6378516026STomasz Sapeta std::shared_ptr<jsi::Object> objectPtr = expo::isWeakRefSupported(*runtime) 64*2727a9f2STomasz Sapeta ? expo::derefWeakRef(*runtime, _weakObject) 65*2727a9f2STomasz Sapeta : _weakObject; 66*2727a9f2STomasz Sapeta#endif 6778516026STomasz Sapeta 6878516026STomasz Sapeta if (!objectPtr) { 6978516026STomasz Sapeta return nil; 7078516026STomasz Sapeta } 7178516026STomasz Sapeta return [[EXJavaScriptObject alloc] initWith:objectPtr runtime:_runtime]; 7278516026STomasz Sapeta} 7378516026STomasz Sapeta 7478516026STomasz Sapeta@end 75