Repository: react-native
Issue: iOS  jsi value ~shared_ptr Crash when RCTHost dealloc
Labels: Platform: iOS,API: Share,Needs: Author Feedback,Needs: Repro,Newer Patch Available,Type: New Architecture

### Description

When a `shared_ptr` is created using a JSI Value, a crash occurs during the destruction of the `shared_ptr` when the RCTHost is deallocated.



### Steps to reproduce

no

### React Native Version

0.74.3

### Affected Platforms

Runtime - iOS

### Areas

JSI - Javascript Interface

### Output of `npx react-native info`

```text
System:
  OS: macOS 15.1.1
  CPU: (12) arm64 Apple M3 Pro
  Memory: 133.20 MB / 18.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 23.3.0
    path: /opt/homebrew/bin/node
  Yarn:
    version: 1.22.22
    path: /opt/homebrew/bin/yarn
  npm:
    version: 10.9.0
    path: /opt/homebrew/bin/npm
  Watchman:
    version: 2024.11.18.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods:
    version: 1.12.1
    path: /Users/didi/.rbenv/shims/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 24.0
      - iOS 18.0
      - macOS 15.0
      - tvOS 18.0
      - visionOS 2.0
      - watchOS 11.0
  Android SDK: Not Found
IDEs:
  Android Studio: Not Found
  Xcode:
    version: 16.0/16A242d
    path: /usr/bin/xcodebuild
Languages:
  Java: Not Found
  Ruby:
    version: 2.6.10
    path: /Users/xxx/.rbenv/shims/ruby
npmPackages:
  "@react-native-community/cli": Not Found
  react:
    installed: 18.2.0
    wanted: 18.2.0
  react-native:
    installed: 0.74.3
    wanted: 0.74.3
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: false
iOS:
  hermesEnabled: true
  newArchEnabled: true

info React Native v0.76.5 is now available (your project is running on v0.74.3).
info Changelog: https://github.com/facebook/react-native/releases/tag/v0.76.5
info Diff: https://react-native-community.github.io/upgrade-helper/?from=0.74.3
info For more info, check out "https://reactnative.dev/docs/upgrading?os=macos".
```


### Stacktrace or Logs

