react-native 0.88.0-rc.1 → 0.88.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29,7 +29,7 @@ export default class ReactNativeVersion {
29
29
  static major: number = 0;
30
30
  static minor: number = 88;
31
31
  static patch: number = 0;
32
- static prerelease: string | null = 'rc.1';
32
+ static prerelease: string | null = 'rc.2';
33
33
 
34
34
  static getVersionString(): string {
35
35
  return `${this.major}.${this.minor}.${this.patch}${this.prerelease != null ? `-${this.prerelease}` : ''}`;
@@ -24,7 +24,7 @@ NSDictionary* RCTGetReactNativeVersion(void)
24
24
  RCTVersionMajor: @(0),
25
25
  RCTVersionMinor: @(88),
26
26
  RCTVersionPatch: @(0),
27
- RCTVersionPrerelease: @"rc.1",
27
+ RCTVersionPrerelease: @"rc.2",
28
28
  };
29
29
  });
30
30
  return __rnVersion;
@@ -23,7 +23,6 @@
23
23
  #import <RCTRequired/RCTRequired.h>
24
24
  #import <RCTTypeSafety/RCTConvertHelpers.h>
25
25
  #import <RCTTypeSafety/RCTTypedModuleConstants.h>
26
- #import <React/RCTArrayBuffer.h>
27
26
  #import <React/RCTBridgeModule.h>
28
27
  #import <React/RCTCxxConvert.h>
29
28
  #import <React/RCTManagedPointer.h>
@@ -1779,9 +1778,9 @@ namespace JS {
1779
1778
  - (NSDictionary *)getValue:(double)x
1780
1779
  y:(NSString *)y
1781
1780
  z:(NSDictionary *)z;
1782
- - (RCTArrayBuffer *)getArrayBuffer:(RCTArrayBuffer *)buffer;
1783
- - (RCTArrayBuffer *)createNativeBuffer:(double)size;
1784
- - (void)processAsyncBuffer:(RCTArrayBuffer *)payload
1781
+ - (NSMutableData *)getArrayBuffer:(NSMutableData *)buffer;
1782
+ - (NSMutableData *)createNativeBuffer:(double)size;
1783
+ - (void)processAsyncBuffer:(NSMutableData *)payload
1785
1784
  resolve:(RCTPromiseResolveBlock)resolve
1786
1785
  reject:(RCTPromiseRejectBlock)reject;
1787
1786
  - (void)getValueWithCallback:(RCTResponseSenderBlock)callback;
@@ -1,4 +1,4 @@
1
- VERSION_NAME=0.88.0-rc.1
1
+ VERSION_NAME=0.88.0-rc.2
2
2
  react.internal.publishingGroup=com.facebook.react
3
3
  react.internal.hermesPublishingGroup=com.facebook.hermes
4
4
 
@@ -15,6 +15,6 @@ public object ReactNativeVersion {
15
15
  "major" to 0,
16
16
  "minor" to 88,
17
17
  "patch" to 0,
18
- "prerelease" to "rc.1"
18
+ "prerelease" to "rc.2"
19
19
  )
20
20
  }
@@ -22,7 +22,7 @@ struct ReactNativeVersionType {
22
22
  int32_t Major = 0;
23
23
  int32_t Minor = 88;
24
24
  int32_t Patch = 0;
25
- std::string_view Prerelease = "rc.1";
25
+ std::string_view Prerelease = "rc.2";
26
26
  };
27
27
 
28
28
  constexpr ReactNativeVersionType ReactNativeVersion;
@@ -7,10 +7,8 @@
7
7
 
8
8
  #import <XCTest/XCTest.h>
9
9
 
10
- #import <React/RCTArrayBuffer.h>
11
10
  #import <ReactCommon/RCTTurboModule.h>
12
11
  #import <hermes/hermes.h>
13
- #import <jsi/decorator.h>
14
12
  #import <react/featureflags/ReactNativeFeatureFlags.h>
15
13
  #import <react/featureflags/ReactNativeFeatureFlagsDefaults.h>
16
14
 
@@ -94,39 +92,6 @@ class TestMutableBuffer : public facebook::jsi::MutableBuffer {
94
92
  std::vector<uint8_t> bytes_;
95
93
  };
96
94
 
