@@ -567,6 +567,81 @@ 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> (
615
+ _ body: ( UnsafeBufferPointer < Element > ) throws -> R
616
+ ) rethrows -> 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
+
570
645
/// Call `body(p)`, where `p` is an `UnsafeBufferPointer` over the
571
646
/// underlying contiguous storage. If no such storage exists, it is
572
647
/// created on-demand.
@@ -579,7 +654,7 @@ extension _ArrayBuffer {
579
654
return try body (
580
655
UnsafeBufferPointer ( start: firstElementAddress, count: count) )
581
656
}
582
- return try ContiguousArray ( self ) . withUnsafeBufferPointer ( body)
657
+ return try withUnsafeBufferPointer_nonNative ( body)
583
658
}
584
659
585
660
/// Call `body(p)`, where `p` is an `UnsafeMutableBufferPointer`
0 commit comments