1// Copyright 2022-present 650 Industries. All rights reserved.
2
3#import <ExpoModulesCore/EXJSIUtils.h>
4#import <ExpoModulesCore/EXJavaScriptWeakObject.h>
5
6@implementation EXJavaScriptWeakObject {
7  /**
8   Pointer to the `EXJavaScriptRuntime` wrapper.
9
10   \note It must be weak because only then the original runtime can be safely deallocated
11   when the JS engine wants to without unsetting it on each created object.
12   */
13  __weak EXJavaScriptRuntime *_runtime;
14
15  /**
16   Shared pointer to the `WeakRef` JS object.
17   */
18  std::shared_ptr<jsi::Object> _jsObject;
19}
20
21- (nonnull instancetype)initWith:(std::shared_ptr<jsi::Object>)jsObject
22                         runtime:(nonnull EXJavaScriptRuntime *)runtime
23{
24  if (self = [super init]) {
25    _runtime = runtime;
26
27    // Check whether the runtime supports `WeakRef` objects. If it does not,
28    // we consciously hold a strong reference to the object and cause memory leaks.
29    // This is the case on hermes and JSC prior to iOS 14.5.
30    // TODO: (@tsapeta) Use `jsi::WeakObject` on hermes
31    if (expo::isWeakRefSupported(*[runtime get])) {
32      _jsObject = expo::createWeakRef(*[runtime get], jsObject);
33    } else {
34      _jsObject = jsObject;
35    }
36  }
37  return self;
38}
39
40- (nullable EXJavaScriptObject *)lock
41{
42  jsi::Runtime *runtime = [_runtime get];
43  std::shared_ptr<jsi::Object> objectPtr = expo::isWeakRefSupported(*runtime)
44    ? expo::derefWeakRef(*runtime, _jsObject)
45    : _jsObject;
46
47  if (!objectPtr) {
48    return nil;
49  }
50  return [[EXJavaScriptObject alloc] initWith:objectPtr runtime:_runtime];
51}
52
53@end
54