iOS jsi value ~shared_ptr Crash when RCTHost dealloc #48214
Open
Description
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
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
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
#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 */