diff --git a/packages/react-native-worklets/Common/cpp/worklets/NativeModules/JSIWorkletsModuleProxy.cpp b/packages/react-native-worklets/Common/cpp/worklets/NativeModules/JSIWorkletsModuleProxy.cpp index 33ff739f33d0..d3537d0c627b 100644 --- a/packages/react-native-worklets/Common/cpp/worklets/NativeModules/JSIWorkletsModuleProxy.cpp +++ b/packages/react-native-worklets/Common/cpp/worklets/NativeModules/JSIWorkletsModuleProxy.cpp @@ -336,25 +336,22 @@ jsi::Object JSIWorkletsModuleProxy::toOptimizedObject(jsi::Runtime &rt) const { return makeSerializableArrayBuffer(rt, buffer); }); - jsi_utils::addMethod<3>( + jsi_utils::addMethod<2>( rt, obj, "createSerializableNonWorkletFunction", - [jsScheduler = jsScheduler_, hostRuntimeId = hostRuntimeId_]( - jsi::Runtime &rt, const jsi::Value &, const jsi::Value(&args)[3]) { + [jsScheduler = jsScheduler_, hostRuntimeId = hostRuntimeId_, rnRuntimeStatus = rnRuntimeStatus_]( + jsi::Runtime &rt, const jsi::Value &, const jsi::Value(&args)[2]) { auto fun = at<0>(args).getObject(rt).getFunction(rt); - const auto name = at<2>(args).isUndefined() ? "" : at<2>(args).getString(rt).utf8(rt); + const auto name = at<1>(args).isUndefined() ? "" : at<1>(args).getString(rt).utf8(rt); if (fun.isHostFunction(rt)) { return makeSerializableHostFunction( rt, fun.getHostFunction(rt), name, fun.getProperty(rt, "length").getNumber()); + } else if (hostRuntimeId == RuntimeData::rnRuntimeId) { + return makeSerializableRemoteFunction(rt, name, fun, jsScheduler, rnRuntimeStatus); + } else { + return makeSerializableRemoteFunction(rt, name, std::move(fun), hostRuntimeId); } - if (hostRuntimeId == RuntimeData::rnRuntimeId) { - const int remoteId = static_cast(at<1>(args).getNumber()); - auto ref = makeSerializableRemoteFunction(rt, name, remoteId, jsScheduler); - ref.asObject(rt).setProperty(rt, "__keepAlive", true); - return ref; - } - return makeSerializableRemoteFunction(rt, name, std::move(fun), hostRuntimeId); }); jsi_utils::addMethod<2>( diff --git a/packages/react-native-worklets/Common/cpp/worklets/NativeModules/JSIWorkletsModuleProxy.h b/packages/react-native-worklets/Common/cpp/worklets/NativeModules/JSIWorkletsModuleProxy.h index f99660554a35..cf08d0c5ceb5 100644 --- a/packages/react-native-worklets/Common/cpp/worklets/NativeModules/JSIWorkletsModuleProxy.h +++ b/packages/react-native-worklets/Common/cpp/worklets/NativeModules/JSIWorkletsModuleProxy.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,7 @@ class JSIWorkletsModuleProxy : public std::enable_shared_from_this &runtimeBindings, const BundleModeConfig &bundleModeConfig, const std::shared_ptr &unpackerLoader, + const std::shared_ptr &rnRuntimeStatus, RuntimeData::RuntimeId hostRuntimeId) : isDevBundle_(isDevBundle), bundleModeConfig_(bundleModeConfig), @@ -41,6 +43,7 @@ class JSIWorkletsModuleProxy : public std::enable_shared_from_this createForNewRuntime( @@ -56,6 +59,7 @@ class JSIWorkletsModuleProxy : public std::enable_shared_from_thisruntimeBindings_, sourceProxy->bundleModeConfig_, sourceProxy->unpackerLoader_, + sourceProxy->rnRuntimeStatus_, hostRuntimeId); } @@ -115,6 +119,7 @@ class JSIWorkletsModuleProxy : public std::enable_shared_from_this uiWorkletRuntime_; const std::shared_ptr runtimeBindings_; const std::shared_ptr unpackerLoader_; + const std::shared_ptr rnRuntimeStatus_; const RuntimeData::RuntimeId hostRuntimeId_; }; diff --git a/packages/react-native-worklets/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.cpp b/packages/react-native-worklets/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.cpp index 8149dc985227..94dd3afe5088 100644 --- a/packages/react-native-worklets/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.cpp +++ b/packages/react-native-worklets/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.cpp @@ -45,7 +45,8 @@ WorkletsModuleProxy::WorkletsModuleProxy( const std::shared_ptr &uiScheduler, std::function &&isJavaScriptThread, const std::shared_ptr &runtimeBindings, - const BundleModeConfig &bundleModeConfig) + const BundleModeConfig &bundleModeConfig, + const std::shared_ptr &rnRuntimeStatus) : isDevBundle_(isDevBundleFromRNRuntime(rnRuntime)), jsScheduler_(std::make_shared(rnRuntime, jsCallInvoker, std::move(isJavaScriptThread))), uiScheduler_(uiScheduler), @@ -55,6 +56,7 @@ WorkletsModuleProxy::WorkletsModuleProxy( memoryManager_(std::make_shared()), runtimeManager_(std::make_shared()), unpackerLoader_(std::make_shared()), + rnRuntimeStatus_(rnRuntimeStatus), uiWorkletRuntime_(runtimeManager_->createUninitializedUIRuntime(std::make_shared(uiScheduler_))), rnRuntimeProxy_(std::make_shared( isDevBundle_, @@ -66,6 +68,7 @@ WorkletsModuleProxy::WorkletsModuleProxy( runtimeBindings_, bundleModeConfig_, unpackerLoader_, + rnRuntimeStatus_, RuntimeData::rnRuntimeId)) { RNRuntimeWorkletDecorator::decorate(rnRuntime, rnRuntimeProxy_->toOptimizedObject(rnRuntime), jsLogger_); } diff --git a/packages/react-native-worklets/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.h b/packages/react-native-worklets/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.h index fc1a8e2c1fbc..540976ed53ec 100644 --- a/packages/react-native-worklets/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.h +++ b/packages/react-native-worklets/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -28,7 +29,8 @@ class WorkletsModuleProxy : public std::enable_shared_from_this &uiScheduler, std::function &&isJavaScriptQueue, const std::shared_ptr &runtimeBindings, - const BundleModeConfig &bundleModeConfig); + const BundleModeConfig &bundleModeConfig, + const std::shared_ptr &rnRuntimeStatus); ~WorkletsModuleProxy(); @@ -62,6 +64,7 @@ class WorkletsModuleProxy : public std::enable_shared_from_this memoryManager_; const std::shared_ptr runtimeManager_; const std::shared_ptr unpackerLoader_; + const std::shared_ptr rnRuntimeStatus_; std::shared_ptr uiWorkletRuntime_; const std::shared_ptr rnRuntimeProxy_; std::shared_ptr animationFrameBatchinator_; diff --git a/packages/react-native-worklets/Common/cpp/worklets/SharedItems/Serializable.cpp b/packages/react-native-worklets/Common/cpp/worklets/SharedItems/Serializable.cpp index 3114a09c60f2..b5525a4170b3 100644 --- a/packages/react-native-worklets/Common/cpp/worklets/SharedItems/Serializable.cpp +++ b/packages/react-native-worklets/Common/cpp/worklets/SharedItems/Serializable.cpp @@ -28,12 +28,6 @@ jsi::Function getRemoteFunctionUnpacker(jsi::Runtime &rt) { return remoteFunctionUnpacker.asObject(rt).asFunction(rt); } -jsi::Object getRemoteFunctionRegistry(jsi::Runtime &rt) { - auto registry = rt.global().getProperty(rt, "__remoteFunctionRegistry"); - react_native_assert(registry.isObject() && "remoteFunctionRegistry not found"); - return registry.getObject(rt); -} - } // namespace jsi::Value makeSerializableClone( @@ -298,28 +292,19 @@ jsi::Value SerializableImport::toJSValue(jsi::Runtime &rt) { SerializableRemoteFunction::~SerializableRemoteFunction() { if (isHostedOnRNRuntime()) { - // TODO: consider batching - const auto &data = std::get(runtimeData_); - data.jsScheduler->scheduleOnJS([id = data.remoteId](jsi::Runtime &rt) { - const auto registry = getRemoteFunctionRegistry(rt); - registry.getPropertyAsFunction(rt, "delete").callWithThis(rt, registry, jsi::Value(id)); - }); + if (rnRuntimeStatus_->isDead()) { + freeWithoutCallingDestructor(function_); + } else { + function_.reset(); + } } else { - auto &workletData = std::get(runtimeData_); - cleanupRuntimeAware(hostRuntime_, workletData.function); + cleanupRuntimeAware(hostRuntime_, function_); } } jsi::Value SerializableRemoteFunction::toJSValue(jsi::Runtime &rt) { if (&rt == hostRuntime_) { - if (isHostedOnRNRuntime()) { - const auto &rnData = std::get(runtimeData_); - const auto registry = getRemoteFunctionRegistry(rt); - return registry.getPropertyAsFunction(rt, "get").callWithThis(rt, registry, jsi::Value(rnData.remoteId)); - } else { - const auto &workletData = std::get(runtimeData_); - return jsi::Value(rt, *workletData.function); - } + return jsi::Value(rt, *function_); } else { const auto name = name_.empty() ? jsi::Value::undefined() : jsi::String::createFromUtf8(rt, name_); auto holderFunction = getRemoteFunctionUnpacker(rt).call(rt, name).getObject(rt); @@ -333,8 +318,7 @@ void SerializableRemoteFunction::resolveOrRejectPromise( const std::shared_ptr &resolveValue, const std::shared_ptr &runtimeManager) { if (isHostedOnRNRuntime()) { - const auto &data = std::get(runtimeData_); - data.jsScheduler->scheduleOnJS([resolver = shared_from_this(), resolveValue](jsi::Runtime &rt) { + jsScheduler_->scheduleOnJS([resolver = shared_from_this(), resolveValue](jsi::Runtime &rt) { resolver->toJSValue(rt).getObject(rt).getFunction(rt).call(rt, resolveValue->toJSValue(rt)); }); } else { diff --git a/packages/react-native-worklets/Common/cpp/worklets/SharedItems/Serializable.h b/packages/react-native-worklets/Common/cpp/worklets/SharedItems/Serializable.h index 41940974a549..5d5ef4fa1e34 100644 --- a/packages/react-native-worklets/Common/cpp/worklets/SharedItems/Serializable.h +++ b/packages/react-native-worklets/Common/cpp/worklets/SharedItems/Serializable.h @@ -4,13 +4,13 @@ #include #include #include +#include #include #include #include #include #include -#include #include using namespace facebook; @@ -283,33 +283,21 @@ class RuntimeManager; class SerializableRemoteFunction : public Serializable, public std::enable_shared_from_this { - private: - struct RNRuntimeData { - const int remoteId; - const std::shared_ptr jsScheduler; - }; - - struct WorkletRuntimeData { - std::unique_ptr function; - }; - - jsi::Runtime *hostRuntime_; - const RuntimeData::RuntimeId hostRuntimeId_; - std::variant runtimeData_; - const std::string name_; - public: /** Creates RN Runtime Remote Function. */ SerializableRemoteFunction( jsi::Runtime &rnRuntime, const std::string &name, - const int remoteId, - const std::shared_ptr &jsScheduler) + jsi::Function &&function, + const std::shared_ptr &jsScheduler, + const std::shared_ptr &rnRuntimeStatus) : Serializable(ValueType::RemoteFunctionType), hostRuntime_(&rnRuntime), hostRuntimeId_(RuntimeData::rnRuntimeId), - runtimeData_(RNRuntimeData{.remoteId = remoteId, .jsScheduler = jsScheduler}), - name_(name) {} + function_(std::make_unique(rnRuntime, std::move(function))), + name_(name), + jsScheduler_(jsScheduler), + rnRuntimeStatus_(rnRuntimeStatus) {} /** Creates Worklet Runtime Remote Function. */ SerializableRemoteFunction( @@ -320,8 +308,10 @@ class SerializableRemoteFunction : public Serializable, : Serializable(ValueType::RemoteFunctionType), hostRuntime_(&workletRuntime), hostRuntimeId_(hostRuntimeId), - runtimeData_(WorkletRuntimeData{.function = std::make_unique(workletRuntime, std::move(function))}), - name_(name) {} + function_(std::make_unique(workletRuntime, std::move(function))), + name_(name), + jsScheduler_(nullptr), + rnRuntimeStatus_(nullptr) {} ~SerializableRemoteFunction() override; @@ -335,12 +325,20 @@ class SerializableRemoteFunction : public Serializable, jsi::Value toJSValue(jsi::Runtime &rt) override; [[nodiscard]] bool isHostedOnRNRuntime() const noexcept { - return std::holds_alternative(runtimeData_); + return hostRuntimeId_ == RuntimeData::rnRuntimeId; } [[nodiscard]] RuntimeData::RuntimeId getHostRuntimeId() const { return hostRuntimeId_; } + + private: + jsi::Runtime *hostRuntime_; + const RuntimeData::RuntimeId hostRuntimeId_; + std::unique_ptr function_; + const std::string name_; + const std::shared_ptr jsScheduler_; + const std::shared_ptr rnRuntimeStatus_; }; class SerializableInitializer : public Serializable { diff --git a/packages/react-native-worklets/Common/cpp/worklets/SharedItems/SerializableFactory.cpp b/packages/react-native-worklets/Common/cpp/worklets/SharedItems/SerializableFactory.cpp index 97b078761f93..7864868b2b36 100644 --- a/packages/react-native-worklets/Common/cpp/worklets/SharedItems/SerializableFactory.cpp +++ b/packages/react-native-worklets/Common/cpp/worklets/SharedItems/SerializableFactory.cpp @@ -63,9 +63,15 @@ jsi::Value makeSerializableHostFunction( jsi::Value makeSerializableRemoteFunction( jsi::Runtime &rnRuntime, const std::string &name, - const int remoteId, - const std::shared_ptr &jsScheduler) { - auto serializable = std::make_shared(rnRuntime, name, remoteId, jsScheduler); + const jsi::Function &function, + const std::shared_ptr &jsScheduler, + const std::shared_ptr &rnRuntimeStatus) { + auto serializable = std::make_shared( + rnRuntime, + name, + jsi::Value(rnRuntime, function).getObject(rnRuntime).getFunction(rnRuntime), + jsScheduler, + rnRuntimeStatus); return SerializableJSRef::newNativeStateObject(rnRuntime, serializable); } diff --git a/packages/react-native-worklets/Common/cpp/worklets/SharedItems/SerializableFactory.h b/packages/react-native-worklets/Common/cpp/worklets/SharedItems/SerializableFactory.h index a7ce5effb781..7336919c1442 100644 --- a/packages/react-native-worklets/Common/cpp/worklets/SharedItems/SerializableFactory.h +++ b/packages/react-native-worklets/Common/cpp/worklets/SharedItems/SerializableFactory.h @@ -63,8 +63,9 @@ jsi::Value makeSerializableHostFunction( jsi::Value makeSerializableRemoteFunction( jsi::Runtime &rnRuntime, const std::string &name, - int remoteId, - const std::shared_ptr &jsScheduler); + const jsi::Function &function, + const std::shared_ptr &jsScheduler, + const std::shared_ptr &rnRuntimeStatus); /** Creates Worklet Runtime Remote Function. */ jsi::Value makeSerializableRemoteFunction( diff --git a/packages/react-native-worklets/Common/cpp/worklets/Tools/RNRuntimeStatus.h b/packages/react-native-worklets/Common/cpp/worklets/Tools/RNRuntimeStatus.h new file mode 100644 index 000000000000..772ee50682ea --- /dev/null +++ b/packages/react-native-worklets/Common/cpp/worklets/Tools/RNRuntimeStatus.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +namespace worklets { + +class RNRuntimeStatus { + public: + [[nodiscard]] bool isDead() const { + return isDead_; + } + + void setDead() { + isDead_ = true; + } + + private: + std::atomic_bool isDead_ = false; +}; + +} // namespace worklets diff --git a/packages/react-native-worklets/android/src/main/cpp/worklets/android/WorkletsModule.cpp b/packages/react-native-worklets/android/src/main/cpp/worklets/android/WorkletsModule.cpp index c9bda01b6f1d..0b18991bd057 100644 --- a/packages/react-native-worklets/android/src/main/cpp/worklets/android/WorkletsModule.cpp +++ b/packages/react-native-worklets/android/src/main/cpp/worklets/android/WorkletsModule.cpp @@ -33,13 +33,15 @@ WorkletsModule::WorkletsModule( const std::shared_ptr &uiScheduler) : javaPart_(jni::make_global(jThis)), rnRuntime_(rnRuntime), + rnRuntimeStatus_(std::make_shared()), workletsModuleProxy_(std::make_shared( *rnRuntime, jsCallInvoker, uiScheduler, getIsOnJSQueueThread(), getRuntimeBindings(bundleModeConfig.enabled, *rnRuntime), - bundleModeConfig)) {} + bundleModeConfig, + rnRuntimeStatus_)) {} jni::local_ref WorkletsModule::initHybrid( jni::alias_ref jThis, // NOLINT //(performance-unnecessary-value-param) @@ -179,6 +181,7 @@ std::function WorkletsModule::getIsOnJSQueueThread() { } void WorkletsModule::invalidateCpp() { + rnRuntimeStatus_->setDead(); javaPart_.reset(); workletsModuleProxy_.reset(); } diff --git a/packages/react-native-worklets/android/src/main/cpp/worklets/android/WorkletsModule.h b/packages/react-native-worklets/android/src/main/cpp/worklets/android/WorkletsModule.h index dfe2f8b69790..bc4ee11ed4a8 100644 --- a/packages/react-native-worklets/android/src/main/cpp/worklets/android/WorkletsModule.h +++ b/packages/react-native-worklets/android/src/main/cpp/worklets/android/WorkletsModule.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,7 @@ class WorkletsModule : public jni::HybridClass { friend HybridBase; jni::global_ref javaPart_; jsi::Runtime *rnRuntime_; + std::shared_ptr rnRuntimeStatus_; std::shared_ptr workletsModuleProxy_; }; diff --git a/packages/react-native-worklets/android/src/networking/com/swmansion/worklets/WorkletsModule.kt b/packages/react-native-worklets/android/src/networking/com/swmansion/worklets/WorkletsModule.kt index 5d6e0d8d8199..7e2346c62515 100644 --- a/packages/react-native-worklets/android/src/networking/com/swmansion/worklets/WorkletsModule.kt +++ b/packages/react-native-worklets/android/src/networking/com/swmansion/worklets/WorkletsModule.kt @@ -166,9 +166,6 @@ class WorkletsModule( return } if (mHybridData != null && mHybridData!!.isValid) { - // We have to destroy extra runtimes when invalidate is called. If we clean - // it up later instead there's a chance the runtime will retain references - // to invalidated memory and will crash on its destruction. invalidateCpp() } mAndroidUIScheduler.deactivate() diff --git a/packages/react-native-worklets/android/src/no-networking/com/swmansion/worklets/WorkletsModule.kt b/packages/react-native-worklets/android/src/no-networking/com/swmansion/worklets/WorkletsModule.kt index 3f4c43a7cdc3..56bf3055b60f 100644 --- a/packages/react-native-worklets/android/src/no-networking/com/swmansion/worklets/WorkletsModule.kt +++ b/packages/react-native-worklets/android/src/no-networking/com/swmansion/worklets/WorkletsModule.kt @@ -122,9 +122,6 @@ class WorkletsModule( return } if (mHybridData != null && mHybridData!!.isValid) { - // We have to destroy extra runtimes when invalidate is called. If we clean - // it up later instead there's a chance the runtime will retain references - // to invalidated memory and will crash on its destruction. invalidateCpp() } mAndroidUIScheduler.deactivate() diff --git a/packages/react-native-worklets/apple/worklets/apple/WorkletsModule.mm b/packages/react-native-worklets/apple/worklets/apple/WorkletsModule.mm index 29cd4896af3d..8aabb1432405 100644 --- a/packages/react-native-worklets/apple/worklets/apple/WorkletsModule.mm +++ b/packages/react-native-worklets/apple/worklets/apple/WorkletsModule.mm @@ -1,4 +1,5 @@ #import +#import #import #import #import @@ -27,6 +28,7 @@ - (void *)runtime; @implementation WorkletsModule { AnimationFrameQueue *animationFrameQueue_; std::shared_ptr workletsModuleProxy_; + std::shared_ptr rnRuntimeStatus_; #ifdef WORKLETS_FETCH_PREVIEW_ENABLED WorkletsNetworking *workletsNetworking_; #endif // WORKLETS_FETCH_PREVIEW_ENABLED @@ -79,6 +81,7 @@ @implementation WorkletsModule { }; animationFrameQueue_ = [AnimationFrameQueue new]; auto runtimeBindings = [self getRuntimeBindings:rnRuntime bundleModeEnabled:bundleModeEnabled]; + rnRuntimeStatus_ = std::make_shared(); workletsModuleProxy_ = std::make_shared( rnRuntime, @@ -86,7 +89,8 @@ @implementation WorkletsModule { uiScheduler, std::move(isJavaScriptQueue), runtimeBindings, - BundleModeConfig{.enabled = static_cast(bundleModeEnabled), .script = script, .sourceURL = sourceURL}); + BundleModeConfig{.enabled = static_cast(bundleModeEnabled), .script = script, .sourceURL = sourceURL}, + rnRuntimeStatus_); return @YES; } @@ -109,9 +113,7 @@ - (void)invalidate [animationFrameQueue_ invalidate]; - // We have to destroy extra runtimes when invalidate is called. If we clean - // it up later instead there's a chance the runtime will retain references - // to invalidated memory and will crash on destruction. + rnRuntimeStatus_->setDead(); workletsModuleProxy_.reset(); [super invalidate]; diff --git a/packages/react-native-worklets/src/WorkletsModule/NativeWorklets.native.ts b/packages/react-native-worklets/src/WorkletsModule/NativeWorklets.native.ts index 778a67783ed0..2b6e077ea921 100644 --- a/packages/react-native-worklets/src/WorkletsModule/NativeWorklets.native.ts +++ b/packages/react-native-worklets/src/WorkletsModule/NativeWorklets.native.ts @@ -174,12 +174,10 @@ See https://docs.swmansion.com/react-native-worklets/docs/guides/troubleshooting createSerializableNonWorkletFunction( fun: (...args: TArgs) => TReturn, - functionId: number, functionName: string | undefined ): SerializableRef<(...args: TArgs) => TReturn> { return this.#workletsModuleProxy.createSerializableNonWorkletFunction( fun, - functionId, functionName ); } diff --git a/packages/react-native-worklets/src/WorkletsModule/workletsModuleProxy.ts b/packages/react-native-worklets/src/WorkletsModule/workletsModuleProxy.ts index d545482e7dca..ebb8c2d0fc44 100644 --- a/packages/react-native-worklets/src/WorkletsModule/workletsModuleProxy.ts +++ b/packages/react-native-worklets/src/WorkletsModule/workletsModuleProxy.ts @@ -96,7 +96,6 @@ export interface WorkletsModuleProxy { createSerializableNonWorkletFunction( fun: (...args: TArgs) => TReturn, - functionId: number, functionName: string | undefined ): SerializableRef<(...args: TArgs) => TReturn>; diff --git a/packages/react-native-worklets/src/memory/remoteFunctionRegistry.native.ts b/packages/react-native-worklets/src/memory/remoteFunctionRegistry.native.ts deleted file mode 100644 index 4573b83c6926..000000000000 --- a/packages/react-native-worklets/src/memory/remoteFunctionRegistry.native.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-function-type */ -'use strict'; - -const remoteFunctionRegistry = new Map(); - -export let nextRemoteFunctionId = 1; - -export function registerRemoteFunction(fun: Function): number { - const id = nextRemoteFunctionId++; - remoteFunctionRegistry.set(id, fun); - return id; -} - -globalThis.__remoteFunctionRegistry = remoteFunctionRegistry; diff --git a/packages/react-native-worklets/src/memory/serializable.native.ts b/packages/react-native-worklets/src/memory/serializable.native.ts index fd73c6b0d362..5a356c1b7fe1 100644 --- a/packages/react-native-worklets/src/memory/serializable.native.ts +++ b/packages/react-native-worklets/src/memory/serializable.native.ts @@ -8,17 +8,12 @@ import type { WorkletFunction, WorkletImport } from '../types'; import { isWorkletFunction } from '../workletFunction'; import { WorkletsModule } from '../WorkletsModule/NativeWorklets'; import { isSynchronizable } from './isSynchronizable'; -import { - nextRemoteFunctionId, - registerRemoteFunction, -} from './remoteFunctionRegistry'; import { serializableMappingCache, serializableMappingFlag, } from './serializableMappingCache'; import type { FlatSerializableRef, - RegisteredRemoteFunction, RegistrationData, RemoteFunction, SerializableRef, @@ -177,7 +172,15 @@ export function createSerializable( const cached = getFromCache(value); if (cached !== undefined) { - return cached as SerializableRef; + if (globalThis.WeakRef && cached instanceof WeakRef) { + // WeakRef is installed on runtimes only with Hermes microtaskQueue enabled. + const deref = cached.deref(); + if (deref !== undefined) { + return deref as SerializableRef; + } + } else { + return cached as SerializableRef; + } } if (Array.isArray(value)) { @@ -443,19 +446,18 @@ function cloneArray( function cloneNonWorkletFunction( fun: (...args: TArgs) => TReturn ): SerializableRef<(...args: TArgs) => TReturn> { - const functionId = nextRemoteFunctionId; const clone = WorkletsModule.createSerializableNonWorkletFunction( fun, - functionId, __DEV__ ? fun.name : undefined ) as SerializableRef<(...args: TArgs) => TReturn>; - if ((clone as RegisteredRemoteFunction).__keepAlive) { - registerRemoteFunction(fun); + + if (globalThis.WeakRef) { + // WeakRef is installed on runtimes only with Hermes microtaskQueue enabled. + serializableMappingCache.set(fun, new WeakRef(clone)); + serializableMappingCache.set(clone); + freezeObjectInDev(fun); } - serializableMappingCache.set(fun, clone); - serializableMappingCache.set(clone); - freezeObjectInDev(fun); return clone; } diff --git a/packages/react-native-worklets/src/memory/serializableMappingCache.native.ts b/packages/react-native-worklets/src/memory/serializableMappingCache.native.ts index f270194343dc..c60d111d0bf7 100644 --- a/packages/react-native-worklets/src/memory/serializableMappingCache.native.ts +++ b/packages/react-native-worklets/src/memory/serializableMappingCache.native.ts @@ -21,10 +21,16 @@ During cloning we use `Object.entries` to iterate over the keys which throws an For convenience we moved this cache to a separate file so it doesn't scare us with red squiggles. */ -const cache = new WeakMap(); +const cache = new WeakMap< + object, + SerializableRef | WeakRef | symbol +>(); export const serializableMappingCache = { - set(serializable: object, serializableRef?: SerializableRef): void { + set( + serializable: object, + serializableRef?: SerializableRef | WeakRef + ): void { cache.set(serializable, serializableRef || serializableMappingFlag); }, get: cache.get.bind(cache), diff --git a/packages/react-native-worklets/src/memory/types.ts b/packages/react-native-worklets/src/memory/types.ts index 38d05b37ab5a..46f805de641f 100644 --- a/packages/react-native-worklets/src/memory/types.ts +++ b/packages/react-native-worklets/src/memory/types.ts @@ -189,8 +189,3 @@ export interface RemoteFunction extends SerializableRef { /** Defined when extracted on a Guest Runtime. */ __remoteFunction: true | undefined; } - -export interface RegisteredRemoteFunction extends SerializableRef { - /** Defined when created on the Host Runtime. */ - __keepAlive: true | undefined; -} diff --git a/packages/react-native-worklets/src/privateGlobals.d.ts b/packages/react-native-worklets/src/privateGlobals.d.ts index 58db73121692..e038b0a1be29 100644 --- a/packages/react-native-worklets/src/privateGlobals.d.ts +++ b/packages/react-native-worklets/src/privateGlobals.d.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unsafe-function-type */ 'use strict'; // This file works by accident - currently Builder Bob doesn't move `.d.ts` files to output types. @@ -112,7 +111,6 @@ declare global { unknown, unknown >; - var __remoteFunctionRegistry: Map; /** Only in Bundle Mode on Worklet Runtimes. */ var TurboModules: Map; /**