97
- // `jsi::Runtime::tryGetMutableBuffer` is optional — the Hermes branch linked into apps returns
98
- // nullptr for every ArrayBuffer — so decorate the runtime to answer it for the buffers created
99
- // through it. That keeps the coverage of the native-backed path independent of the engine.
100
- // The registry is weak, so the only owners of a backing store remain the JS ArrayBuffer and
101
- // whatever the conversion retains.
102
- class MutableBufferAwareRuntime final : public facebook::jsi::RuntimeDecorator<facebook::jsi::Runtime> {
103
- public:
104
- explicit MutableBufferAwareRuntime(facebook::jsi::Runtime &plain) : RuntimeDecorator(plain) {}
105
-
106
- facebook::jsi::ArrayBuffer createArrayBuffer(std::shared_ptr<facebook::jsi::MutableBuffer> buffer) override
107
- {
108
- auto arrayBuffer = RuntimeDecorator::createArrayBuffer(buffer);
109
- buffers_.push_back(buffer);
110
- return arrayBuffer;
111
- }
112
-
113
- std::shared_ptr<facebook::jsi::MutableBuffer> tryGetMutableBuffer(
114
- const facebook::jsi::ArrayBuffer &arrayBuffer) override
115
- {
116
- uint8_t *data = arrayBuffer.data(*this);
117
- for (const auto &weakBuffer : buffers_) {
118
- auto buffer = weakBuffer.lock();
119
- if (buffer != nullptr && buffer->data() == data) {
120
- return buffer;
121
- }
122
- }
123
- return nullptr;
124
- }
125
-
126
- private:
127
- std::vector<std::weak_ptr<facebook::jsi::MutableBuffer>> buffers_;
128
- };
129
-
130
95
  class StubNativeMethodCallInvoker : public NativeMethodCallInvoker {
131
96
  public:
132
97
  void invokeAsync(const std::string &methodName, NativeMethodCallFunc &&func) noexcept override
@@ -354,46 +319,34 @@ class ExceptionCapturingNativeMethodCallInvoker : public NativeMethodCallInvoker
354
319
  XCTAssertNotNil(original.callStackSymbols);
355
320
  }
356
321
 
357
- // A native-backed ArrayBuffer is aliased rather than copied, and the RCTArrayBuffer retains
358
- // the backing MutableBuffer, so the alias outlives the JS object.
359
- - (void)testNativeBackedArrayBufferIsAliasedAndKeepsBackingStoreAlive
322
+ // A JS ArrayBuffer converts to an NSMutableData that owns an independent copy of
323
+ // the bytes — NSMutableData cannot alias a foreign buffer, so the result stays
324
+ // valid and is safe to mutate after the source buffer is gone. This covers the
325
+ // ArrayBuffer-backed-by-native-MutableBuffer case, which is the one that could in
326
+ // principle have been aliased zero-copy.
327
+ - (void)testArrayBufferConvertsToIndependentNSMutableData
360
328
  {
361
329
  constexpr size_t kBufferSize = 64 * 1024;
362
330
 
363
331
  auto hermesRuntime = facebook::hermes::makeHermesRuntime();
364
- MutableBufferAwareRuntime runtime(*hermesRuntime);
332
+ facebook::jsi::Runtime *rt = hermesRuntime.get();
365
333
 
366
334
  auto buffer = std::make_shared<TestMutableBuffer>(kBufferSize);
367
335
  *buffer->data() = 0xAB;
368
- const uint8_t *sourceBytes = buffer->data();
369
-
370
- RCTArrayBuffer *converted = nil;
371
- {
372
- facebook::jsi::ArrayBuffer arrayBuffer(runtime, buffer);
373
- const long ownersBeforeConversion = buffer.use_count();
374
-
375
- id result = TurboModuleConvertUtils::convertJSIValueToObjCObject(
376
- runtime, facebook::jsi::Value(runtime, arrayBuffer), nullptr, NO, NO);
377
- XCTAssertTrue([result isKindOfClass:[RCTArrayBuffer class]]);
378
- converted = (RCTArrayBuffer *)result;
379
-
380
- XCTAssertEqual(
381
- buffer.use_count(), ownersBeforeConversion + 1, @"The RCTArrayBuffer must retain the backing MutableBuffer");
382
- }
383
336
 
384
- XCTAssertTrue(converted.isOwningBytes, @"A native-backed buffer must be safe to retain");
385
- XCTAssertEqual(converted.length, (NSUInteger)kBufferSize);
386
- XCTAssertEqual(converted.mutableBytes, (void *)sourceBytes, @"Bytes must be aliased, not copied");
337
+ facebook::jsi::ArrayBuffer arrayBuffer(*rt, buffer);
338
+ id converted =
339
+ TurboModuleConvertUtils::convertJSIValueToObjCObject(*rt, facebook::jsi::Value(*rt, arrayBuffer), nullptr);
387
340
 
388
- // Writes through the source are visible, and vice versa: one shared allocation.
389
- *buffer->data() = 0xCD;
390
- XCTAssertEqual(*static_cast<const uint8_t *>(converted.mutableBytes), 0xCD);
391
- *static_cast<uint8_t *>(converted.mutableBytes) = 0xEF;
392
- XCTAssertEqual(*buffer->data(), 0xEF);
341
+ XCTAssertTrue([converted isKindOfClass:[NSMutableData class]]);
342
+ NSMutableData *data = (NSMutableData *)converted;
343
+ XCTAssertEqual(data.length, (NSUInteger)kBufferSize);
344
+ XCTAssertEqual(*static_cast<const uint8_t *>(data.bytes), 0xAB);
393
345
 
394
- // Dropping the caller's reference leaves the bytes valid.
395
- buffer.reset();
396
- XCTAssertEqual(*static_cast<const uint8_t *>(converted.mutableBytes), 0xEF);
346
+ // Independent copy: mutating the NSMutableData must not write through to the
347
+ // source MutableBuffer.
348
+ *static_cast<uint8_t *>(data.mutableBytes) = 0xCD;
349
+ XCTAssertEqual(*buffer->data(), 0xAB, @"NSMutableData must not alias the source buffer");
397
350
  }
