cherry-pick(worklets-0.9-stable): tie RNR remote function lifetime to TurboModule invalidate status (#9789)#9898
Open
tjzel wants to merge 1 commit into
Conversation
…date status (#9789) ## Summary Fixes #9751 Changing (again) how RN Runtime remote functions (RFs) are managed, since changes from #9673 and #9272 were actually insufficient and the map approach won't work. It's impossible to keep both the actual callback and cached serialized callback value alive without a memory cycle, so I'm dropping cache consistency. This might result in multiple serializations of a given RF the GC triggered and the serialized value wasn't saved, but the serialization of a RF is actually cheap. I'm dropping the map approach entirely in favor of the behavior where destructor invocation is based upon the information if the runtime is still alive. We can't directly check it, so I'm depending on the `invalidate()` method of Turbo Modules - which is supposed to be called when the runtime is still alive. ## Test plan You can test it on [df3e344](df3e344) commit - there's a special registry there that artificially extends the lifetime of Remote Functions - click some buttons on the provided example, then reload the app with R button. The callbacks with persist and will crash on destructor invocation without the check for `isDead`. (cherry picked from commit 325a644)
Contributor
There was a problem hiding this comment.
Pull request overview
Cherry-picks the fix from #9789 onto the 0.9 branch to address a Remote Function (RN Runtime) lifetime/memory issue by tying cleanup behavior to TurboModule invalidation (runtime “alive/dead” status), instead of maintaining a JS-side registry/map.
Changes:
- Remove the JS-side remote function registry/id-based model (and the
functionIdplumbing) in favor of holding the RN-runtimejsi::Functiondirectly on the native side. - Introduce
RNRuntimeStatusand propagate it through module proxies so Remote Function destruction can safely avoid touching torn-down runtime state afterinvalidate(). - Adjust JS-side serializable cache behavior to optionally use
WeakRef(when available) to reduce retention/leak risk.
Reviewed changes
Copilot reviewed 20 out of 21 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/react-native-worklets/src/WorkletsModule/workletsModuleProxy.ts | Removes functionId from the proxy API for non-worklet function serialization. |
| packages/react-native-worklets/src/WorkletsModule/NativeWorklets.native.ts | Updates wrapper to match the new 2-arg native method signature. |
| packages/react-native-worklets/src/privateGlobals.d.ts | Removes the global __remoteFunctionRegistry type declaration. |
| packages/react-native-worklets/src/memory/types.ts | Removes RegisteredRemoteFunction type related to the old keep-alive model. |
| packages/react-native-worklets/src/memory/serializableMappingCache.native.ts | Allows caching WeakRef<SerializableRef> in addition to strong refs/flag. |
| packages/react-native-worklets/src/memory/serializable.native.ts | Drops registry/id usage and uses WeakRef-based caching when available. |
| packages/react-native-worklets/src/memory/remoteFunctionRegistry.native.ts | Deletes the JS-side remote function registry implementation. |
| packages/react-native-worklets/Common/cpp/worklets/Tools/RNRuntimeStatus.h | Adds runtime liveness tracking used to gate Remote Function destruction behavior. |
| packages/react-native-worklets/Common/cpp/worklets/SharedItems/SerializableFactory.h | Changes RN-runtime RF factory to accept a jsi::Function + RNRuntimeStatus. |
| packages/react-native-worklets/Common/cpp/worklets/SharedItems/SerializableFactory.cpp | Implements new RN-runtime RF factory that stores the function directly. |
| packages/react-native-worklets/Common/cpp/worklets/SharedItems/Serializable.h | Refactors SerializableRemoteFunction storage to use function_ + runtime status. |
| packages/react-native-worklets/Common/cpp/worklets/SharedItems/Serializable.cpp | Updates RF destructor and toJSValue to use direct function storage and status checks. |
| packages/react-native-worklets/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.h | Threads RNRuntimeStatus through the proxy API/state. |
| packages/react-native-worklets/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.cpp | Passes RNRuntimeStatus into the RN runtime proxy instance. |
| packages/react-native-worklets/Common/cpp/worklets/NativeModules/JSIWorkletsModuleProxy.h | Stores RNRuntimeStatus for use when creating RN-runtime remote functions. |
| packages/react-native-worklets/Common/cpp/worklets/NativeModules/JSIWorkletsModuleProxy.cpp | Updates createSerializableNonWorkletFunction to 2 args and new RF factory call. |
| packages/react-native-worklets/apple/worklets/apple/WorkletsModule.mm | Creates RNRuntimeStatus on install and marks it dead during invalidate. |
| packages/react-native-worklets/android/src/no-networking/com/swmansion/worklets/WorkletsModule.kt | Removes outdated invalidate rationale comment (no functional change). |
| packages/react-native-worklets/android/src/networking/com/swmansion/worklets/WorkletsModule.kt | Removes outdated invalidate rationale comment (no functional change). |
| packages/react-native-worklets/android/src/main/cpp/worklets/android/WorkletsModule.h | Stores RNRuntimeStatus in the Android hybrid module. |
| packages/react-native-worklets/android/src/main/cpp/worklets/android/WorkletsModule.cpp | Creates and marks RNRuntimeStatus dead on invalidateCpp(). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cherry-picking #9789
This fixes memory leak that is present on the 0.9 branch, introduced in #9272