@@ -238,14 +238,29 @@ struct RefCountBitOffsets;
238
238
// 32-bit out of line
239
239
template <>
240
240
struct RefCountBitOffsets <8 > {
241
- static const size_t IsImmortalShift = 0 ;
242
- static const size_t IsImmortalBitCount = 1 ;
243
- static const uint64_t IsImmortalMask = maskForField(IsImmortal);
244
-
245
- static const size_t UnownedRefCountShift = shiftAfterField(IsImmortal);
241
+ /*
242
+ The bottom 32 bits (on 64 bit architectures, fewer on 32 bit) of the refcount
243
+ field are effectively a union of two different configurations:
244
+
245
+ ---Normal case---
246
+ Bit 0: Does this object need to call out to the ObjC runtime for deallocation
247
+ Bits 1-31: Unowned refcount
248
+
249
+ ---Immortal case---
250
+ All bits set, the object does not deallocate or have a refcount
251
+ */
252
+ static const size_t PureSwiftDeallocShift = 0 ;
253
+ static const size_t PureSwiftDeallocBitCount = 1 ;
254
+ static const uint64_t PureSwiftDeallocMask = maskForField(PureSwiftDealloc);
255
+
256
+ static const size_t UnownedRefCountShift = shiftAfterField(PureSwiftDealloc);
246
257
static const size_t UnownedRefCountBitCount = 31 ;
247
258
static const uint64_t UnownedRefCountMask = maskForField(UnownedRefCount);
248
259
260
+ static const size_t IsImmortalShift = 0 ; // overlaps PureSwiftDealloc and UnownedRefCount
261
+ static const size_t IsImmortalBitCount = 32 ;
262
+ static const uint64_t IsImmortalMask = maskForField(IsImmortal);
263
+
249
264
static const size_t IsDeinitingShift = shiftAfterField(UnownedRefCount);
250
265
static const size_t IsDeinitingBitCount = 1 ;
251
266
static const uint64_t IsDeinitingMask = maskForField(IsDeiniting);
@@ -271,14 +286,18 @@ struct RefCountBitOffsets<8> {
271
286
// 32-bit inline
272
287
template <>
273
288
struct RefCountBitOffsets <4 > {
274
- static const size_t IsImmortalShift = 0 ;
275
- static const size_t IsImmortalBitCount = 1 ;
276
- static const uint64_t IsImmortalMask = maskForField(IsImmortal );
289
+ static const size_t PureSwiftDeallocShift = 0 ;
290
+ static const size_t PureSwiftDeallocBitCount = 1 ;
291
+ static const uint32_t PureSwiftDeallocMask = maskForField(PureSwiftDealloc );
277
292
278
- static const size_t UnownedRefCountShift = shiftAfterField(IsImmortal );
293
+ static const size_t UnownedRefCountShift = shiftAfterField(PureSwiftDealloc );
279
294
static const size_t UnownedRefCountBitCount = 7 ;
280
295
static const uint32_t UnownedRefCountMask = maskForField(UnownedRefCount);
281
296
297
+ static const size_t IsImmortalShift = 0 ; // overlaps PureSwiftDealloc and UnownedRefCount
298
+ static const size_t IsImmortalBitCount = 8 ;
299
+ static const uint32_t IsImmortalMask = maskForField(IsImmortal);
300
+
282
301
static const size_t IsDeinitingShift = shiftAfterField(UnownedRefCount);
283
302
static const size_t IsDeinitingBitCount = 1 ;
284
303
static const uint32_t IsDeinitingMask = maskForField(IsDeiniting);
@@ -369,33 +388,56 @@ class RefCountBitsT {
369
388
enum Immortal_t { Immortal };
370
389
371
390
LLVM_ATTRIBUTE_ALWAYS_INLINE
372
- bool isImmortal () const {
373
- return bool (getField (IsImmortal));
391
+ bool isImmortal (bool checkSlowRCBit) const {
392
+ if (checkSlowRCBit) {
393
+ return (getField (IsImmortal) == Offsets::IsImmortalMask) &&
394
+ bool (getField (UseSlowRC));
395
+ } else {
396
+ return (getField (IsImmortal) == Offsets::IsImmortalMask);
397
+ }
398
+ }
399
+
400
+ LLVM_ATTRIBUTE_ALWAYS_INLINE
401
+ bool isOverflowingUnownedRefCount (uint32_t oldValue, uint32_t inc) const {
402
+ auto newValue = getUnownedRefCount ();
403
+ return newValue != oldValue + inc ||
404
+ newValue == Offsets::UnownedRefCountMask;
374
405
}
375
406
376
407
LLVM_ATTRIBUTE_ALWAYS_INLINE
377
408
void setIsImmortal (bool value) {
378
- setField (IsImmortal, value);
409
+ assert (value);
410
+ setField (IsImmortal, Offsets::IsImmortalMask);
379
411
setField (UseSlowRC, value);
380
412
}
381
413
414
+ LLVM_ATTRIBUTE_ALWAYS_INLINE
415
+ bool pureSwiftDeallocation () const {
416
+ return bool (getField (PureSwiftDealloc)) && !bool (getField (UseSlowRC));
417
+ }
418
+
419
+ LLVM_ATTRIBUTE_ALWAYS_INLINE
420
+ void setPureSwiftDeallocation (bool value) {
421
+ setField (PureSwiftDealloc, value);
422
+ }
423
+
382
424
LLVM_ATTRIBUTE_ALWAYS_INLINE
383
425
RefCountBitsT () = default;
384
426
385
427
LLVM_ATTRIBUTE_ALWAYS_INLINE
386
428
constexpr
387
429
RefCountBitsT (uint32_t strongExtraCount, uint32_t unownedCount)
388
430
: bits((BitsType(strongExtraCount) << Offsets::StrongExtraRefCountShift) |
431
+ (BitsType(1 ) << Offsets::PureSwiftDeallocShift) |
389
432
(BitsType(unownedCount) << Offsets::UnownedRefCountShift))
390
433
{ }
391
434
392
435
LLVM_ATTRIBUTE_ALWAYS_INLINE
393
436
constexpr
394
437
RefCountBitsT (Immortal_t immortal)
395
- : bits((BitsType(2 ) << Offsets::StrongExtraRefCountShift) |
396
- (BitsType(2 ) << Offsets::UnownedRefCountShift) |
397
- (BitsType(1 ) << Offsets::IsImmortalShift) |
398
- (BitsType(1 ) << Offsets::UseSlowRCShift))
438
+ : bits((BitsType(2 ) << Offsets::StrongExtraRefCountShift) |
439
+ (BitsType(Offsets::IsImmortalMask)) |
440
+ (BitsType(1 ) << Offsets::UseSlowRCShift))
399
441
{ }
400
442
401
443
LLVM_ATTRIBUTE_ALWAYS_INLINE
@@ -433,7 +475,7 @@ class RefCountBitsT {
433
475
434
476
LLVM_ATTRIBUTE_ALWAYS_INLINE
435
477
bool hasSideTable () const {
436
- bool hasSide = getUseSlowRC () && !isImmortal ();
478
+ bool hasSide = getUseSlowRC () && !isImmortal (false );
437
479
438
480
// Side table refcount must not point to another side table.
439
481
assert ((refcountIsInline || !hasSide) &&
@@ -523,7 +565,7 @@ class RefCountBitsT {
523
565
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE
524
566
bool decrementStrongExtraRefCount (uint32_t dec) {
525
567
#ifndef NDEBUG
526
- if (!hasSideTable () && !isImmortal ()) {
568
+ if (!hasSideTable () && !isImmortal (false )) {
527
569
// Can't check these assertions with side table present.
528
570
529
571
if (getIsDeiniting ())
@@ -558,7 +600,7 @@ class RefCountBitsT {
558
600
static_assert (Offsets::UnownedRefCountBitCount +
559
601
Offsets::IsDeinitingBitCount +
560
602
Offsets::StrongExtraRefCountBitCount +
561
- Offsets::IsImmortalBitCount +
603
+ Offsets::PureSwiftDeallocBitCount +
562
604
Offsets::UseSlowRCBitCount == sizeof (bits)*8 ,
563
605
" inspect isUniquelyReferenced after adding fields" );
564
606
@@ -715,7 +757,7 @@ class RefCounts {
715
757
716
758
void setIsImmortal (bool immortal) {
717
759
auto oldbits = refCounts.load (SWIFT_MEMORY_ORDER_CONSUME);
718
- if (oldbits.isImmortal ()) {
760
+ if (oldbits.isImmortal (true )) {
719
761
return ;
720
762
}
721
763
RefCountBits newbits;
@@ -725,7 +767,28 @@ class RefCounts {
725
767
} while (!refCounts.compare_exchange_weak (oldbits, newbits,
726
768
std::memory_order_relaxed));
727
769
}
728
-
770
+
771
+ void setPureSwiftDeallocation (bool nonobjc) {
772
+ auto oldbits = refCounts.load (SWIFT_MEMORY_ORDER_CONSUME);
773
+ // Immortal and no objc complications share a bit, so don't let setting
774
+ // the complications one clear the immmortal one
775
+ if (oldbits.isImmortal (true ) || oldbits.pureSwiftDeallocation () == nonobjc){
776
+ assert (!oldbits.hasSideTable ());
777
+ return ;
778
+ }
779
+ RefCountBits newbits;
780
+ do {
781
+ newbits = oldbits;
782
+ newbits.setPureSwiftDeallocation (nonobjc);
783
+ } while (!refCounts.compare_exchange_weak (oldbits, newbits,
784
+ std::memory_order_relaxed));
785
+ }
786
+
787
+ bool getPureSwiftDeallocation () {
788
+ auto bits = refCounts.load (SWIFT_MEMORY_ORDER_CONSUME);
789
+ return bits.pureSwiftDeallocation ();
790
+ }
791
+
729
792
// Initialize from another refcount bits.
730
793
// Only inline -> out-of-line is allowed (used for new side table entries).
731
794
void init (InlineRefCountBits newBits) {
@@ -740,7 +803,7 @@ class RefCounts {
740
803
newbits = oldbits;
741
804
bool fast = newbits.incrementStrongExtraRefCount (inc);
742
805
if (SWIFT_UNLIKELY (!fast)) {
743
- if (oldbits.isImmortal ())
806
+ if (oldbits.isImmortal (false ))
744
807
return ;
745
808
return incrementSlow (oldbits, inc);
746
809
}
@@ -753,7 +816,7 @@ class RefCounts {
753
816
auto newbits = oldbits;
754
817
bool fast = newbits.incrementStrongExtraRefCount (inc);
755
818
if (SWIFT_UNLIKELY (!fast)) {
756
- if (oldbits.isImmortal ())
819
+ if (oldbits.isImmortal (false ))
757
820
return ;
758
821
return incrementNonAtomicSlow (oldbits, inc);
759
822
}
@@ -771,7 +834,7 @@ class RefCounts {
771
834
newbits = oldbits;
772
835
bool fast = newbits.incrementStrongExtraRefCount (1 );
773
836
if (SWIFT_UNLIKELY (!fast)) {
774
- if (oldbits.isImmortal ())
837
+ if (oldbits.isImmortal (false ))
775
838
return true ;
776
839
return tryIncrementSlow (oldbits);
777
840
}
@@ -788,7 +851,7 @@ class RefCounts {
788
851
auto newbits = oldbits;
789
852
bool fast = newbits.incrementStrongExtraRefCount (1 );
790
853
if (SWIFT_UNLIKELY (!fast)) {
791
- if (oldbits.isImmortal ())
854
+ if (oldbits.isImmortal (false ))
792
855
return true ;
793
856
return tryIncrementNonAtomicSlow (oldbits);
794
857
}
@@ -824,7 +887,7 @@ class RefCounts {
824
887
// Precondition: the reference count must be 1
825
888
void decrementFromOneNonAtomic () {
826
889
auto bits = refCounts.load (SWIFT_MEMORY_ORDER_CONSUME);
827
- if (bits.isImmortal ()) {
890
+ if (bits.isImmortal (true )) {
828
891
return ;
829
892
}
830
893
if (bits.hasSideTable ())
@@ -922,7 +985,7 @@ class RefCounts {
922
985
// Decrement completed normally. New refcount is not zero.
923
986
deinitNow = false ;
924
987
}
925
- else if (oldbits.isImmortal ()) {
988
+ else if (oldbits.isImmortal (false )) {
926
989
return false ;
927
990
} else if (oldbits.hasSideTable ()) {
928
991
// Decrement failed because we're on some other slow path.
@@ -961,7 +1024,7 @@ class RefCounts {
961
1024
// Decrement completed normally. New refcount is not zero.
962
1025
deinitNow = false ;
963
1026
}
964
- else if (oldbits.isImmortal ()) {
1027
+ else if (oldbits.isImmortal (false )) {
965
1028
return false ;
966
1029
}
967
1030
else if (oldbits.hasSideTable ()) {
@@ -1001,7 +1064,7 @@ class RefCounts {
1001
1064
bool fast =
1002
1065
newbits.decrementStrongExtraRefCount (dec);
1003
1066
if (SWIFT_UNLIKELY (!fast)) {
1004
- if (oldbits.isImmortal ()) {
1067
+ if (oldbits.isImmortal (false )) {
1005
1068
return false ;
1006
1069
}
1007
1070
// Slow paths include side table; deinit; underflow
@@ -1025,7 +1088,7 @@ class RefCounts {
1025
1088
// Increment the unowned reference count.
1026
1089
void incrementUnowned (uint32_t inc) {
1027
1090
auto oldbits = refCounts.load (SWIFT_MEMORY_ORDER_CONSUME);
1028
- if (oldbits.isImmortal ())
1091
+ if (oldbits.isImmortal (true ))
1029
1092
return ;
1030
1093
RefCountBits newbits;
1031
1094
do {
@@ -1037,7 +1100,7 @@ class RefCounts {
1037
1100
uint32_t oldValue = newbits.incrementUnownedRefCount (inc);
1038
1101
1039
1102
// Check overflow and use the side table on overflow.
1040
- if (newbits.getUnownedRefCount () != oldValue + inc)
1103
+ if (newbits.isOverflowingUnownedRefCount ( oldValue, inc) )
1041
1104
return incrementUnownedSlow (inc);
1042
1105
1043
1106
} while (!refCounts.compare_exchange_weak (oldbits, newbits,
@@ -1046,7 +1109,7 @@ class RefCounts {
1046
1109
1047
1110
void incrementUnownedNonAtomic (uint32_t inc) {
1048
1111
auto oldbits = refCounts.load (SWIFT_MEMORY_ORDER_CONSUME);
1049
- if (oldbits.isImmortal ())
1112
+ if (oldbits.isImmortal (true ))
1050
1113
return ;
1051
1114
if (oldbits.hasSideTable ())
1052
1115
return oldbits.getSideTable ()->incrementUnownedNonAtomic (inc);
@@ -1056,7 +1119,7 @@ class RefCounts {
1056
1119
uint32_t oldValue = newbits.incrementUnownedRefCount (inc);
1057
1120
1058
1121
// Check overflow and use the side table on overflow.
1059
- if (newbits.getUnownedRefCount () != oldValue + inc)
1122
+ if (newbits.isOverflowingUnownedRefCount ( oldValue, inc) )
1060
1123
return incrementUnownedSlow (inc);
1061
1124
1062
1125
refCounts.store (newbits, std::memory_order_relaxed);
@@ -1066,7 +1129,7 @@ class RefCounts {
1066
1129
// Return true if the caller should free the object.
1067
1130
bool decrementUnownedShouldFree (uint32_t dec) {
1068
1131
auto oldbits = refCounts.load (SWIFT_MEMORY_ORDER_CONSUME);
1069
- if (oldbits.isImmortal ())
1132
+ if (oldbits.isImmortal (true ))
1070
1133
return false ;
1071
1134
RefCountBits newbits;
1072
1135
@@ -1094,7 +1157,7 @@ class RefCounts {
1094
1157
1095
1158
bool decrementUnownedShouldFreeNonAtomic (uint32_t dec) {
1096
1159
auto oldbits = refCounts.load (SWIFT_MEMORY_ORDER_CONSUME);
1097
- if (oldbits.isImmortal ())
1160
+ if (oldbits.isImmortal (true ))
1098
1161
return false ;
1099
1162
if (oldbits.hasSideTable ())
1100
1163
return oldbits.getSideTable ()->decrementUnownedShouldFreeNonAtomic (dec);
@@ -1383,7 +1446,7 @@ inline bool RefCounts<InlineRefCountBits>::doDecrementNonAtomic(uint32_t dec) {
1383
1446
auto newbits = oldbits;
1384
1447
bool fast = newbits.decrementStrongExtraRefCount (dec);
1385
1448
if (!fast) {
1386
- if (oldbits.isImmortal ()) {
1449
+ if (oldbits.isImmortal (false )) {
1387
1450
return false ;
1388
1451
}
1389
1452
return doDecrementNonAtomicSlow<performDeinit>(oldbits, dec);
0 commit comments