Skip to content

Commit 295b6ac

Browse files
authored
Merge pull request #62226 from eeckstein/read-only-static-arrays
IRGen: fix and re-enable static read-only arrays
2 parents 2775262 + e4ea749 commit 295b6ac

File tree

13 files changed

+240
-39
lines changed

13 files changed

+240
-39
lines changed

include/swift/AST/ASTContext.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -949,9 +949,9 @@ class ASTContext final {
949949
/// for extended existential types.
950950
AvailabilityContext getParameterizedExistentialRuntimeAvailability();
951951

952-
/// Get the runtime availability of immortal ref-count symbols, which are
953-
/// needed to place array buffers into constant data sections.
954-
AvailabilityContext getImmortalRefCountSymbolsAvailability();
952+
/// Get the runtime availability of array buffers placed in constant data
953+
/// sections.
954+
AvailabilityContext getStaticReadOnlyArraysAvailability();
955955

956956
/// Get the runtime availability of runtime functions for
957957
/// variadic generic types.

lib/AST/Availability.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -567,10 +567,8 @@ ASTContext::getParameterizedExistentialRuntimeAvailability() {
567567
}
568568

569569
AvailabilityContext
570-
ASTContext::getImmortalRefCountSymbolsAvailability() {
571-
// TODO: replace this with a concrete swift version once we have it.
572-
// rdar://94185998
573-
return getSwiftFutureAvailability();
570+
ASTContext::getStaticReadOnlyArraysAvailability() {
571+
return getSwift511Availability();
574572
}
575573

576574
AvailabilityContext

lib/IRGen/GenConstant.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -438,13 +438,10 @@ llvm::Constant *irgen::emitConstantObject(IRGenModule &IGM, ObjectInst *OI,
438438
IGM.swiftImmortalRefCount = var;
439439
}
440440
if (!IGM.swiftStaticArrayMetadata) {
441-
442-
// Static arrays can only contain trivial elements. Therefore we can reuse
443-
// the metadata of the empty array buffer. The important thing is that its
444-
// deinit is a no-op and does not actually destroy any elements.
441+
// type metadata for class __StaticArrayStorage
445442
auto *var = new llvm::GlobalVariable(IGM.Module, IGM.TypeMetadataStructTy,
446443
/*constant*/ true, llvm::GlobalValue::ExternalLinkage,
447-
/*initializer*/ nullptr, "$ss19__EmptyArrayStorageCN");
444+
/*initializer*/ nullptr, "$ss20__StaticArrayStorageCN");
448445
IGM.swiftStaticArrayMetadata = var;
449446
}
450447
elements[0].add(llvm::ConstantStruct::get(ObjectHeaderTy, {

lib/IRGen/IRGenModule.cpp

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2038,13 +2038,6 @@ bool IRGenModule::canUseObjCSymbolicReferences() {
20382038
}
20392039

20402040
bool IRGenModule::canMakeStaticObjectsReadOnly() {
2041-
// Unconditionally disable this until we can fix the metadata.
2042-
// The trick of using the Empty array metadata for static arrays
2043-
// breaks Obj-C interop quite badly.
2044-
// rdar://101126543
2045-
return false;
2046-
2047-
#if 0
20482041
if (getOptions().DisableReadonlyStaticObjects)
20492042
return false;
20502043

@@ -2054,8 +2047,7 @@ bool IRGenModule::canMakeStaticObjectsReadOnly() {
20542047
return false;
20552048

20562049
return getAvailabilityContext().isContainedIn(
2057-
Context.getImmortalRefCountSymbolsAvailability());
2058-
#endif
2050+
Context.getStaticReadOnlyArraysAvailability());
20592051
}
20602052

20612053
void IRGenerator::addGenModule(SourceFile *SF, IRGenModule *IGM) {

stdlib/public/core/ContiguousArrayBuffer.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,49 @@ public var _swiftEmptyArrayStorage: (Int, Int, Int, Int) =
6868
(/*isa*/0, /*refcount*/-1, /*count*/0, /*flags*/1)
6969
#endif
7070

71+
/// The storage for static read-only arrays.
72+
///
73+
/// In contrast to `_ContiguousArrayStorage` this class is _not_ generic over
74+
/// the element type, because the metatype for static read-only arrays cannot
75+
/// be instantiated at runtime.
76+
///
77+
/// Static read-only arrays can only contain non-verbatim bridged element types.
78+
@_fixed_layout
79+
@usableFromInline
80+
@_objc_non_lazy_realization
81+
internal final class __StaticArrayStorage
82+
: __ContiguousArrayStorageBase {
83+
84+
@inlinable
85+
@nonobjc
86+
internal init(_doNotCallMe: ()) {
87+
_internalInvariantFailure("creating instance of __StaticArrayStorage")
88+
}
89+
90+
#if _runtime(_ObjC)
91+
override internal func _withVerbatimBridgedUnsafeBuffer<R>(
92+
_ body: (UnsafeBufferPointer<AnyObject>) throws -> R
93+
) rethrows -> R? {
94+
return nil
95+
}
96+
97+
override internal func _getNonVerbatimBridgingBuffer() -> _BridgingBuffer {
98+
fatalError("__StaticArrayStorage._withVerbatimBridgedUnsafeBuffer must not be called")
99+
}
100+
#endif
101+
102+
@inlinable
103+
override internal func canStoreElements(ofDynamicType _: Any.Type) -> Bool {
104+
return false
105+
}
106+
107+
@inlinable
108+
@_unavailableInEmbedded
109+
override internal var staticElementType: Any.Type {
110+
fatalError("__StaticArrayStorage.staticElementType must not be called")
111+
}
112+
}
113+
71114
/// The empty array prototype. We use the same object for all empty
72115
/// `[Native]Array<Element>`s.
73116
@inlinable
@@ -849,6 +892,9 @@ internal struct _ContiguousArrayBuffer<Element>: _ArrayBufferProtocol {
849892
}
850893
return _storage
851894
}
895+
if _storage is __StaticArrayStorage {
896+
return __SwiftDeferredStaticNSArray<Element>(_nativeStorage: _storage)
897+
}
852898
return __SwiftDeferredNSArray(_nativeStorage: _storage)
853899
}
854900
#endif

stdlib/public/core/SwiftNativeNSArray.swift

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -329,29 +329,29 @@ extension __SwiftNativeNSArrayWithContiguousStorage {
329329
/// buffers used for Array storage.
330330
@_fixed_layout // FIXME(sil-serialize-all)
331331
@usableFromInline
332-
@objc internal final class __SwiftDeferredNSArray
332+
@objc internal class __SwiftDeferredNSArray
333333
: __SwiftNativeNSArrayWithContiguousStorage {
334334

335335
// This stored property should be stored at offset zero. We perform atomic
336336
// operations on it.
337337
//
338338
// Do not access this property directly.
339339
@nonobjc
340-
internal var _heapBufferBridged_DoNotUse: AnyObject?
340+
internal final var _heapBufferBridged_DoNotUse: AnyObject?
341341

342342
// When this class is allocated inline, this property can become a
343343
// computed one.
344344
@usableFromInline
345345
@nonobjc
346-
internal let _nativeStorage: __ContiguousArrayStorageBase
346+
internal final let _nativeStorage: __ContiguousArrayStorageBase
347347

348348
@nonobjc
349-
internal var _heapBufferBridgedPtr: UnsafeMutablePointer<AnyObject?> {
349+
internal final var _heapBufferBridgedPtr: UnsafeMutablePointer<AnyObject?> {
350350
return _getUnsafePointerToStoredProperties(self).assumingMemoryBound(
351351
to: Optional<AnyObject>.self)
352352
}
353353

354-
internal var _heapBufferBridged: __BridgingBufferStorage? {
354+
internal final var _heapBufferBridged: __BridgingBufferStorage? {
355355
if let ref =
356356
_stdlib_atomicLoadARCRef(object: _heapBufferBridgedPtr) {
357357
return unsafeBitCast(ref, to: __BridgingBufferStorage.self)
@@ -365,7 +365,7 @@ extension __SwiftNativeNSArrayWithContiguousStorage {
365365
self._nativeStorage = _nativeStorage
366366
}
367367

368-
internal func _destroyBridgedStorage(_ hb: __BridgingBufferStorage?) {
368+
internal final func _destroyBridgedStorage(_ hb: __BridgingBufferStorage?) {
369369
if let bridgedStorage = hb {
370370
withExtendedLifetime(bridgedStorage) {
371371
let buffer = _BridgingBuffer(bridgedStorage)
@@ -424,10 +424,71 @@ extension __SwiftNativeNSArrayWithContiguousStorage {
424424
/// This override allows the count to be read without triggering
425425
/// bridging of array elements.
426426
@objc
427-
internal override var count: Int {
427+
internal override final var count: Int {
428428
return _nativeStorage.countAndCapacity.count
429429
}
430430
}
431+
432+
/// A `__SwiftDeferredNSArray` which is used for static read-only Swift Arrays.
433+
///
434+
/// In contrast to its base class, `__SwiftDeferredStaticNSArray` is generic
435+
/// over the element type. This is needed because the storage class of a static
436+
/// read-only array (`__StaticArrayStorage`) does _not_ provide the element
437+
/// type.
438+
internal final class __SwiftDeferredStaticNSArray<Element>
439+
: __SwiftDeferredNSArray {
440+
441+
internal override func withUnsafeBufferOfObjects<R>(
442+
_ body: (UnsafeBufferPointer<AnyObject>) throws -> R
443+
) rethrows -> R {
444+
while true {
445+
var buffer: UnsafeBufferPointer<AnyObject>
446+
447+
// If we've already got a buffer of bridged objects, just use it
448+
if let bridgedStorage = _heapBufferBridged {
449+
let bridgingBuffer = _BridgingBuffer(bridgedStorage)
450+
buffer = UnsafeBufferPointer(
451+
start: bridgingBuffer.baseAddress, count: bridgingBuffer.count)
452+
}
453+
else {
454+
// Static read-only arrays can only contain non-verbatim bridged
455+
// element types.
456+
457+
// Create buffer of bridged objects.
458+
let objects = getNonVerbatimBridgingBuffer()
459+
460+
// Atomically store a reference to that buffer in self.
461+
if !_stdlib_atomicInitializeARCRef(
462+
object: _heapBufferBridgedPtr, desired: objects.storage!) {
463+
464+
// Another thread won the race. Throw out our buffer.
465+
_destroyBridgedStorage(
466+
unsafeDowncast(objects.storage!, to: __BridgingBufferStorage.self))
467+
}
468+
continue // Try again
469+
}
470+
471+
defer { _fixLifetime(self) }
472+
return try body(buffer)
473+
}
474+
}
475+
476+
internal func getNonVerbatimBridgingBuffer() -> _BridgingBuffer {
477+
_internalInvariant(
478+
!_isBridgedVerbatimToObjectiveC(Element.self),
479+
"Verbatim bridging should be handled separately")
480+
let count = _nativeStorage.countAndCapacity.count
481+
let result = _BridgingBuffer(count)
482+
let resultPtr = result.baseAddress
483+
let p = UnsafeMutablePointer<Element>(Builtin.projectTailElems(_nativeStorage, Element.self))
484+
for i in 0..<count {
485+
(resultPtr + i).initialize(to: _bridgeAnythingToObjectiveC(p[i]))
486+
}
487+
_fixLifetime(self)
488+
return result
489+
}
490+
}
491+
431492
#else
432493
// Empty shim version for non-objc platforms.
433494
@usableFromInline

stdlib/public/stubs/GlobalObjects.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,8 @@ swift::_SwiftEmptyArrayStorage swift::_swiftEmptyArrayStorage = {
5353
}
5454
};
5555

56-
// Define required symbols to be used by constant static arrays.
57-
// * `__swiftImmortalRefCount`: The bit pattern for the ref-count field of
58-
// the array buffer.
59-
// * `__swiftStaticArrayMetadata`: The isa-pointer for the array buffer.
56+
// Define `__swiftImmortalRefCount` which is used by constant static arrays.
57+
// It is the bit pattern for the ref-count field of the array buffer.
6058
//
6159
// TODO: Support constant static arrays on other platforms, too.
6260
// This needs a bit more work because the tricks with absolute symbols and

test/SILOptimizer/readonly_arrays.swift

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,19 @@
99

1010
// Check if the optimizer is able to convert array literals to constant statically initialized arrays.
1111

12-
// CHECK: @"$s4test11arrayLookupyS2iFTv_r" = {{.*}} constant {{.*}} @"$ss19__EmptyArrayStorageCN", {{.*}} @_swiftImmortalRefCount
13-
// CHECK: @"$s4test11returnArraySaySiGyFTv_r" = {{.*}} constant {{.*}} @"$ss19__EmptyArrayStorageCN", {{.*}} @_swiftImmortalRefCount
14-
// CHECK: @"$s4test9passArrayyyFTv_r" = {{.*}} constant {{.*}} @"$ss19__EmptyArrayStorageCN", {{.*}} @_swiftImmortalRefCount
15-
// CHECK: @"$s4test9passArrayyyFTv0_r" = {{.*}} constant {{.*}} @"$ss19__EmptyArrayStorageCN", {{.*}} @_swiftImmortalRefCount
16-
// CHECK: @"$s4test10storeArrayyyFTv_r" = {{.*}} constant {{.*}} @"$ss19__EmptyArrayStorageCN", {{.*}} @_swiftImmortalRefCount
17-
// CHECK: @"$s4test3StrV14staticVariable_WZTv_r" = {{.*}} constant {{.*}} @"$ss19__EmptyArrayStorageCN", {{.*}} @_swiftImmortalRefCount
12+
// CHECK-DAG: @"$s4test11arrayLookupyS2iFTv_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} @_swiftImmortalRefCount
13+
// CHECK-DAG: @"$s4test11returnArraySaySiGyFTv_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} @_swiftImmortalRefCount
14+
// CHECK-DAG: @"$s4test9passArrayyyFTv_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} @_swiftImmortalRefCount
15+
// CHECK-DAG: @"$s4test9passArrayyyFTv0_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} @_swiftImmortalRefCount
16+
// CHECK-DAG: @"$s4test10storeArrayyyFTv_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} @_swiftImmortalRefCount
17+
// CHECK-DAG: @"$s4test3StrV14staticVariable_WZTv_r" = {{.*}} constant {{.*}} @"$ss20__StaticArrayStorageCN", {{.*}} @_swiftImmortalRefCount
1818
// CHECK-NOT: swift_initStaticObject
1919

2020
// UNSUPPORTED: use_os_stdlib
2121

2222
// Currently, constant static arrays only work on Darwin platforms.
2323
// REQUIRES: VENDOR=apple
2424

25-
// REQUIRES: rdar101126543
2625

2726
public struct Str {
2827
public static let staticVariable = [ 200, 201, 202 ]
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -target %target-future-triple -O %s -o %t/a.out
3+
// RUN: %target-run %t/a.out | %FileCheck %s
4+
5+
// REQUIRES: executable_test,swift_stdlib_no_asserts,optimized_stdlib
6+
// REQUIRES: objc_interop
7+
8+
// UNSUPPORTED: use_os_stdlib
9+
10+
import Foundation
11+
12+
@inline(never)
13+
func createArray() -> [Int] {
14+
return [1, 2, 3]
15+
}
16+
17+
@inline(never)
18+
func printNSArray(_ a: NSArray) {
19+
// CHECK: 1
20+
print(a[0])
21+
// CHECK: 2
22+
print(a[1])
23+
// CHECK: 3
24+
print(a[2])
25+
}
26+
27+
28+
@inline(never)
29+
func testit() {
30+
let a = createArray()
31+
printNSArray(a as NSArray)
32+
}
33+
34+
testit()

test/abi/macOS/arm64/stdlib-asserts.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,23 @@
4040

4141
// Standard Library Symbols
4242

43+
// class __StaticArrayStorage
44+
Added: _$ss20__StaticArrayStorageC12_doNotCallMeAByt_tcfC
45+
Added: _$ss20__StaticArrayStorageC12_doNotCallMeAByt_tcfCTj
46+
Added: _$ss20__StaticArrayStorageC12_doNotCallMeAByt_tcfCTq
47+
Added: _$ss20__StaticArrayStorageC12_doNotCallMeAByt_tcfc
48+
Added: _$ss20__StaticArrayStorageC16_doNotCallMeBaseAByt_tcfC
49+
Added: _$ss20__StaticArrayStorageC16_doNotCallMeBaseAByt_tcfc
50+
Added: _$ss20__StaticArrayStorageC16canStoreElements13ofDynamicTypeSbypXp_tF
51+
Added: _$ss20__StaticArrayStorageC17staticElementTypeypXpvg
52+
Added: _$ss20__StaticArrayStorageCMa
53+
Added: _$ss20__StaticArrayStorageCMn
54+
Added: _$ss20__StaticArrayStorageCMo
55+
Added: _$ss20__StaticArrayStorageCMu
56+
Added: _$ss20__StaticArrayStorageCN
57+
Added: _$ss20__StaticArrayStorageCfD
58+
Added: _$ss20__StaticArrayStorageCfd
59+
Added: _OBJC_CLASS_$__TtCs20__StaticArrayStorage
60+
Added: _OBJC_METACLASS_$__TtCs20__StaticArrayStorage
61+
4362
// Runtime Symbols

test/abi/macOS/arm64/stdlib.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,23 @@ Added: _$ss19_getWeakRetainCountySuyXlF
4545
// Swift._getUnownedRetainCount(Swift.AnyObject) -> Swift.UInt
4646
Added: _$ss22_getUnownedRetainCountySuyXlF
4747

48+
// class __StaticArrayStorage
49+
Added: _$ss20__StaticArrayStorageC12_doNotCallMeAByt_tcfC
50+
Added: _$ss20__StaticArrayStorageC12_doNotCallMeAByt_tcfCTj
51+
Added: _$ss20__StaticArrayStorageC12_doNotCallMeAByt_tcfCTq
52+
Added: _$ss20__StaticArrayStorageC12_doNotCallMeAByt_tcfc
53+
Added: _$ss20__StaticArrayStorageC16_doNotCallMeBaseAByt_tcfC
54+
Added: _$ss20__StaticArrayStorageC16_doNotCallMeBaseAByt_tcfc
55+
Added: _$ss20__StaticArrayStorageC16canStoreElements13ofDynamicTypeSbypXp_tF
56+
Added: _$ss20__StaticArrayStorageC17staticElementTypeypXpvg
57+
Added: _$ss20__StaticArrayStorageCMa
58+
Added: _$ss20__StaticArrayStorageCMn
59+
Added: _$ss20__StaticArrayStorageCMo
60+
Added: _$ss20__StaticArrayStorageCMu
61+
Added: _$ss20__StaticArrayStorageCN
62+
Added: _$ss20__StaticArrayStorageCfD
63+
Added: _$ss20__StaticArrayStorageCfd
64+
Added: _OBJC_CLASS_$__TtCs20__StaticArrayStorage
65+
Added: _OBJC_METACLASS_$__TtCs20__StaticArrayStorage
66+
4867
// Runtime Symbols

test/abi/macOS/x86_64/stdlib-asserts.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,23 @@
4040

4141
// Standard Library Symbols
4242

43+
// class __StaticArrayStorage
44+
Added: _$ss20__StaticArrayStorageC12_doNotCallMeAByt_tcfC
45+
Added: _$ss20__StaticArrayStorageC12_doNotCallMeAByt_tcfCTj
46+
Added: _$ss20__StaticArrayStorageC12_doNotCallMeAByt_tcfCTq
47+
Added: _$ss20__StaticArrayStorageC12_doNotCallMeAByt_tcfc
48+
Added: _$ss20__StaticArrayStorageC16_doNotCallMeBaseAByt_tcfC
49+
Added: _$ss20__StaticArrayStorageC16_doNotCallMeBaseAByt_tcfc
50+
Added: _$ss20__StaticArrayStorageC16canStoreElements13ofDynamicTypeSbypXp_tF
51+
Added: _$ss20__StaticArrayStorageC17staticElementTypeypXpvg
52+
Added: _$ss20__StaticArrayStorageCMa
53+
Added: _$ss20__StaticArrayStorageCMn
54+
Added: _$ss20__StaticArrayStorageCMo
55+
Added: _$ss20__StaticArrayStorageCMu
56+
Added: _$ss20__StaticArrayStorageCN
57+
Added: _$ss20__StaticArrayStorageCfD
58+
Added: _$ss20__StaticArrayStorageCfd
59+
Added: _OBJC_CLASS_$__TtCs20__StaticArrayStorage
60+
Added: _OBJC_METACLASS_$__TtCs20__StaticArrayStorage
61+
4362
// Runtime Symbols

0 commit comments

Comments
 (0)