@@ -567,6 +567,84 @@ extension _ArrayBuffer {
567
567
}
568
568
}
569
569
570
+ @inlinable @_alwaysEmitIntoClient
571
+ static var associationKey : UnsafeRawPointer {
572
+ //We never dereference this, we just need an address to use as a unique key
573
+ UnsafeRawPointer ( Builtin . addressof ( & _swiftEmptyArrayStorage) )
574
+ }
575
+
576
+ @inlinable @_alwaysEmitIntoClient
577
+ internal func getAssociatedBuffer( ) -> _ContiguousArrayBuffer < Element > ? {
578
+ let getter = unsafeBitCast (
579
+ getGetAssociatedObjectPtr ( ) ,
580
+ to: ( @convention( c) (
581
+ AnyObject,
582
+ UnsafeRawPointer
583
+ ) - > UnsafeRawPointer? ) . self
584
+ )
585
+ if let assocPtr = getter (
586
+ _storage. objCInstance,
587
+ _ArrayBuffer. associationKey
588
+ ) {
589
+ let buffer = assocPtr. loadUnaligned (
590
+ as: _ContiguousArrayStorage< Element> . self
591
+ )
592
+ return _ContiguousArrayBuffer ( buffer)
593
+ }
594
+ return nil
595
+ }
596
+
597
+ @inlinable @_alwaysEmitIntoClient
598
+ internal func setAssociatedBuffer( _ buffer: _ContiguousArrayBuffer < Element > ) {
599
+ let setter = unsafeBitCast ( getSetAssociatedObjectPtr ( ) , to: ( @convention( c) (
600
+ AnyObject,
601
+ UnsafeRawPointer,
602
+ AnyObject? ,
603
+ UInt
604
+ ) - > Void) . self)
605
+ setter (
606
+ _storage. objCInstance,
607
+ _ArrayBuffer. associationKey,
608
+ buffer. _storage,
609
+ 1 //OBJC_ASSOCIATION_RETAIN_NONATOMIC
610
+ )
611
+ }
612
+
613
+ @_alwaysEmitIntoClient @inline ( never)
614
+ internal func withUnsafeBufferPointer_nonNative< R, E> (
615
+ _ body: ( UnsafeBufferPointer < Element > ) throws ( E ) -> R
616
+ ) throws ( E) -> R {
617
+ let unwrapped : _ContiguousArrayBuffer < Element >
618
+ // libobjc already provides the necessary memory barriers for
619
+ // double checked locking to be safe, per comments on
620
+ // https://github.com/swiftlang/swift/pull/75148
621
+ if let associatedBuffer = getAssociatedBuffer ( ) {
622
+ unwrapped = associatedBuffer
623
+ } else {
624
+ let lock = _storage. objCInstance
625
+ objc_sync_enter ( lock)
626
+ var associatedBuffer = getAssociatedBuffer ( )
627
+ if let associatedBuffer {
628
+ unwrapped = associatedBuffer
629
+ } else {
630
+ associatedBuffer = ContiguousArray ( self ) . _buffer
631
+ unwrapped = associatedBuffer. unsafelyUnwrapped
632
+ setAssociatedBuffer ( unwrapped)
633
+ }
634
+ defer { _fixLifetime ( unwrapped) }
635
+ objc_sync_exit ( lock)
636
+ }
637
+ return try body (
638
+ UnsafeBufferPointer (
639
+ start: unwrapped. firstElementAddress,
640
+ count: unwrapped. count
641
+ )
642
+ )
643
+ }
644
+
645
+ /// Call `body(p)`, where `p` is an `UnsafeBufferPointer` over the
646
+ /// underlying contiguous storage. If no such storage exists, it is
647
+ /// created on-demand.
570
648
// Superseded by the typed-throws version of this function, but retained
571
649
// for ABI reasons.
572
650
@usableFromInline
@@ -594,7 +672,7 @@ extension _ArrayBuffer {
594
672
return try body (
595
673
UnsafeBufferPointer ( start: firstElementAddress, count: count) )
596
674
}
597
- return try ContiguousArray ( self ) . withUnsafeBufferPointer ( body)
675
+ return try withUnsafeBufferPointer_nonNative ( body)
598
676
}
599
677
600
678
// Superseded by the typed-throws version of this function, but retained
0 commit comments