398
351
 
399
352
  @end
@@ -75,8 +75,7 @@ class JSI_EXPORT ObjCInteropTurboModule : public ObjCTurboModule {
75
75
  const jsi::Value &arg,
76
76
  size_t i,
77
77
  NSInvocation *inv,
78
- NSMutableArray *retainedObjectsForInvocation,
79
- bool mustCopyBytes) override;
78
+ NSMutableArray *retainedObjectsForInvocation) override;
80
79
 
81
80
  private:
82
81
  std::vector<MethodDescriptor> methodDescriptors_;
@@ -363,8 +363,7 @@ void ObjCInteropTurboModule::setInvocationArg(
363
363
  const jsi::Value &jsiArg,
364
364
  size_t index,
365
365
  NSInvocation *inv,
366
- NSMutableArray *retainedObjectsForInvocation,
367
- [[maybe_unused]] bool mustCopyBytes)
366
+ NSMutableArray *retainedObjectsForInvocation)
368
367
  {
369
368
  NSString *methodName = @(methodNameCStr);
370
369
  std::string methodJsSignature = name_ + "." + methodNameCStr + "()";
@@ -35,8 +35,7 @@ id convertJSIValueToObjCObject(
35
35
  jsi::Runtime &runtime,
36
36
  const jsi::Value &value,
37
37
  const std::shared_ptr<CallInvoker> &jsInvoker,
38
- BOOL useNSNull = NO,
39
- BOOL mustCopyBytes = YES);
38
+ BOOL useNSNull = NO);
40
39
  } // namespace TurboModuleConvertUtils
41
40
 
42
41
  template <>
