@@ -779,73 +779,142 @@ void swift::swift_deallocObject(HeapObject *object,
779
779
}
780
780
}
781
781
782
+ enum : uintptr_t {
783
+ WR_NATIVE = 1 <<(swift::heap_object_abi::ObjCReservedLowBits),
784
+ WR_READING = 1 <<(swift::heap_object_abi::ObjCReservedLowBits+1 ),
785
+
786
+ WR_NATIVEMASK = WR_NATIVE | swift::heap_object_abi::ObjCReservedBitsMask,
787
+ };
788
+
789
+ static_assert (WR_READING < alignof (void *),
790
+ "weakref lock bit mustn't interfere with real pointer bits");
791
+
792
+ enum : short {
793
+ WR_SPINLIMIT = 64 ,
794
+ };
795
+
796
+ bool swift::isNativeSwiftWeakReference (WeakReference *ref) {
797
+ return (ref->Value & WR_NATIVEMASK) == WR_NATIVE;
798
+ }
799
+
782
800
void swift::swift_weakInit (WeakReference *ref, HeapObject *value) {
783
- ref->Value = value;
801
+ ref->Value = ( uintptr_t ) value | WR_NATIVE ;
784
802
SWIFT_RT_ENTRY_CALL (swift_unownedRetain)(value);
785
803
}
786
804
787
805
void swift::swift_weakAssign (WeakReference *ref, HeapObject *newValue) {
788
806
SWIFT_RT_ENTRY_CALL (swift_unownedRetain)(newValue);
789
- auto oldValue = ref->Value ;
790
- ref->Value = newValue;
807
+ auto oldValue = (HeapObject*) ( ref->Value & ~WR_NATIVE) ;
808
+ ref->Value = ( uintptr_t ) newValue | WR_NATIVE ;
791
809
SWIFT_RT_ENTRY_CALL (swift_unownedRelease)(oldValue);
792
810
}
793
811
794
812
HeapObject *swift::swift_weakLoadStrong (WeakReference *ref) {
795
- auto object = ref->Value ;
796
- if (object == nullptr ) return nullptr ;
813
+ if (ref->Value == (uintptr_t )nullptr ) {
814
+ return nullptr ;
815
+ }
816
+
817
+ // ref might be visible to other threads
818
+ auto ptr = __atomic_fetch_or (&ref->Value , WR_READING, __ATOMIC_RELAXED);
819
+ while (ptr & WR_READING) {
820
+ short c = 0 ;
821
+ while (__atomic_load_n (&ref->Value , __ATOMIC_RELAXED) & WR_READING) {
822
+ if (++c == WR_SPINLIMIT) {
823
+ sched_yield ();
824
+ c -= 1 ;
825
+ }
826
+ }
827
+ ptr = __atomic_fetch_or (&ref->Value , WR_READING, __ATOMIC_RELAXED);
828
+ }
829
+
830
+ auto object = (HeapObject*)(ptr & ~WR_NATIVE);
831
+ if (object == nullptr ) {
832
+ __atomic_store_n (&ref->Value , (uintptr_t )nullptr , __ATOMIC_RELAXED);
833
+ return nullptr ;
834
+ }
797
835
if (object->refCount .isDeallocating ()) {
836
+ __atomic_store_n (&ref->Value , (uintptr_t )nullptr , __ATOMIC_RELAXED);
798
837
SWIFT_RT_ENTRY_CALL (swift_unownedRelease)(object);
799
- ref->Value = nullptr ;
800
838
return nullptr ;
801
839
}
802
- return swift_tryRetain (object);
840
+ auto result = swift_tryRetain (object);
841
+ __atomic_store_n (&ref->Value , ptr, __ATOMIC_RELAXED);
842
+ return result;
803
843
}
804
844
805
845
HeapObject *swift::swift_weakTakeStrong (WeakReference *ref) {
806
- auto result = swift_weakLoadStrong (ref);
807
- swift_weakDestroy (ref);
846
+ auto object = (HeapObject*) (ref->Value & ~WR_NATIVE);
847
+ if (object == nullptr ) return nullptr ;
848
+ auto result = swift_tryRetain (object);
849
+ ref->Value = (uintptr_t )nullptr ;
850
+ swift_unownedRelease (object);
808
851
return result;
809
852
}
810
853
811
854
void swift::swift_weakDestroy (WeakReference *ref) {
812
- auto tmp = ref->Value ;
813
- ref->Value = nullptr ;
855
+ auto tmp = (HeapObject*) ( ref->Value & ~WR_NATIVE) ;
856
+ ref->Value = ( uintptr_t ) nullptr ;
814
857
SWIFT_RT_ENTRY_CALL (swift_unownedRelease)(tmp);
815
858
}
816
859
817
860
void swift::swift_weakCopyInit (WeakReference *dest, WeakReference *src) {
818
- auto object = src->Value ;
861
+ if (src->Value == (uintptr_t )nullptr ) {
862
+ dest->Value = (uintptr_t )nullptr ;
863
+ return ;
864
+ }
865
+
866
+ // src might be visible to other threads
867
+ auto ptr = __atomic_fetch_or (&src->Value , WR_READING, __ATOMIC_RELAXED);
868
+ while (ptr & WR_READING) {
869
+ short c = 0 ;
870
+ while (__atomic_load_n (&src->Value , __ATOMIC_RELAXED) & WR_READING) {
871
+ if (++c == WR_SPINLIMIT) {
872
+ sched_yield ();
873
+ c -= 1 ;
874
+ }
875
+ }
876
+ ptr = __atomic_fetch_or (&src->Value , WR_READING, __ATOMIC_RELAXED);
877
+ }
878
+
879
+ auto object = (HeapObject*)(ptr & ~WR_NATIVE);
819
880
if (object == nullptr ) {
820
- dest->Value = nullptr ;
881
+ __atomic_store_n (&src->Value , (uintptr_t )nullptr , __ATOMIC_RELAXED);
882
+ dest->Value = (uintptr_t )nullptr ;
821
883
} else if (object->refCount .isDeallocating ()) {
822
- src->Value = nullptr ;
823
- dest->Value = nullptr ;
884
+ __atomic_store_n (&src->Value , (uintptr_t )nullptr , __ATOMIC_RELAXED);
824
885
SWIFT_RT_ENTRY_CALL (swift_unownedRelease)(object);
886
+ dest->Value = (uintptr_t )nullptr ;
825
887
} else {
826
- dest->Value = object;
827
888
SWIFT_RT_ENTRY_CALL (swift_unownedRetain)(object);
889
+ __atomic_store_n (&src->Value , ptr, __ATOMIC_RELAXED);
890
+ dest->Value = (uintptr_t )object | WR_NATIVE;
828
891
}
829
892
}
830
893
831
894
void swift::swift_weakTakeInit (WeakReference *dest, WeakReference *src) {
832
- auto object = src->Value ;
833
- dest->Value = object;
834
- if (object != nullptr && object->refCount .isDeallocating ()) {
835
- dest->Value = nullptr ;
895
+ auto object = (HeapObject*) (src->Value & ~WR_NATIVE);
896
+ if (object == nullptr ) {
897
+ dest->Value = (uintptr_t )nullptr ;
898
+ } else if (object->refCount .isDeallocating ()) {
899
+ dest->Value = (uintptr_t )nullptr ;
836
900
SWIFT_RT_ENTRY_CALL (swift_unownedRelease)(object);
901
+ } else {
902
+ dest->Value = (uintptr_t )object | WR_NATIVE;
837
903
}
904
+ src->Value = (uintptr_t )nullptr ;
838
905
}
839
906
840
907
void swift::swift_weakCopyAssign (WeakReference *dest, WeakReference *src) {
841
- if (auto object = dest->Value ) {
908
+ if (dest->Value ) {
909
+ auto object = (HeapObject*) (dest->Value & ~WR_NATIVE);
842
910
SWIFT_RT_ENTRY_CALL (swift_unownedRelease)(object);
843
911
}
844
912
swift_weakCopyInit (dest, src);
845
913
}
846
914
847
915
void swift::swift_weakTakeAssign (WeakReference *dest, WeakReference *src) {
848
- if (auto object = dest->Value ) {
916
+ if (dest->Value ) {
917
+ auto object = (HeapObject*) (dest->Value & ~WR_NATIVE);
849
918
SWIFT_RT_ENTRY_CALL (swift_unownedRelease)(object);
850
919
}
851
920
swift_weakTakeInit (dest, src);
0 commit comments