```text
Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000010
Exception Codes: 0x0000000000000001, 0x0000000000000010
VM Region Info: 0x10 is not in any region.  Bytes before following region: 68719476720
      REGION TYPE                 START - END      [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
      UNUSED SPACE AT START
--->  
      commpage (reserved)     1000000000-7000000000 [384.0G] ---/--- SM=NUL  ...(unallocated)
Termination Reason: SIGNAL 11 Segmentation fault: 11
Terminating Process: exc handler [61876]

Triggered by Thread:  23


Crash Stack:
Thread 23 Crashed:
0   App                     	0x000000010516bc44 std::__1::__shared_weak_count::__release_shared[abi:ne180100]() + 56
1   App                     	0x000000010727a43c std::__1::shared_ptr<reanimated::Shareable>::~shared_ptr[abi:ne180100]() + 28
2   App                     	0x00000001072972d0 std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::shared_ptr<reanimated::Shareable>>::~pair() + 24
3   App                     	0x0000000107297588 std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::shared_ptr<reanimated::Shareable>>, std::__1::allocator<std::__1::pai... + 40
4   App                     	0x0000000107297538 std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::shared_ptr<reanimated::Shareable>>, std::__1::allocator<std::__1::pai... + 32
5   App                     	0x0000000107297504 std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::shared_ptr<reanimated::Shareable>>, std::__1::allocator<std::__1::pai... + 32

6   App                     	0x0000000107295f28 reanimated::ShareableObject::~ShareableObject() + 48
7   App                     	0x000000010516bc50 std::__1::__shared_weak_count::__release_shared[abi:ne180100]() + 68
8   App                     	0x000000010727a43c std::__1::shared_ptr<reanimated::Shareable>::~shared_ptr[abi:ne180100]() + 28
9   App                     	0x0000000107296ff0 std::__1::vector<std::__1::shared_ptr<reanimated::Shareable>, std::__1::allocator<std::__1::shared_ptr<reanimated::Shareable>>>::__base_destruct_at_end[abi:ne180100](std::__1::shared_ptr<reanimated... + 40
10  App                     	0x0000000107296fa0 std::__1::vector<std::__1::shared_ptr<reanimated::Shareable>, std::__1::allocator<std::__1::shared_ptr<reanimated::Shareable>>>::__destroy_vector::operator()[abi:ne180100]() + 32
11  App                     	0x0000000107296f6c std::__1::vector<std::__1::shared_ptr<reanimated::Shareable>, std::__1::allocator<std::__1::shared_ptr<reanimated::Shareable>>>::~vector[abi:ne180100]() + 32

12  App                     	0x000000010729786c reanimated::ShareableArray::~ShareableArray() + 32
13  App                     	0x000000010516bc50 std::__1::__shared_weak_count::__release_shared[abi:ne180100]() + 68
14  App                     	0x000000010727a43c std::__1::shared_ptr<reanimated::Shareable>::~shared_ptr[abi:ne180100]() + 28
15  App                     	0x0000000107296ff0 std::__1::vector<std::__1::shared_ptr<reanimated::Shareable>, std::__1::allocator<std::__1::shared_ptr<reanimated::Shareable>>>::__base_destruct_at_end[abi:ne180100](std::__1::shared_ptr<reanimated... + 40
16  App                     	0x0000000107296fa0 std::__1::vector<std::__1::shared_ptr<reanimated::Shareable>, std::__1::allocator<std::__1::shared_ptr<reanimated::Shareable>>>::__destroy_vector::operator()[abi:ne180100]() + 32
17  App                     	0x0000000107296f6c std::__1::vector<std::__1::shared_ptr<reanimated::Shareable>, std::__1::allocator<std::__1::shared_ptr<reanimated::Shareable>>>::~vector[abi:ne180100]() + 32

18  App                     	0x000000010729786c reanimated::ShareableArray::~ShareableArray() + 32
19  App                     	0x000000010516bc50 std::__1::__shared_weak_count::__release_shared[abi:ne180100]() + 68
20  App                     	0x000000010727a43c std::__1::shared_ptr<reanimated::Shareable>::~shared_ptr[abi:ne180100]() + 28
21  App                     	0x00000001072972d0 std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::shared_ptr<reanimated::Shareable>>::~pair() + 24
22  App                     	0x0000000107297588 std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::shared_ptr<reanimated::Shareable>>, std::__1::allocator<std::__1::pai... + 40
23  App                     	0x0000000107297538 std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::shared_ptr<reanimated::Shareable>>, std::__1::allocator<std::__1::pai... + 32
24  App                     	0x0000000107297504 std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::shared_ptr<reanimated::Shareable>>, std::__1::allocator<std::__1::pai... + 32

25  App                     	0x0000000107295f28 reanimated::ShareableObject::~ShareableObject() + 48
26  App                     	0x000000010516bc50 std::__1::__shared_weak_count::__release_shared[abi:ne180100]() + 68
27  App                     	0x000000010727a43c std::__1::shared_ptr<reanimated::Shareable>::~shared_ptr[abi:ne180100]() + 28
28  App                     	0x00000001072972d0 std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::shared_ptr<reanimated::Shareable>>::~pair() + 24
29  App                     	0x0000000107297588 std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::shared_ptr<reanimated::Shareable>>, std::__1::allocator<std::__1::pai... + 40
30  App                     	0x0000000107297538 std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::shared_ptr<reanimated::Shareable>>, std::__1::allocator<std::__1::pai... + 32
31  App                     	0x0000000107297504 std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::shared_ptr<reanimated::Shareable>>, std::__1::allocator<std::__1::pai... + 32

32  App                     	0x0000000107295f28 reanimated::ShareableObject::~ShareableObject() + 48
33  App                     	0x000000010516bc50 std::__1::__shared_weak_count::__release_shared[abi:ne180100]() + 68
34  App                     	0x000000010727a43c std::__1::shared_ptr<reanimated::Shareable>::~shared_ptr[abi:ne180100]() + 28
35  App                     	0x0000000107295624 reanimated::ShareableJSRef::~ShareableJSRef() + 32
36  hermes                        	0x000000010d7b655c 0x10d7a0000 + 91484
37  hermes                        	0x000000010d90a5d0 0x10d7a0000 + 1484240
38  hermes                        	0x000000010d88234c 0x10d7a0000 + 926540
39  hermes                        	0x000000010d8827dc 0x10d7a0000 + 927708
40  hermes                        	0x000000010d7b3b08 0x10d7a0000 + 80648
41  hermes                        	0x000000010d7b02cc 0x10d7a0000 + 66252
42  App                     	0x000000010516bc50 std::__1::__shared_weak_count::__release_shared[abi:ne180100]() + 68
43  App                     	0x0000000107512610 std::__1::shared_ptr<facebook::hermes::HermesRuntime>::~shared_ptr[abi:ne180100]() + 28
44  App                     	0x00000001074fe844 facebook::react::HermesJSRuntime::~HermesJSRuntime() + 48
45  App                     	0x00000001074fe570 facebook::react::HermesJSRuntime::~HermesJSRuntime() + 12
46  App                     	0x000000010516bc50 std::__1::__shared_weak_count::__release_shared[abi:ne180100]() + 68
47  App                     	0x00000001074f2818 std::__1::shared_ptr<facebook::react::JSRuntime>::~shared_ptr[abi:ne180100]() + 28
48  App                     	0x00000001074f269c facebook::react::ReactInstance::~ReactInstance() + 80
49  App                     	0x00000001074f2644 std::__1::default_delete<facebook::react::ReactInstance>::operator()[abi:ne180100](facebook::react::ReactInstance*) const + 20
50  App                     	0x00000001074efd70 __25-[RCTInstance invalidate]_block_invoke + 48
51  App                     	0x00000001073841ac facebook::react::tryAndReturnError(std::__1::function<void ()> const&) + 16
52  App                     	0x00000001074f4a28 -[RCTJSThreadManager _tryAndHandleError:] + 56
53  App                     	0x00000001074f4c00 std::__1::__function::__func<-[RCTJSThreadManager dispatchToJSThread:]::$_0, std::__1::allocator<-[RCTJSThreadManager dispatchToJSThread:]::$_0>, void ()>::operator()() + 36
54  App                     	0x00000001073841ac facebook::react::tryAndReturnError(std::__1::function<void ()> const&) + 16
55  App                     	0x00000001073901ec facebook::react::RCTMessageThread::tryFunc(std::__1::function<void ()> const&) + 24
56  App                     	0x0000000107390070 invocation function for block in facebook::react::RCTMessageThread::runAsync(std::__1::function<void ()>) + 32
57  CoreFoundation                	0x00000001b4cb1138 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 28 (CFRunLoop.c:1805)
58  CoreFoundation                	0x00000001b4caf92c __CFRunLoopDoBlocks + 356 (CFRunLoop.c:1847)
59  CoreFoundation                	0x00000001b4cad808 __CFRunLoopRun + 812 (CFRunLoop.c:2953)
60  CoreFoundation                	0x00000001b4cad3f8 CFRunLoopRunSpecific + 608 (CFRunLoop.c:3420)
61  App                     	0x00000001074f4990 +[RCTJSThreadManager runRunLoop] + 204
62  Foundation                    	0x00000001b3cc3d40 __NSThread__start__ + 732 (NSThread.m:991)
63  libsystem_pthread.dylib       	0x000000021ed744d4 _pthread_start + 136 (pthread.c:904)
64  libsystem_pthread.dylib       	0x000000021ed73a10 thread_start + 8 (:-1)

Thread 23 crashed with ARM Thread State (64-bit):
    x0: 0x0000000281b8d300   x1: 0x00000002826b7980   x2: 0x0000000000000000   x3: 0x000000028117d980
    x4: 0x00000002829c9940   x5: 0x000000011c1f84a0   x6: 0x0000000000000365   x7: 0x0000000000ffff7f
    x8: 0x0000000000000000   x9: 0x0000000000000000  x10: 0xffffffffffffffff  x11: 0x0000000000000000
   x12: 0x00000000000007fb  x13: 0x00000000000007fd  x14: 0x0000000097c11866  x15: 0x0000000000000066
   x16: 0x0000000097a1103d  x17: 0x0000000000011800  x18: 0x0000000000000000  x19: 0x0000000281b8d300
   x20: 0x00000002829c97e8  x21: 0x000000014b5c20d0  x22: 0x000000014b5c20e0  x23: 0x000000010dabb0a0
   x24: 0x00000000141300cd  x25: 0x0000000000000000  x26: 0x000000011a31d040  x27: 0x00000002811b9dc0
   x28: 0x0000000000000000   fp: 0x000000016bd456a0   lr: 0x000000010727a43c
    sp: 0x000000016bd45690   pc: 0x000000010516bc44 cpsr: 0x20000000
   esr: 0x92000006 (Data Abort) byte read Translation fault
```