@@ -114,9 +113,6 @@ class JSI_EXPORT ObjCTurboModule : public TurboModule {
114
113
  * ObjCInteropTurboModule relies heavily on RCTConvert to convert arguments from JavaScript values to Objective C
115
114
  * values. ObjCTurboModule tries to minimize reliance on RCTConvert: RCTConvert uses the RCT_EXPORT_METHOD macros,
116
115
  * which we want to remove long term from React Native.
117
- *
118
- * mustCopyBytes says whether the invocation may outlive the JS call, in which case ArrayBuffer arguments must be
119
- * copied rather than aliased.
120
116
  */
121
117
  virtual void setInvocationArg(
122
118
  jsi::Runtime &runtime,
@@ -125,8 +121,7 @@ class JSI_EXPORT ObjCTurboModule : public TurboModule {
125
121
  const jsi::Value &arg,
126
122
  size_t i,
127
123
  NSInvocation *inv,
128
- NSMutableArray *retainedObjectsForInvocation,
129
- bool mustCopyBytes);
124
+ NSMutableArray *retainedObjectsForInvocation);
130
125
 
131
126
  private:
132
127
  // Does the NativeModule dispatch async methods to the JS thread?
@@ -142,13 +137,11 @@ class JSI_EXPORT ObjCTurboModule : public TurboModule {
142
137
  NSDictionary<NSString *, NSArray<NSString *> *> *methodArgumentTypeNames_;
143
138
 
144
139
  bool isMethodSync(TurboModuleMethodValueKind returnType);
145
- bool mustCopyJSHeapArrayBufferBytes(TurboModuleMethodValueKind returnType);
146
140
  BOOL hasMethodArgConversionSelector(NSString *methodName, size_t argIndex);
147
141
  SEL getMethodArgConversionSelector(NSString *methodName, size_t argIndex);
148
142
  NSInvocation *createMethodInvocation(
149
143
  jsi::Runtime &runtime,
150
144
  bool isSync,
151
- bool mustCopyBytes,
152
145
  const char *methodName,
153
146
  SEL selector,
154
147
  const jsi::Value *args,
@@ -7,7 +7,6 @@
7
7
 
8
8
  #import "RCTTurboModule.h"
9
9
 
10
- #import <React/RCTArrayBuffer.h>
11
10
  #import <React/RCTBridgeModule.h>
12
11
  #import <React/RCTConvert.h>
13
12
  #import <React/RCTCxxConvert.h>
@@ -90,43 +89,35 @@ static std::vector<jsi::Value> convertNSArrayToStdVector(jsi::Runtime &runtime,
90
89
  return result;
91
90
  }
92
91
 
93
- static jsi::ArrayBuffer convertRCTArrayBufferToJSIArrayBuffer(jsi::Runtime &runtime, RCTArrayBuffer *value)
92
+ static jsi::ArrayBuffer convertNSMutableDataToJSIArrayBuffer(jsi::Runtime &runtime, NSMutableData *value)
94
93
  {
95
- class RCTArrayBufferMutableBuffer final : public jsi::MutableBuffer {
94
+ class NSMutableDataBuffer final : public jsi::MutableBuffer {
96
95
  public:
97
- explicit RCTArrayBufferMutableBuffer(RCTArrayBuffer *buffer)
98
- : buffer_(buffer), data_(static_cast<uint8_t *>(buffer.mutableBytes)), size_(buffer.length)
99
- {
100
- }
96
+ explicit NSMutableDataBuffer(NSMutableData *data) : data_(data) {}
101
97
 
102
98
  size_t size() const override
103
99
  {
104
- return size_;
100
+ return data_.length;
105
101
  }
106
102
 
107
103
  uint8_t *data() override
108
104
  {
109
- return data_;
105
+ return static_cast<uint8_t *>(data_.mutableBytes);
110
106
  }
111
107
 
112
108
  private:
113
- // Never read: retains the buffer so `data_` stays valid for the ArrayBuffer's lifetime.
114
- [[maybe_unused]] RCTArrayBuffer *buffer_;
115
- uint8_t *data_;
116
- size_t size_;
109
+ NSMutableData *data_;
117
110
  };
118
111
 
119
- // nil would yield a NULL pointer via ObjC nil-messaging and corrupt the ArrayBuffer.
112
+ // A nil NSMutableData would silently yield a NULL `mutableBytes` pointer
113
+ // (ObjC nil-messaging) and corrupt the resulting ArrayBuffer. Substitute a
114
+ // fresh empty NSMutableData so the wrapped pointer is always well-defined.
120
115
  if (value == nil) {
121
- RCTLogWarn(@"convertRCTArrayBufferToJSIArrayBuffer: received nil RCTArrayBuffer; returning empty ArrayBuffer");
122
- value = [RCTArrayBuffer arrayBufferWithLength:0];
123
- }
124
-
125
- if (!value.isOwningBytes) {
126
- value = [RCTArrayBuffer arrayBufferWithCopiedBytes:value.mutableBytes length:value.length];
116
+ RCTLogWarn(@"convertNSMutableDataToJSIArrayBuffer: received nil NSMutableData; returning empty ArrayBuffer");
117
+ value = [NSMutableData data];
127
118
  }
128
-
129
- return {runtime, std::make_shared<RCTArrayBufferMutableBuffer>(value)};
119
+ auto buffer = std::make_shared<NSMutableDataBuffer>(value);
120
+ return {runtime, std::move(buffer)};
130
121
  }
131
122
 
132
123
  jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value)
@@ -142,8 +133,8 @@ jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value)
142
133
  return convertNSDictionaryToJSIObject(runtime, (NSDictionary *)value);
143
134
  } else if ([value isKindOfClass:[NSArray class]]) {
144
135
  return convertNSArrayToJSIArray(runtime, (NSArray *)value);
145
- } else if ([value isKindOfClass:[RCTArrayBuffer class]]) {
146
- return convertRCTArrayBufferToJSIArrayBuffer(runtime, (RCTArrayBuffer *)value);
136
+ } else if ([value isKindOfClass:[NSMutableData class]]) {
137
+ return convertNSMutableDataToJSIArrayBuffer(runtime, (NSMutableData *)value);
147
138
  } else if (value == (id)kCFNull) {
148
139
  return jsi::Value::null();
149
140
  }
@@ -210,41 +201,23 @@ convertJSIFunctionToCallback(jsi::Runtime &rt, jsi::Function &&function, const s
210
201
  };
211
202
  }
212
203
 
213
- // Native-backed buffers are aliased and keep their backing store alive, so they stay valid for
214
- // as long as the module holds them. JS-heap buffers have nothing to retain — their bytes are
215
- // freed when the ArrayBuffer is collected or detached — so `mustCopyBytes` is set whenever the
216
- // invocation may outlive the JS call, and they are aliased only when it cannot. Engines that
217
- // don't hand out the backing MutableBuffer fall back to those JS-heap rules for every buffer.
218
- static RCTArrayBuffer *
219
- convertJSIArrayBufferToRCTArrayBuffer(jsi::Runtime &rt, const jsi::ArrayBuffer &arrayBuffer, BOOL mustCopyBytes)
204
+ // Copy the ArrayBuffer's bytes into an NSMutableData. A zero-copy wrap is not
205
+ // possible here: NSMutableData needs its own resizable backing store and cannot
206
+ // alias a foreign buffer (even via initWithBytesNoCopy:length:deallocator:, which
207
+ // copies eagerly for the mutable subclass). Copying also makes the result safe to
208
+ // retain in a block, store, or dispatch to another thread, regardless of whether
209
+ // the bytes were owned by JS (valid only for this callstack) or by a native
210
+ // MutableBuffer (which the JS ArrayBuffer may GC concurrently).
211
+ static NSMutableData *convertJSIArrayBufferToNSMutableData(jsi::Runtime &rt, const jsi::ArrayBuffer &value)
220
212
  {
221
- if (auto nativeBuffer = arrayBuffer.tryGetMutableBuffer(rt)) {
222
- auto keepAlive = std::move(nativeBuffer);
223
- return [RCTArrayBuffer arrayBufferWithOwnedBytes:keepAlive->data()
224
- length:keepAlive->size()
225
- cleanup:^{
226
- (void)keepAlive;
227
- }];
228
- }
229
-
230
- void *bytes = arrayBuffer.data(rt);
231
- size_t size = arrayBuffer.size(rt);
232
-
233
- // The bytes belong to the JS heap -> async call.
234
- if (mustCopyBytes) {
235
- return [RCTArrayBuffer arrayBufferWithCopiedBytes:bytes length:size];
236
- }
237
-
238
- // The bytes belong to the JS heap -> sync call.
239
- return [RCTArrayBuffer arrayBufferWithUnownedBytes:bytes length:size];
213
+ return [NSMutableData dataWithBytes:value.data(rt) length:value.size(rt)];
240
214
  }
