@@ -631,6 +631,9 @@ typedef union {
631
631
char * values ;
632
632
} PyDictOrValues ;
633
633
634
+ // Sentinel value to indicate when an update to PyDictOrValues is in-flight
635
+ #define _PYDICTORVALUES_UPDATING 0x0000002
636
+
634
637
static inline PyDictOrValues *
635
638
_PyObject_DictOrValuesPointer (PyObject * obj )
636
639
{
@@ -651,23 +654,120 @@ _PyDictOrValues_GetValues(PyDictOrValues dorv)
651
654
return (PyDictValues * )(dorv .values + 1 );
652
655
}
653
656
657
+ static inline PyDictValues *
658
+ _PyDictOrValues_TryGetValues (PyDictOrValues * dorv )
659
+ {
660
+ #ifdef Py_GIL_DISABLED
661
+ char * values ;
662
+ while (1 ) {
663
+ values = _Py_atomic_load_ptr_acquire (& dorv -> values );
664
+ if (values != (char * )_PYDICTORVALUES_UPDATING ) {
665
+ if ((uintptr_t )values & 1 ) {
666
+ return (PyDictValues * )(values + 1 );
667
+ }
668
+ // The values have become a dict or is not yet initialized
669
+ return NULL ;
670
+ }
671
+ // There is an atomic update of the values in progress...
672
+ _Py_yield ();
673
+ }
674
+ #else
675
+ if (_PyDictOrValues_IsValues (* dorv )) {
676
+ return _PyDictOrValues_GetValues (* dorv );
677
+ }
678
+ return NULL ;
679
+ #endif
680
+ }
681
+
654
682
static inline PyObject *
655
683
_PyDictOrValues_GetDict (PyDictOrValues dorv )
656
684
{
657
685
assert (!_PyDictOrValues_IsValues (dorv ));
658
686
return dorv .dict ;
659
687
}
660
688
689
+ // Trys to get the dict from the PyDictOrValues and returns
690
+ // a new strong reference if successful.
691
+ static inline PyObject *
692
+ _PyDictOrValues_TryGetDict (PyDictOrValues * dorv )
693
+ {
694
+ #ifdef Py_GIL_DISABLED
695
+ PyObject * dict ;
696
+ while (1 ) {
697
+ dict = _Py_atomic_load_ptr_acquire (& dorv -> dict );
698
+ if (dict != (PyObject * )_PYDICTORVALUES_UPDATING ) {
699
+ if ((uintptr_t )dict & 1 ) {
700
+ // The dict has become a values
701
+ return NULL ;
702
+ } else if (dict != NULL ) {
703
+ Py_INCREF (dict );
704
+ if (_Py_atomic_load_ptr_acquire (& dorv -> dict ) == dict ) {
705
+ return dict ;
706
+ }
707
+
708
+ // We've lost a race (presumably with dematerialization) so
709
+ // we'll try again...
710
+ Py_DECREF (dict );
711
+ } else {
712
+ // The dict is not yet initialized...
713
+ return dict ;
714
+ }
715
+ }
716
+ // There is an atomic update of the values in progress...
717
+ _Py_yield ();
718
+ }
719
+ #else
720
+ if (!_PyDictOrValues_IsValues (* dorv )) {
721
+ Py_XINCREF (dorv -> dict );
722
+ return dorv -> dict ;
723
+ }
724
+ return NULL ;
725
+ #endif
726
+ }
727
+
728
+ static inline bool
729
+ _PyDictOrValues_TrySetDict (PyDictOrValues * dorv_ptr , void * expected , PyObject * dict )
730
+ {
731
+ #ifdef Py_GIL_DISABLED
732
+ if (!_Py_atomic_compare_exchange_ptr (& dorv_ptr -> dict , & expected , dict )) {
733
+ return false;
734
+ }
735
+ return true;
736
+ #else
737
+ dorv_ptr -> dict = dict ;
738
+ return true;
739
+ #endif
740
+ }
741
+
742
+
743
+
744
+ static inline void
745
+ _PyDictOrValues_FreeValues (PyDictValues * values )
746
+ {
747
+ // TODO: Maybe free with qsbr
748
+ int prefix_size = ((uint8_t * )values )[-1 ];
749
+ PyMem_Free (((char * )values )- prefix_size );
750
+ }
751
+
661
752
static inline void
662
753
_PyDictOrValues_SetValues (PyDictOrValues * ptr , PyDictValues * values )
663
754
{
755
+ #ifdef Py_GIL_DISABLED
756
+ char * expected = NULL ;
757
+ if (!_Py_atomic_compare_exchange_ptr (& ptr -> values , & expected , ((char * )values ) - 1 )) {
758
+ _PyDictOrValues_FreeValues (values );
759
+ }
760
+ #else
664
761
ptr -> values = ((char * )values ) - 1 ;
762
+ #endif
665
763
}
666
764
667
765
extern PyObject * * _PyObject_ComputedDictPointer (PyObject * );
668
766
extern void _PyObject_FreeInstanceAttributes (PyObject * obj );
669
767
extern int _PyObject_IsInstanceDictEmpty (PyObject * );
670
768
769
+ extern int _PyObject_SetDict (PyObject * obj , PyObject * new_dict );
770
+
671
771
// Export for 'math' shared extension
672
772
PyAPI_FUNC (PyObject * ) _PyObject_LookupSpecial (PyObject * , PyObject * );
673
773
0 commit comments