@@ -567,6 +567,81 @@ extension _ArrayBuffer {
567567 }
568568 }
569569
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+
570645 /// Call `body(p)`, where `p` is an `UnsafeBufferPointer` over the
571646 /// underlying contiguous storage. If no such storage exists, it is
572647 /// created on-demand.
@@ -579,7 +654,7 @@ extension _ArrayBuffer {
579654 return try body (
580655 UnsafeBufferPointer ( start: firstElementAddress, count: count) )
581656 }
582- return try ContiguousArray ( self ) . withUnsafeBufferPointer ( body)
657+ return try withUnsafeBufferPointer_nonNative ( body)
583658 }
584659
585660 /// Call `body(p)`, where `p` is an `UnsafeMutableBufferPointer`
0 commit comments