241
215
 
242
216
  id convertJSIValueToObjCObject(
243
217
  jsi::Runtime &runtime,
244
218
  const jsi::Value &value,
245
219
  const std::shared_ptr<CallInvoker> &jsInvoker,
246
- BOOL useNSNull,
247
- BOOL mustCopyBytes)
220
+ BOOL useNSNull)
248
221
  {
249
222
  if (value.isUndefined() || (value.isNull() && !useNSNull)) {
250
223
  return nil;
@@ -270,7 +243,7 @@ id convertJSIValueToObjCObject(
270
243
  return convertJSIFunctionToCallback(runtime, o.getFunction(runtime), jsInvoker);
271
244
  }
272
245
  if (o.isArrayBuffer(runtime)) {
273
- return convertJSIArrayBufferToRCTArrayBuffer(runtime, o.getArrayBuffer(runtime), mustCopyBytes);
246
+ return convertJSIArrayBufferToNSMutableData(runtime, o.getArrayBuffer(runtime));
274
247
  }
275
248
  return convertJSIObjectToNSDictionary(runtime, o, jsInvoker, useNSNull);
276
249
  }
@@ -629,11 +602,11 @@ jsi::Value ObjCTurboModule::convertReturnIdToJSIValue(
629
602
  break;
630
603
  }
631
604
  case ArrayBufferKind: {
632
- if (result != nil && ![result isKindOfClass:[RCTArrayBuffer class]]) {
633
- RCTLogError(@"convertReturnIdToJSIValue: expected RCTArrayBuffer for ArrayBufferKind, got %@", [result class]);
605
+ if (result != nil && ![result isKindOfClass:[NSMutableData class]]) {
606
+ RCTLogError(@"convertReturnIdToJSIValue: expected NSMutableData for ArrayBufferKind, got %@", [result class]);
634
607
  break;
635
608
  }
636
- returnValue = convertRCTArrayBufferToJSIArrayBuffer(runtime, (RCTArrayBuffer *)result);
609
+ returnValue = convertNSMutableDataToJSIArrayBuffer(runtime, (NSMutableData *)result);
637
610
  break;
638
611
  }
639
612
  case FunctionKind:
@@ -710,8 +683,7 @@ void ObjCTurboModule::setInvocationArg(
710
683
  const jsi::Value &arg,
711
684
  size_t i,
712
685
  NSInvocation *inv,
713
- NSMutableArray *retainedObjectsForInvocation,
714
- bool mustCopyBytes)
686
+ NSMutableArray *retainedObjectsForInvocation)
715
687
  {
716
688
  if (arg.isBool()) {
717
689
  bool v = arg.getBool();
@@ -754,15 +726,13 @@ void ObjCTurboModule::setInvocationArg(
754
726
  * Convert arg to ObjC objects.
755
727
  */
756
728
  BOOL enableModuleArgumentNSNullConversionIOS = ReactNativeFeatureFlags::enableModuleArgumentNSNullConversionIOS();
757
- id objCArg =
758
- convertJSIValueToObjCObject(runtime, arg, jsInvoker_, enableModuleArgumentNSNullConversionIOS, mustCopyBytes);
729
+ id objCArg = convertJSIValueToObjCObject(runtime, arg, jsInvoker_, enableModuleArgumentNSNullConversionIOS);
759
730
 
760
731
  // A JS `null` in argument position must reach ObjC as `nil`; only nulls nested inside arrays and
761
732
  // dictionaries are preserved as `kCFNull`. Skipping `setArgument:` leaves the slot zeroed.
762
733
  if (enableModuleArgumentNSNullConversionIOS && objCArg == (id)kCFNull) {
763
734
  return;
764
735
  }
765
-
766
736
  if (objCArg != nullptr) {
767
737
  NSString *methodNameNSString = @(methodName);
768
738
 
@@ -823,7 +793,6 @@ void ObjCTurboModule::setInvocationArg(
823
793
  NSInvocation *ObjCTurboModule::createMethodInvocation(
824
794
  jsi::Runtime &runtime,
825
795
  bool isSync,
826
- bool mustCopyBytes,
827
796
  const char *methodName,
828
797
  SEL selector,
829
798
  const jsi::Value *args,
@@ -852,7 +821,7 @@ NSInvocation *ObjCTurboModule::createMethodInvocation(
852
821
  for (size_t i = 0; i < count; i++) {
853
822
  const jsi::Value &arg = args[i];
854
823
  const std::string objCArgType = [methodSignature getArgumentTypeAtIndex:i + 2];
855
- setInvocationArg(runtime, methodName, objCArgType, arg, i, inv, retainedObjectsForInvocation, mustCopyBytes);
824
+ setInvocationArg(runtime, methodName, objCArgType, arg, i, inv, retainedObjectsForInvocation);
856
825
  }
857
826
 
858
827
  if (isSync) {
@@ -873,12 +842,6 @@ bool ObjCTurboModule::isMethodSync(TurboModuleMethodValueKind returnType)
873
842
  return returnType != VoidKind && returnType != PromiseKind;
874
843
  }
875
844
 
876
- bool ObjCTurboModule::mustCopyJSHeapArrayBufferBytes(TurboModuleMethodValueKind returnType)
877
- {
878
- // Void always dispatches via invokeAsync and promise may.
879
- return returnType == VoidKind || returnType == PromiseKind;
880
- }
881
-
882
845
  ObjCTurboModule::ObjCTurboModule(const InitParams &params)
883
846
  : TurboModule(params.moduleName, params.jsInvoker),
884
847
  instance_(params.instance),
@@ -899,7 +862,6 @@ jsi::Value ObjCTurboModule::invokeObjCMethod(
899
862
  const char *methodName = methodNameStr.c_str();
900
863
 
901
864
  bool isSyncInvocation = isMethodSync(returnType);
902
- bool mustCopyBytes = mustCopyJSHeapArrayBufferBytes(returnType);
903
865
 
904
866
  if (isSyncInvocation) {
905
867
  TurboModulePerfLogger::syncMethodCallStart(moduleName, methodName);
@@ -909,7 +871,7 @@ jsi::Value ObjCTurboModule::invokeObjCMethod(
909
871
 
910
872
  NSMutableArray *retainedObjectsForInvocation = [NSMutableArray arrayWithCapacity:count + 2];
911
873
  NSInvocation *inv = createMethodInvocation(
912
- runtime, isSyncInvocation, mustCopyBytes, methodName, selector, args, count, retainedObjectsForInvocation);
874
+ runtime, isSyncInvocation, methodName, selector, args, count, retainedObjectsForInvocation);
913
875
 
914
876
  jsi::Value returnValue = jsi::Value::undefined();
915
877
 
@@ -6,8 +6,6 @@
6
6
  */
7
7
 
8
8
  #import "RCTSampleTurboModule.h"
9
-
10
- #import <React/RCTArrayBuffer.h>
11
9
  #import "RCTSampleTurboModulePlugin.h"
12
10
 
13
11
  #import <React/RCTAssert.h>
@@ -16,8 +14,6 @@
16
14
  #import <ReactCommon/RCTTurboModuleWithJSIBindings.h>
17
15
  #import <UIKit/UIKit.h>
18
16
 
19
- #include <span>
20
-
21
17
  using namespace facebook::react;
22
18
 
23
19
  @interface RCTSampleTurboModule () <RCTTurboModuleWithJSIBindings, RCTInitializing>
@@ -149,27 +145,20 @@ RCT_EXPORT_MODULE()
149
145
  };
150
146
  }
151
147
 
152
- // The argument aliases the JS ArrayBuffer's bytes, so mutating in place is visible to JS.
153
- - (RCTArrayBuffer *)getArrayBuffer:(RCTArrayBuffer *)buffer
148
+ // Arguments arrive as an immutable NSData, but an ArrayBuffer return must be
149
+ // NSMutableData: it is handed to JS as a jsi::MutableBuffer, whose data() is
150
+ // non-const. Echoing the argument back therefore needs a mutable copy.
151
+ - (NSMutableData *)getArrayBuffer:(NSData *)buffer
154
152
  {
155
- auto *bytes = static_cast<uint8_t *>(buffer.mutableBytes);
156
- if (bytes == nullptr) {
157
- return buffer;
158
- }
159
-
160
- std::span<uint8_t> byteSpan(bytes, static_cast<size_t>(buffer.length));
161
- for (auto &byte : byteSpan) {
162
- byte = static_cast<uint8_t>(byte * 2);
163
- }
164
- return buffer;
153
+ return [buffer mutableCopy];
165
154
  }
166
155
 
167
- - (RCTArrayBuffer *)createNativeBuffer:(double)size
156
+ - (NSMutableData *)createNativeBuffer:(double)size
168
157
  {
169
- return [RCTArrayBuffer arrayBufferWithLength:(NSUInteger)size];
158
+ return [NSMutableData dataWithLength:(NSUInteger)size];
170
159
  }
171
160
 
172
- - (void)processAsyncBuffer:(RCTArrayBuffer *)payload
161
+ - (void)processAsyncBuffer:(NSData *)payload
173
162
  resolve:(RCTPromiseResolveBlock)resolve
174
163
  reject:(RCTPromiseRejectBlock)reject
175
164
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native",
3
- "version": "0.88.0-rc.1",
3
+ "version": "0.88.0-rc.2",
4
4
  "description": "A framework for building native apps using React",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -34,7 +34,10 @@
34
34
  "default": "./index.js"
35
35
  },
36
36
  "./Libraries/*": {
37
- "react-native-legacy-deep-imports": "./types_DEPRECATED/Libraries/*.d.ts",
37
+ "react-native-legacy-deep-imports": [
38
+ "./types_DEPRECATED/Libraries/*.d.ts",
39
+ "./Libraries/*.d.ts"
40
+ ],
38
41
  "types": null,
39
42
  "default": "./Libraries/*.js"
40
43
  },
@@ -151,12 +154,12 @@
151
154
  }
152
155
  },
153
156
  "dependencies": {
154
- "@react-native/asset-utils": "0.88.0-rc.1",
155
- "@react-native/codegen": "0.88.0-rc.1",
156
- "@react-native/community-cli-plugin": "0.88.0-rc.1",
157
- "@react-native/gradle-plugin": "0.88.0-rc.1",
158
- "@react-native/normalize-colors": "0.88.0-rc.1",
159
- "@react-native/virtualized-lists": "0.88.0-rc.1",
157
+ "@react-native/asset-utils": "0.88.0-rc.2",
158
+ "@react-native/codegen": "0.88.0-rc.2",
159
+ "@react-native/community-cli-plugin": "0.88.0-rc.2",
160
+ "@react-native/gradle-plugin": "0.88.0-rc.2",
161
+ "@react-native/normalize-colors": "0.88.0-rc.2",
162
+ "@react-native/virtualized-lists": "0.88.0-rc.2",
160
163
  "anser": "^1.4.9",
161
164
  "ansi-regex": "^5.0.0",
162
165
  "flow-parser": "0.327.0",
@@ -165,8 +168,8 @@
165
168
  "hermes-compiler": "260318099.0.3",
166
169
  "invariant": "^2.2.4",
167
170
  "memoize-one": "^5.0.0",
168
- "metro-runtime": "^0.87.0",
169
- "metro-source-map": "^0.87.0",
171
+ "metro-runtime": "^0.87.1",
172
+ "metro-source-map": "^0.87.1",
170
173
  "nullthrows": "^1.1.1",
171
174
  "pretty-format": "^29.7.0",
172
175
  "promise": "^8.3.0",
@@ -1,64 +0,0 @@
1
- /*
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
- #import <Foundation/Foundation.h>
9
-
10
- NS_ASSUME_NONNULL_BEGIN
11
-
12
- /**
13
- * A fixed-length byte buffer shared between JS `ArrayBuffer`s and ObjC TurboModules. Fixed
14
- * length lets the backing store alias JS memory; `NSMutableData` cannot do that.
15
- *
16
- * `isOwningBytes`:
17
- * - `YES` — safe to retain and use from any thread (synchronize if aliasing JS
18
- * memory).
19
- * - `NO` — valid only during the synchronous call on the calling thread; copy with
20
- * `arrayBufferWithCopiedBytes:length:` to keep the bytes.
21
- */
22
- @interface RCTArrayBuffer : NSObject
23
-
24
- /**
25
- * NULL when `length` is 0, non-NULL otherwise, matching `NSData.bytes`.
26
- */
27
- @property (nonatomic, readonly, nullable) void *mutableBytes NS_RETURNS_INNER_POINTER;
28
-
29
- @property (nonatomic, readonly) NSUInteger length;
30
-
31
- /** Whether the buffer owns its bytes. See the class comment. */
32
- @property (nonatomic, readonly, getter=isOwningBytes) BOOL owningBytes;
33
-
34
- /**
35
- * A new zero-filled owning buffer.
36
- */
37
- + (instancetype)arrayBufferWithLength:(NSUInteger)length;
38
-
39
- /**
40
- * A new owning buffer holding a copy of `bytes`. Passing NULL zero-fills.
41
- */
42
- + (instancetype)arrayBufferWithCopiedBytes:(const void *_Nullable)bytes length:(NSUInteger)length;
43
-
44
- /**
45
- * An owning buffer aliasing `bytes` without copying. If `cleanup` is non-nil, it runs on dealloc,
46
- * like `-[NSData dataWithBytesNoCopy:length:freeWhenDone:YES]`; if nil, the caller must keep
47
- * `bytes` valid until dealloc. NULL `bytes` with non-zero `length` raises NSInvalidArgumentException.
48
- */
49
- + (instancetype)arrayBufferWithOwnedBytes:(nullable void *)bytes
50
- length:(NSUInteger)length
51
- cleanup:(nullable void (^)(void))cleanup;
52
-
53
- /**
54
- * A non-owning, zero-copy alias of `bytes`. See the class comment for lifetime rules. NULL `bytes`
55
- * with non-zero `length` raises NSInvalidArgumentException.
56
- */
57
- + (instancetype)arrayBufferWithUnownedBytes:(nullable void *)bytes length:(NSUInteger)length;
58
-
59
- - (instancetype)init NS_UNAVAILABLE;
60
- + (instancetype)new NS_UNAVAILABLE;
61
-
62
- @end
63
-
64
- NS_ASSUME_NONNULL_END
@@ -1,127 +0,0 @@
1
- /*
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
- #import "RCTArrayBuffer.h"
9
-
10
- #include <cstdint>
11
- #include <cstring>
12
- #include <utility>
13
- #include <vector>
14
-
15
- @interface RCTArrayBuffer ()
16
-
17
- - (instancetype)initWithBytesNoCopy:(nullable void *)bytes
18
- length:(NSUInteger)length
19
- owningBytes:(BOOL)owningBytes
20
- cleanup:(nullable void (^)(void))cleanup NS_DESIGNATED_INITIALIZER;
21
- - (instancetype)initWithCopiedBytes:(const void *_Nullable)bytes length:(NSUInteger)length;
22
-
23
- @end
24
-
25
- @implementation RCTArrayBuffer {
26
- void *_bytes;
27
- NSUInteger _length;
28
- BOOL _owningBytes;
29
- void (^_cleanup)(void);
30
- std::vector<uint8_t> _copiedBytes;
31
- }
32
-
33
- #pragma mark - Initializers
34
-
35
- - (instancetype)initWithBytesNoCopy:(void *)bytes
36
- length:(NSUInteger)length
37
- owningBytes:(BOOL)owningBytes
38
- cleanup:(void (^)(void))cleanup
39
- {
40
- if (bytes == NULL && length != 0) {
41
- [NSException raise:NSInvalidArgumentException
42
- format:@"RCTArrayBuffer: NULL bytes with length %lu", (unsigned long)length];
43
- }
44
-
45
- if (self = [super init]) {
46
- _bytes = bytes;
47
- _length = length;
48
- _owningBytes = owningBytes;
49
- _cleanup = [cleanup copy];
50
- }
51
- return self;
52
- }
53
-
54
- - (instancetype)initWithCopiedBytes:(const void *)bytes length:(NSUInteger)length
55
- {
56
- if (length == 0) {
57
- return [self initWithBytesNoCopy:NULL length:0 owningBytes:YES cleanup:nil];
58
- }
59
-
60
- std::vector<uint8_t> copy(length);
61
- if (bytes != NULL) {
62
- std::memcpy(copy.data(), bytes, length);
63
- }
64
-
65
- // Moving a vector hands over its heap buffer, so `data()` stays valid in `_copiedBytes`.
66
- if (self = [self initWithBytesNoCopy:copy.data() length:length owningBytes:YES cleanup:nil]) {
67
- _copiedBytes = std::move(copy);
68
- }
69
- return self;
70
- }
71
-
72
- + (instancetype)arrayBufferWithLength:(NSUInteger)length
73
- {
74
- return [[self alloc] initWithCopiedBytes:NULL length:length];
75
- }
76
-
77
- + (instancetype)arrayBufferWithCopiedBytes:(const void *)bytes length:(NSUInteger)length
78
- {
79
- return [[self alloc] initWithCopiedBytes:bytes length:length];
80
- }
81
-
82
- + (instancetype)arrayBufferWithOwnedBytes:(void *)bytes
83
- length:(NSUInteger)length
84
- cleanup:(nullable void (^)(void))cleanup
85
- {
86
- return [[self alloc] initWithBytesNoCopy:bytes length:length owningBytes:YES cleanup:cleanup];
87
- }
88
-
89
- + (instancetype)arrayBufferWithUnownedBytes:(void *)bytes length:(NSUInteger)length
90
- {
91
- return [[self alloc] initWithBytesNoCopy:bytes length:length owningBytes:NO cleanup:nil];
92
- }
93
-
94
- #pragma mark - Accessors
95
-
96
- - (void *)mutableBytes
97
- {
98
- return _bytes;
99
- }
100
-
101
- - (NSUInteger)length
102
- {
103
- return _length;
104
- }
105
-
106
- - (BOOL)isOwningBytes
107
- {
108
- return _owningBytes;
109
- }
110
-
111
- - (NSString *)description
112
- {
113
- return [NSString stringWithFormat:@"<%@: %p; length = %lu; owningBytes = %@>",
114
- NSStringFromClass([self class]),
115
- self,
116
- (unsigned long)_length,
117
- _owningBytes ? @"YES" : @"NO"];
118
- }
119
-
120
- - (void)dealloc
121
- {
122
- if (_cleanup != nil) {
123
- _cleanup();
124
- }
125
- }
126
-
127
- @end