Change ArrayBuffer implementation from copyBuffer to moveBuffer (#56691)#56691
Open
christophpurrer wants to merge 3 commits intofacebook:mainfrom
Open
Change ArrayBuffer implementation from copyBuffer to moveBuffer (#56691)#56691christophpurrer wants to merge 3 commits intofacebook:mainfrom
christophpurrer wants to merge 3 commits intofacebook:mainfrom
Conversation
|
@christophpurrer has exported this pull request. If you are a Meta employee, you can view the originating Diff in D96034456. |
…etween JavaScript and native Summary: ## Changelog: [General] [Added] - Add ArrayBuffer support for React Native Turbo Modules react-native-community/discussions-and-proposals#947 Adds first-class `ArrayBuffer` support across the entire TurboModule pipeline, enabling efficient binary data transfer between JavaScript and native code without base64 encoding overhead. **Schema & Parser:** - Added `NativeModuleArrayBufferTypeAnnotation` to `CodegenSchema.js` and `.d.ts` - Added `emitArrayBuffer` to `parsers-primitives.js` type map **C++ (Bridging & Generator):** - Added `ArrayBufferKind` to `TurboModuleMethodValueKind` enum - Created `ArrayBuffer.h` bridging header with `OwnedMutableBuffer` and `Bridging<std::vector<uint8_t>>` - Added `jsi::ArrayBuffer` conversion operators to `Convert.h` - Mapped `ArrayBufferTypeAnnotation` → `jsi::ArrayBuffer` in `GenerateModuleH.js` **Android (Java/JNI):** - Mapped `ArrayBufferTypeAnnotation` → `java.nio.ByteBuffer` in Java spec generator - Mapped to `Ljava/nio/ByteBuffer;` JNI signature in JNI generator - Added `ByteBuffer` arg/return handling in `JavaTurboModule.cpp` via `NewDirectByteBuffer`/`GetDirectBufferAddress` **iOS (ObjC):** - Mapped `ArrayBufferTypeAnnotation` → `NSData *` in ObjC spec generator - Added ArrayBuffer→NSData conversion in `convertJSIValueToObjCObject()` - Added NSData→ArrayBuffer conversion in `convertReturnIdToJSIValue()` **Flow-Schema:** - Added `ArrayBuffer` to `JAVASCRIPT_BUILTINS` in `BoundaryTypes.js` **Tests:** - Added Flow and TypeScript parser fixtures (`NATIVE_MODULE_WITH_ARRAYBUFFER`) - Added generator schema fixture (`ARRAYBUFFER_MODULE`) - Added `emitArrayBuffer` unit tests Differential Revision: D95649873
Summary: ## Changelog: [General] [Added] - Add ArrayBuffer sample methods to TurboModule examples react-native-community/discussions-and-proposals#947 Add `getArrayBuffer` method to NativeCxxModuleExample and NativeSampleTurboModule specs to demonstrate and validate ArrayBuffer support across all platforms. - **JS Specs:** Added `getArrayBuffer: (arg: ArrayBuffer) => ArrayBuffer` to both NativeCxxModuleExample.js and NativeSampleTurboModule.js - **C++:** Implemented in NativeCxxModuleExample.cpp using `OwnedMutableBuffer` to copy and return the ArrayBuffer - **Java/Kotlin:** Implemented in SampleTurboModule.kt with `ByteBuffer` param/return - **ObjC:** Implemented in RCTSampleTurboModule.mm (iOS + macOS) with `NSData *` param/return Differential Revision: D95652569
…book#56691) Summary: Pull Request resolved: facebook#56691 Switches the `jsi::ArrayBuffer ⇄ native byte buffer` bridge in TurboModules from a copy-based implementation (`OwnedMutableBuffer`) to a zero-copy borrow implementation (`BorrowedMutableBuffer`) on the paths where the caller can guarantee the source memory's lifetime, eliminating an O(N) copy on every ArrayBuffer that crosses the JS/native boundary. **`ReactCommon/react/bridging/ArrayBuffer.h`** — adds `BorrowedMutableBuffer`: holds a raw `uint8_t*` + size, plus an optional `std::function<void()>` release callback invoked from the destructor. Caller is responsible for keeping the underlying memory alive — typically by capturing a JNI `global_ref` or ARC-retained ObjC object in the release lambda. Non-copyable; documents thread-safety requirements (release may fire on the JS GC thread). `OwnedMutableBuffer` and the `Bridging<std::vector<uint8_t>>` specialization are preserved for paths where the source lifetime cannot be guaranteed. **Android — `JavaTurboModule.cpp`** — wraps the Java `ByteBuffer`'s direct memory in a `BorrowedMutableBuffer`. Pins the buffer with `jni::make_global(jByteBuffer)` and captures the global ref in the release lambda so Java GC cannot collect it while the JS ArrayBuffer is alive. Tightens the `Ljava/nio/ByteBuffer;` argument check from `isObject()` to `isObject() && isArrayBuffer()`. **iOS — `RCTTurboModule.mm`** — `convertJSIObjectToObjCObject` (sync arg path) returns `NSMutableData dataWithBytesNoCopy:length:freeWhenDone:NO` instead of copying via `[NSData dataWithBytes:length:]`. Safe because the JS ArrayBuffer outlives the synchronous call. `convertReturnIdToJSIValue` `ArrayBufferKind` (sync return path) wraps `NSMutableData.mutableBytes` with `BorrowedMutableBuffer`, retaining the `NSMutableData` via the block capture for the lifetime of the JS ArrayBuffer. `convertObjCObjectToJSIValue` (async/promise path) adds an `NSData → ArrayBuffer` branch that still copies via `OwnedMutableBuffer`, since the source NSData lifetime cannot be guaranteed past the async callback. **Codegen — `serializeMethod.js` + snapshot** — ObjC++ spec generator now emits `NSMutableData *` (instead of `NSData *`) for `ArrayBufferTypeAnnotation`, both for parameters and return types. Module authors must update their ObjC implementations. Changelog: [General][Changed] - TurboModule ArrayBuffer transfers between JS and native are now zero-copy where caller lifetime can be guaranteed; ObjC TurboModule specs now use `NSMutableData *` for `ArrayBufferTypeAnnotation` parameters and return types Differential Revision: D96034456
82af115 to
5b43793
Compare
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.
Summary:
Switches the
jsi::ArrayBuffer ⇄ native byte bufferbridge in TurboModules from a copy-based implementation (OwnedMutableBuffer) to a zero-copy borrow implementation (BorrowedMutableBuffer) on the paths where the caller can guarantee the source memory's lifetime, eliminating an O(N) copy on every ArrayBuffer that crosses the JS/native boundary.ReactCommon/react/bridging/ArrayBuffer.h— addsBorrowedMutableBuffer: holds a rawuint8_t*+ size, plus an optionalstd::function<void()>release callback invoked from the destructor. Caller is responsible for keeping the underlying memory alive — typically by capturing a JNIglobal_refor ARC-retained ObjC object in the release lambda. Non-copyable; documents thread-safety requirements (release may fire on the JS GC thread).OwnedMutableBufferand theBridging<std::vector<uint8_t>>specialization are preserved for paths where the source lifetime cannot be guaranteed.Android —
JavaTurboModule.cpp— wraps the JavaByteBuffer's direct memory in aBorrowedMutableBuffer. Pins the buffer withjni::make_global(jByteBuffer)and captures the global ref in the release lambda so Java GC cannot collect it while the JS ArrayBuffer is alive. Tightens theLjava/nio/ByteBuffer;argument check fromisObject()toisObject() && isArrayBuffer().iOS —
RCTTurboModule.mm—convertJSIObjectToObjCObject(sync arg path) returnsNSMutableData dataWithBytesNoCopy:length:freeWhenDone:NOinstead of copying via[NSData dataWithBytes:length:]. Safe because the JS ArrayBuffer outlives the synchronous call.convertReturnIdToJSIValueArrayBufferKind(sync return path) wrapsNSMutableData.mutableByteswithBorrowedMutableBuffer, retaining theNSMutableDatavia the block capture for the lifetime of the JS ArrayBuffer.convertObjCObjectToJSIValue(async/promise path) adds anNSData → ArrayBufferbranch that still copies viaOwnedMutableBuffer, since the source NSData lifetime cannot be guaranteed past the async callback.Codegen —
serializeMethod.js+ snapshot — ObjC++ spec generator now emitsNSMutableData *(instead ofNSData *) forArrayBufferTypeAnnotation, both for parameters and return types. Module authors must update their ObjC implementations.Changelog:
[General][Changed] - TurboModule ArrayBuffer transfers between JS and native are now zero-copy where caller lifetime can be guaranteed; ObjC TurboModule specs now use
NSMutableData *forArrayBufferTypeAnnotationparameters and return typesDifferential Revision: D96034456