### Reproducer

no

### Screenshots and Videos

```c++
#include "Shareables.h"

using namespace facebook;

namespace reanimated {

jsi::Function getValueUnpacker(jsi::Runtime &rt) {
  auto valueUnpacker = rt.global().getProperty(rt, "__valueUnpacker");
  assert(valueUnpacker.isObject() && "valueUnpacker not found");
  return valueUnpacker.asObject(rt).asFunction(rt);
}

#ifndef NDEBUG

static const auto callGuardLambda = [](facebook::jsi::Runtime &rt,
                                       const facebook::jsi::Value &thisVal,
                                       const facebook::jsi::Value *args,
                                       size_t count) {
  return args[0].asObject(rt).asFunction(rt).call(rt, args + 1, count - 1);
};

jsi::Function getCallGuard(jsi::Runtime &rt) {
  auto callGuard = rt.global().getProperty(rt, "__callGuardDEV");
  if (callGuard.isObject()) {
    // Use JS implementation if `__callGuardDEV` has already been installed.
    // This is the desired behavior.
    return callGuard.asObject(rt).asFunction(rt);
  }

  // Otherwise, fallback to C++ JSI implementation. This is necessary so that we
  // can install `__callGuardDEV` itself and should happen only once. Note that
  // the C++ implementation doesn't intercept errors and simply throws them as
  // C++ exceptions which crashes the app. We assume that installing the guard
  // doesn't throw any errors.
  return jsi::Function::createFromHostFunction(
      rt, jsi::PropNameID::forAscii(rt, "callGuard"), 1, callGuardLambda);
}

#endif // NDEBUG

jsi::Value makeShareableClone(
    jsi::Runtime &rt,
    const jsi::Value &value,
    const jsi::Value &shouldRetainRemote,
    const jsi::Value &nativeStateSource) {
  std::shared_ptr<Shareable> shareable;
  if (value.isObject()) {
    auto object = value.asObject(rt);
    if (!object.getProperty(rt, "__workletHash").isUndefined()) {
      shareable = std::make_shared<ShareableWorklet>(rt, object);
    } else if (!object.getProperty(rt, "__init").isUndefined()) {
      shareable = std::make_shared<ShareableHandle>(rt, object);
    } else if (object.isFunction(rt)) {
      auto function = object.asFunction(rt);
      if (function.isHostFunction(rt)) {
        shareable =
            std::make_shared<ShareableHostFunction>(rt, std::move(function));
      } else {
        shareable =
            std::make_shared<ShareableRemoteFunction>(rt, std::move(function));
      }
    } else if (object.isArray(rt)) {
      if (shouldRetainRemote.isBool() && shouldRetainRemote.getBool()) {
        shareable = std::make_shared<RetainingShareable<ShareableArray>>(
            rt, object.asArray(rt));
      } else {
        shareable = std::make_shared<ShareableArray>(rt, object.asArray(rt));
      }
    } else if (object.isArrayBuffer(rt)) {
      shareable =
          std::make_shared<ShareableArrayBuffer>(rt, object.getArrayBuffer(rt));
    } else if (object.isHostObject(rt)) {
      if (object.isHostObject<ShareableJSRef>(rt)) {
        return object;
      }
      shareable =
          std::make_shared<ShareableHostObject>(rt, object.getHostObject(rt));
    } else {
      if (shouldRetainRemote.isBool() && shouldRetainRemote.getBool()) {
        shareable = std::make_shared<RetainingShareable<ShareableObject>>(
            rt,
            object
#if SUPPORTS_NATIVE_STATE
            ,
            nativeStateSource
#endif // SUPPORTS_NATIVE_STATE
        );
      } else {
        shareable = std::make_shared<ShareableObject>(
            rt,
            object
#if SUPPORTS_NATIVE_STATE
            ,
            nativeStateSource
#endif // SUPPORTS_NATIVE_STATE
        );
      }
    }
  } else if (value.isString()) {
    shareable = std::make_shared<ShareableString>(value.asString(rt).utf8(rt));
  } else if (value.isUndefined()) {
    shareable = std::make_shared<ShareableScalar>();
  } else if (value.isNull()) {
    shareable = std::make_shared<ShareableScalar>(nullptr);
  } else if (value.isBool()) {
    shareable = std::make_shared<ShareableScalar>(value.getBool());
  } else if (value.isNumber()) {
    shareable = std::make_shared<ShareableScalar>(value.getNumber());
  } else if (value.isBigInt()) {
    shareable = std::make_shared<ShareableBigInt>(rt, value.getBigInt(rt));
  } else if (value.isSymbol()) {
    // TODO: this is only a placeholder implementation, here we replace symbols
    // with strings in order to make certain objects to be captured. There isn't
    // yet any usecase for using symbols on the UI runtime so it is fine to keep
    // it like this for now.
    shareable =
        std::make_shared<ShareableString>(value.getSymbol(rt).toString(rt));
  } else {
    throw std::runtime_error(
        "[Reanimated] Attempted to convert an unsupported value type.");
  }
  return ShareableJSRef::newHostObject(rt, shareable);
}

std::shared_ptr<Shareable> extractShareableOrThrow(
    jsi::Runtime &rt,
    const jsi::Value &maybeShareableValue,
    const std::string &errorMessage) {
  if (maybeShareableValue.isObject()) {
    auto object = maybeShareableValue.asObject(rt);
    if (object.isHostObject<ShareableJSRef>(rt)) {
      return object.getHostObject<ShareableJSRef>(rt)->value();
    }
    throw std::runtime_error(
        "[Reanimated] Attempted to extract from a HostObject that wasn't converted to a Shareable.");
  } else if (maybeShareableValue.isUndefined()) {
    return Shareable::undefined();
  }
  throw std::runtime_error(errorMessage);
}

Shareable::~Shareable() {}

std::shared_ptr<Shareable> Shareable::undefined() {
  static auto undefined = std::make_shared<ShareableScalar>();
  return undefined;
}

template <typename BaseClass>
jsi::Value RetainingShareable<BaseClass>::toJSValue(jsi::Runtime &rt) {
  if (&rt == primaryRuntime_) {
    // TODO: it is suboptimal to generate new object every time getJS is
    // called on host runtime – the objects we are generating already exists
    // and we should possibly just grab a hold of such object and use it here
    // instead of creating a new JS representation. As far as I understand the
    // only case where it can be realistically called this way is when a
    // shared value is created and then accessed on the same runtime
    return BaseClass::toJSValue(rt);
  }
  if (secondaryValue_ == nullptr) {
    auto value = BaseClass::toJSValue(rt);
    secondaryValue_ = std::make_unique<jsi::Value>(rt, value);
    secondaryRuntime_ = &rt;
    return value;
  }
  if (&rt == secondaryRuntime_) {
    return jsi::Value(rt, *secondaryValue_);
  }
  return BaseClass::toJSValue(rt);
}

ShareableJSRef::~ShareableJSRef() {}

ShareableArray::ShareableArray(jsi::Runtime &rt, const jsi::Array &array)
    : Shareable(ArrayType) {
  auto size = array.size(rt);
  data_.reserve(size);
  for (size_t i = 0; i < size; i++) {
    data_.push_back(extractShareableOrThrow(rt, array.getValueAtIndex(rt, i)));
  }
}

jsi::Value ShareableArray::toJSValue(jsi::Runtime &rt) {
  auto size = data_.size();
  auto ary = jsi::Array(rt, size);
  for (size_t i = 0; i < size; i++) {
    ary.setValueAtIndex(rt, i, data_[i]->toJSValue(rt));
  }
  return ary;
}

jsi::Value ShareableArrayBuffer::toJSValue(jsi::Runtime &rt) {
  auto size = static_cast<int>(data_.size());
  auto arrayBuffer = rt.global()
                         .getPropertyAsFunction(rt, "ArrayBuffer")
                         .callAsConstructor(rt, size)
                         .getObject(rt)
                         .getArrayBuffer(rt);
  memcpy(arrayBuffer.data(rt), data_.data(), size);
  return arrayBuffer;
}

ShareableObject::ShareableObject(jsi::Runtime &rt, const jsi::Object &object)
    : Shareable(ObjectType) {
  auto propertyNames = object.getPropertyNames(rt);
  auto size = propertyNames.size(rt);
  data_.reserve(size);
  for (size_t i = 0; i < size; i++) {
    auto key = propertyNames.getValueAtIndex(rt, i).asString(rt);
    auto value = extractShareableOrThrow(rt, object.getProperty(rt, key));
    data_.emplace_back(key.utf8(rt), value);
  }
#if SUPPORTS_NATIVE_STATE
  if (object.hasNativeState(rt)) {
    nativeState_ = object.getNativeState(rt);
  }
#endif // SUPPORTS_NATIVE_STATE
}

#if SUPPORTS_NATIVE_STATE
ShareableObject::ShareableObject(
    jsi::Runtime &rt,
    const jsi::Object &object,
    const jsi::Value &nativeStateSource)
    : ShareableObject(rt, object) {
  if (nativeStateSource.isObject() &&
      nativeStateSource.asObject(rt).hasNativeState(rt)) {
    nativeState_ = nativeStateSource.asObject(rt).getNativeState(rt);
  }
}
#endif // SUPPORTS_NATIVE_STATE

jsi::Value ShareableObject::toJSValue(jsi::Runtime &rt) {
  auto obj = jsi::Object(rt);
  for (size_t i = 0, size = data_.size(); i < size; i++) {
    obj.setProperty(rt, jsi::String::createFromUtf8(rt, data_[i].first), data_[i].second->toJSValue(rt));
  }
#if SUPPORTS_NATIVE_STATE
  if (nativeState_ != nullptr) {
    obj.setNativeState(rt, nativeState_);
  }
#endif // SUPPORTS_NATIVE_STATE
  return obj;
}

jsi::Value ShareableHostObject::toJSValue(jsi::Runtime &rt) {
  return jsi::Object::createFromHostObject(rt, hostObject_);
}

jsi::Value ShareableHostFunction::toJSValue(jsi::Runtime &rt) {
  return jsi::Function::createFromHostFunction(
      rt, jsi::PropNameID::forUtf8(rt, name_), paramCount_, hostFunction_);
}

jsi::Value ShareableWorklet::toJSValue(jsi::Runtime &rt) {
  assert(
      std::any_of(
          data_.cbegin(),
          data_.cend(),
          [](const auto &item) { return item.first == "__workletHash"; }) &&
      "ShareableWorklet doesn't have `__workletHash` property");
  jsi::Value obj = ShareableObject::toJSValue(rt);
  return getValueUnpacker(rt).call(
      rt, obj, jsi::String::createFromAscii(rt, "Worklet"));
}

jsi::Value ShareableRemoteFunction::toJSValue(jsi::Runtime &rt) {
  if (&rt == runtime_) {
    return jsi::Value(rt, *function_);
  } else {
#ifndef NDEBUG
    return getValueUnpacker(rt).call(
        rt,
        ShareableJSRef::newHostObject(rt, shared_from_this()),
        jsi::String::createFromAscii(rt, "RemoteFunction"),
        jsi::String::createFromUtf8(rt, name_));
#else
    return ShareableJSRef::newHostObject(rt, shared_from_this());
#endif
  }
}

jsi::Value ShareableHandle::toJSValue(jsi::Runtime &rt) {
  if (remoteValue_ == nullptr) {
    auto initObj = initializer_->toJSValue(rt);
    auto value = std::make_unique<jsi::Value>(getValueUnpacker(rt).call(
        rt, initObj, jsi::String::createFromAscii(rt, "Handle")));

    // We are locking the initialization here since the thread that is
    // initalizing can be pre-empted on runtime lock. E.g.
    // UI thread can be pre-empted on initialization of a shared value and then
    // JS thread can try to access the shared value, locking the whole runtime.
    // If we put the lock on `getValueUnpacker` part (basically any part that
    // requires runtime) we would get a deadlock since UI thread would never
    // release it.
    std::unique_lock<std::mutex> lock(initializationMutex_);
    if (remoteValue_ == nullptr) {
      remoteValue_ = std::move(value);
      remoteRuntime_ = &rt;
    }
  }
  return jsi::Value(rt, *remoteValue_);
}

jsi::Value ShareableString::toJSValue(jsi::Runtime &rt) {
  return jsi::String::createFromUtf8(rt, data_);
}

jsi::Value ShareableBigInt::toJSValue(jsi::Runtime &rt) {
  return rt.global()
      .getPropertyAsFunction(rt, "BigInt")
      .call(rt, jsi::String::createFromUtf8(rt, string_));
}

jsi::Value ShareableScalar::toJSValue(jsi::Runtime &) {
  switch (valueType_) {
    case Shareable::UndefinedType:
      return jsi::Value();
    case Shareable::NullType:
      return jsi::Value(nullptr);
    case Shareable::BooleanType:
      return jsi::Value(data_.boolean);
    case Shareable::NumberType:
      return jsi::Value(data_.number);
    default:
      throw std::runtime_error(
          "[Reanimated] Attempted to convert object that's not of a scalar type.");
  }
}

} /* namespace reanimated */
```