Skip to content

Commit 7c01181

Browse files
authored
Use associated objects to attach contiguous array buffers to lazy ones (#75148)
rdar://132124808
1 parent 4548fb6 commit 7c01181

File tree

7 files changed

+139
-4
lines changed

7 files changed

+139
-4
lines changed

stdlib/public/SwiftShims/swift/shims/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ set(sources
99
LibcOverlayShims.h
1010
LibcShims.h
1111
MetadataSections.h
12+
ObjCShims.h
1213
Random.h
1314
RefCount.h
1415
Reflection.h

stdlib/public/SwiftShims/swift/shims/CoreFoundationShims.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@ extern "C" {
3030
#if __LLP64__
3131
typedef unsigned long long _swift_shims_CFHashCode;
3232
typedef signed long long _swift_shims_CFIndex;
33+
3334
#else
3435
typedef unsigned long _swift_shims_CFHashCode;
3536
typedef signed long _swift_shims_CFIndex;
37+
3638
#endif
3739

3840
// Consider creating SwiftMacTypes.h for these
@@ -74,7 +76,7 @@ _swift_stdlib_NSStringGetCStringTrampoline(id _Nonnull obj,
7476
SWIFT_RUNTIME_STDLIB_API
7577
__swift_uint8_t
7678
_swift_stdlib_dyld_is_objc_constant_string(const void * _Nonnull addr);
77-
79+
7880
#endif // __OBJC2__
7981

8082
#ifdef __cplusplus
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//===--- ObjCShims.h - Access to libobjc for the core stdlib ---------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Using the ObjectiveC module in the core stdlib would create a
14+
// circular dependency, so instead we import these declarations as
15+
// part of SwiftShims.
16+
//
17+
//===----------------------------------------------------------------------===//
18+
19+
#ifndef SWIFT_STDLIB_SHIMS_OBJCSHIMS_H
20+
#define SWIFT_STDLIB_SHIMS_OBJCSHIMS_H
21+
22+
#include "SwiftStdint.h"
23+
#include "Visibility.h"
24+
25+
#ifdef __cplusplus
26+
extern "C" {
27+
#endif
28+
29+
#ifdef __OBJC2__
30+
31+
extern void objc_setAssociatedObject(void);
32+
extern void objc_getAssociatedObject(void);
33+
int objc_sync_enter(id _Nonnull object);
34+
int objc_sync_exit(id _Nonnull object);
35+
36+
static void * _Nonnull getSetAssociatedObjectPtr() {
37+
return (void *)&objc_setAssociatedObject;
38+
}
39+
40+
static void * _Nonnull getGetAssociatedObjectPtr() {
41+
return (void *)&objc_getAssociatedObject;
42+
}
43+
44+
#endif // __OBJC2__
45+
46+
#ifdef __cplusplus
47+
} // extern "C"
48+
#endif
49+
50+
#endif // SWIFT_STDLIB_SHIMS_COREFOUNDATIONSHIMS_H
51+

stdlib/public/SwiftShims/swift/shims/module.modulemap

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module SwiftShims {
22
header "AssertionReporting.h"
33
header "CoreFoundationShims.h"
4+
header "ObjCShims.h"
45
header "EmbeddedShims.h"
56
header "FoundationShims.h"
67
header "GlobalObjects.h"

stdlib/public/core/ArrayBuffer.swift

+76-1
Original file line numberDiff line numberDiff line change
@@ -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`

stdlib/public/core/CocoaArray.swift

+6-2
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,16 @@ internal struct _CocoaArrayWrapper: RandomAccessCollection {
5151

5252
@usableFromInline
5353
internal var endIndex: Int {
54-
return core.count
54+
@_effects(releasenone) get {
55+
core.count
56+
}
5557
}
5658

5759
@usableFromInline
5860
internal subscript(i: Int) -> AnyObject {
59-
return core.objectAt(i)
61+
@_effects(releasenone) get {
62+
core.objectAt(i)
63+
}
6064
}
6165

6266
@usableFromInline

stdlib/public/stubs/FoundationHelpers.mm

+1
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,6 @@ typedef __swift_uint8_t (*getCStringImplPtr)(id,
112112
&& SWIFT_RUNTIME_WEAK_USE(_dyld_is_objc_constant(dyld_objc_string_kind, addr))) ? 1 : 0;
113113
}
114114

115+
115116
#endif
116117

0 commit comments

Comments
 (0)