@@ -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,55 @@ 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
+ setField (IsImmortal, value ? Offsets::IsImmortalMask : 0 );
379
410
setField (UseSlowRC, value);
380
411
}
381
412
413
+ LLVM_ATTRIBUTE_ALWAYS_INLINE
414
+ bool pureSwiftDeallocation () const {
415
+ return bool (getField (PureSwiftDealloc)) && !bool (getField (UseSlowRC));
416
+ }
417
+
418
+ LLVM_ATTRIBUTE_ALWAYS_INLINE
419
+ void setPureSwiftDeallocation (bool value) {
420
+ setField (PureSwiftDealloc, value);
421
+ }
422
+
382
423
LLVM_ATTRIBUTE_ALWAYS_INLINE
383
424
RefCountBitsT () = default;
384
425
385
426
LLVM_ATTRIBUTE_ALWAYS_INLINE
386
427
constexpr
387
428
RefCountBitsT (uint32_t strongExtraCount, uint32_t unownedCount)
388
429
: bits((BitsType(strongExtraCount) << Offsets::StrongExtraRefCountShift) |
430
+ (BitsType(1 ) << Offsets::PureSwiftDeallocShift) |
389
431
(BitsType(unownedCount) << Offsets::UnownedRefCountShift))
390
432
{ }
391
433
392
434
LLVM_ATTRIBUTE_ALWAYS_INLINE
393
435
constexpr
394
436
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))
437
+ : bits((BitsType(2 ) << Offsets::StrongExtraRefCountShift) |
438
+ (BitsType(Offsets::IsImmortalMask)) |
439
+ (BitsType(1 ) << Offsets::UseSlowRCShift))
399
440
{ }
400
441
401
442
LLVM_ATTRIBUTE_ALWAYS_INLINE
@@ -433,7 +474,7 @@ class RefCountBitsT {
433
474
434
475
LLVM_ATTRIBUTE_ALWAYS_INLINE
435
476
bool hasSideTable () const {
436
- bool hasSide = getUseSlowRC () && !isImmortal ();
477
+ bool hasSide = getUseSlowRC () && !isImmortal (false );
437
478
438
479
// Side table refcount must not point to another side table.
439
480
assert ((refcountIsInline || !hasSide) &&
@@ -523,7 +564,7 @@ class RefCountBitsT {
523
564
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE
524
565
bool decrementStrongExtraRefCount (uint32_t dec) {
525
566
#ifndef NDEBUG
526
- if (!hasSideTable () && !isImmortal ()) {
567
+ if (!hasSideTable () && !isImmortal (false )) {
527
568
// Can't check these assertions with side table present.
528
569
529
570
if (getIsDeiniting ())
@@ -558,7 +599,7 @@ class RefCountBitsT {
558
599
static_assert (Offsets::UnownedRefCountBitCount +
559
600
Offsets::IsDeinitingBitCount +
560
601
Offsets::StrongExtraRefCountBitCount +
561
- Offsets::IsImmortalBitCount +
602
+ Offsets::PureSwiftDeallocBitCount +
562
603
Offsets::UseSlowRCBitCount == sizeof (bits)*8 ,
563
604
" inspect isUniquelyReferenced after adding fields" );
564
605
@@ -715,7 +756,7 @@ class RefCounts {
715
756
716
757
void setIsImmortal (bool immortal) {
717
758
auto oldbits = refCounts.load (SWIFT_MEMORY_ORDER_CONSUME);
718
- if (oldbits.isImmortal ()) {
759
+ if (oldbits.isImmortal (true )) {
719
760
return ;
720
761
}
721
762
RefCountBits newbits;
@@ -725,7 +766,27 @@ class RefCounts {
725
766
} while (!refCounts.compare_exchange_weak (oldbits, newbits,
726
767
std::memory_order_relaxed));
727
768
}
728
-
769
+
770
+ void setPureSwiftDeallocation (bool nonobjc) {
771
+ auto oldbits = refCounts.load (SWIFT_MEMORY_ORDER_CONSUME);
772
+ // Immortal and no objc complications share a bit, so don't let setting
773
+ // the complications one clear the immmortal one
774
+ if (oldbits.isImmortal (true ) || oldbits.pureSwiftDeallocation () == nonobjc){
775
+ return ;
776
+ }
777
+ RefCountBits newbits;
778
+ do {
779
+ newbits = oldbits;
780
+ newbits.setPureSwiftDeallocation (nonobjc);
781
+ } while (!refCounts.compare_exchange_weak (oldbits, newbits,
782
+ std::memory_order_relaxed));
783
+ }
784
+
785
+ bool getPureSwiftDeallocation () {
786
+ auto bits = refCounts.load (SWIFT_MEMORY_ORDER_CONSUME);
787
+ return bits.pureSwiftDeallocation ();
788
+ }
789
+
729
790
// Initialize from another refcount bits.
730
791
// Only inline -> out-of-line is allowed (used for new side table entries).
731
792
void init (InlineRefCountBits newBits) {
@@ -740,7 +801,7 @@ class RefCounts {
740
801
newbits = oldbits;
741
802
bool fast = newbits.incrementStrongExtraRefCount (inc);
742
803
if (SWIFT_UNLIKELY (!fast)) {
743
- if (oldbits.isImmortal ())
804
+ if (oldbits.isImmortal (false ))
744
805
return ;
745
806
return incrementSlow (oldbits, inc);
746
807
}
@@ -753,7 +814,7 @@ class RefCounts {
753
814
auto newbits = oldbits;
754
815
bool fast = newbits.incrementStrongExtraRefCount (inc);
755
816
if (SWIFT_UNLIKELY (!fast)) {
756
- if (oldbits.isImmortal ())
817
+ if (oldbits.isImmortal (false ))
757
818
return ;
758
819
return incrementNonAtomicSlow (oldbits, inc);
759
820
}
@@ -771,7 +832,7 @@ class RefCounts {
771
832
newbits = oldbits;
772
833
bool fast = newbits.incrementStrongExtraRefCount (1 );
773
834
if (SWIFT_UNLIKELY (!fast)) {
774
- if (oldbits.isImmortal ())
835
+ if (oldbits.isImmortal (false ))
775
836
return true ;
776
837
return tryIncrementSlow (oldbits);
777
838
}
@@ -788,7 +849,7 @@ class RefCounts {
788
849
auto newbits = oldbits;
789
850
bool fast = newbits.incrementStrongExtraRefCount (1 );
790
851
if (SWIFT_UNLIKELY (!fast)) {
791
- if (oldbits.isImmortal ())
852
+ if (oldbits.isImmortal (false ))
792
853
return true ;
793
854
return tryIncrementNonAtomicSlow (oldbits);
794
855
}
@@ -824,7 +885,7 @@ class RefCounts {
824
885
// Precondition: the reference count must be 1
825
886
void decrementFromOneNonAtomic () {
826
887
auto bits = refCounts.load (SWIFT_MEMORY_ORDER_CONSUME);
827
- if (bits.isImmortal ()) {
888
+ if (bits.isImmortal (true )) {
828
889
return ;
829
890
}
830
891
if (bits.hasSideTable ())
@@ -922,7 +983,7 @@ class RefCounts {
922
983
// Decrement completed normally. New refcount is not zero.
923
984
deinitNow = false ;
924
985
}
925
- else if (oldbits.isImmortal ()) {
986
+ else if (oldbits.isImmortal (false )) {
926
987
return false ;
927
988
} else if (oldbits.hasSideTable ()) {
928
989
// Decrement failed because we're on some other slow path.
@@ -961,7 +1022,7 @@ class RefCounts {
961
1022
// Decrement completed normally. New refcount is not zero.
962
1023
deinitNow = false ;
963
1024
}
964
- else if (oldbits.isImmortal ()) {
1025
+ else if (oldbits.isImmortal (false )) {
965
1026
return false ;
966
1027
}
967
1028
else if (oldbits.hasSideTable ()) {
@@ -1001,7 +1062,7 @@ class RefCounts {
1001
1062
bool fast =
1002
1063
newbits.decrementStrongExtraRefCount (dec);
1003
1064
if (SWIFT_UNLIKELY (!fast)) {
1004
- if (oldbits.isImmortal ()) {
1065
+ if (oldbits.isImmortal (false )) {
1005
1066
return false ;
1006
1067
}
1007
1068
// Slow paths include side table; deinit; underflow
@@ -1025,7 +1086,7 @@ class RefCounts {
1025
1086
// Increment the unowned reference count.
1026
1087
void incrementUnowned (uint32_t inc) {
1027
1088
auto oldbits = refCounts.load (SWIFT_MEMORY_ORDER_CONSUME);
1028
- if (oldbits.isImmortal ())
1089
+ if (oldbits.isImmortal (true ))
1029
1090
return ;
1030
1091
RefCountBits newbits;
1031
1092
do {
@@ -1037,7 +1098,7 @@ class RefCounts {
1037
1098
uint32_t oldValue = newbits.incrementUnownedRefCount (inc);
1038
1099
1039
1100
// Check overflow and use the side table on overflow.
1040
- if (newbits.getUnownedRefCount () != oldValue + inc)
1101
+ if (newbits.isOverflowingUnownedRefCount ( oldValue, inc) )
1041
1102
return incrementUnownedSlow (inc);
1042
1103
1043
1104
} while (!refCounts.compare_exchange_weak (oldbits, newbits,
@@ -1046,7 +1107,7 @@ class RefCounts {
1046
1107
1047
1108
void incrementUnownedNonAtomic (uint32_t inc) {
1048
1109
auto oldbits = refCounts.load (SWIFT_MEMORY_ORDER_CONSUME);
1049
- if (oldbits.isImmortal ())
1110
+ if (oldbits.isImmortal (true ))
1050
1111
return ;
1051
1112
if (oldbits.hasSideTable ())
1052
1113
return oldbits.getSideTable ()->incrementUnownedNonAtomic (inc);
@@ -1056,7 +1117,7 @@ class RefCounts {
1056
1117
uint32_t oldValue = newbits.incrementUnownedRefCount (inc);
1057
1118
1058
1119
// Check overflow and use the side table on overflow.
1059
- if (newbits.getUnownedRefCount () != oldValue + inc)
1120
+ if (newbits.isOverflowingUnownedRefCount ( oldValue, inc) )
1060
1121
return incrementUnownedSlow (inc);
1061
1122
1062
1123
refCounts.store (newbits, std::memory_order_relaxed);
@@ -1066,7 +1127,7 @@ class RefCounts {
1066
1127
// Return true if the caller should free the object.
1067
1128
bool decrementUnownedShouldFree (uint32_t dec) {
1068
1129
auto oldbits = refCounts.load (SWIFT_MEMORY_ORDER_CONSUME);
1069
- if (oldbits.isImmortal ())
1130
+ if (oldbits.isImmortal (true ))
1070
1131
return false ;
1071
1132
RefCountBits newbits;
1072
1133
@@ -1094,7 +1155,7 @@ class RefCounts {
1094
1155
1095
1156
bool decrementUnownedShouldFreeNonAtomic (uint32_t dec) {
1096
1157
auto oldbits = refCounts.load (SWIFT_MEMORY_ORDER_CONSUME);
1097
- if (oldbits.isImmortal ())
1158
+ if (oldbits.isImmortal (true ))
1098
1159
return false ;
1099
1160
if (oldbits.hasSideTable ())
1100
1161
return oldbits.getSideTable ()->decrementUnownedShouldFreeNonAtomic (dec);
@@ -1383,7 +1444,7 @@ inline bool RefCounts<InlineRefCountBits>::doDecrementNonAtomic(uint32_t dec) {
1383
1444
auto newbits = oldbits;
1384
1445
bool fast = newbits.decrementStrongExtraRefCount (dec);
1385
1446
if (!fast) {
1386
- if (oldbits.isImmortal ()) {
1447
+ if (oldbits.isImmortal (false )) {
1387
1448
return false ;
1388
1449
}
1389
1450
return doDecrementNonAtomicSlow<performDeinit>(oldbits, dec);
0 commit comments