10
10
11
11
#include "Python.h"
12
12
#include "pycore_ceval.h" // _Py_EnterRecursiveCall()
13
+ #include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION_SEQUENCE_FAST()
13
14
#include "pycore_global_strings.h" // _Py_ID()
14
15
#include "pycore_pyerrors.h" // _PyErr_FormatNote
15
16
#include "pycore_runtime.h" // _PyRuntime
@@ -1456,7 +1457,7 @@ write_newline_indent(PyUnicodeWriter *writer,
1456
1457
static PyObject *
1457
1458
encoder_call (PyObject * op , PyObject * args , PyObject * kwds )
1458
1459
{
1459
- /* Python callable interface to encode_listencode_obj */
1460
+ /* Python callable interface to encoder_listencode_obj */
1460
1461
static char * kwlist [] = {"obj" , "_current_indent_level" , NULL };
1461
1462
PyObject * obj ;
1462
1463
Py_ssize_t indent_level ;
@@ -1743,15 +1744,84 @@ encoder_encode_key_value(PyEncoderObject *s, PyUnicodeWriter *writer, bool *firs
1743
1744
return 0 ;
1744
1745
}
1745
1746
1747
+ static inline int
1748
+ _encoder_iterate_mapping_lock_held (PyEncoderObject * s , PyUnicodeWriter * writer ,
1749
+ bool * first , PyObject * dct , PyObject * items ,
1750
+ Py_ssize_t indent_level , PyObject * indent_cache ,
1751
+ PyObject * separator )
1752
+ {
1753
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED (items );
1754
+ PyObject * key , * value ;
1755
+ for (Py_ssize_t i = 0 ; i < PyList_GET_SIZE (items ); i ++ ) {
1756
+ PyObject * item = PyList_GET_ITEM (items , i );
1757
+ #ifdef Py_GIL_DISABLED
1758
+ // gh-119438: in the free-threading build the critical section on items can get suspended
1759
+ Py_INCREF (item );
1760
+ #endif
1761
+ if (!PyTuple_Check (item ) || PyTuple_GET_SIZE (item ) != 2 ) {
1762
+ PyErr_SetString (PyExc_ValueError , "items must return 2-tuples" );
1763
+ #ifdef Py_GIL_DISABLED
1764
+ Py_DECREF (item );
1765
+ #endif
1766
+ return -1 ;
1767
+ }
1768
+
1769
+ key = PyTuple_GET_ITEM (item , 0 );
1770
+ value = PyTuple_GET_ITEM (item , 1 );
1771
+ if (encoder_encode_key_value (s , writer , first , dct , key , value ,
1772
+ indent_level , indent_cache ,
1773
+ separator ) < 0 ) {
1774
+ #ifdef Py_GIL_DISABLED
1775
+ Py_DECREF (item );
1776
+ #endif
1777
+ return -1 ;
1778
+ }
1779
+ #ifdef Py_GIL_DISABLED
1780
+ Py_DECREF (item );
1781
+ #endif
1782
+ }
1783
+
1784
+ return 0 ;
1785
+ }
1786
+
1787
+ static inline int
1788
+ _encoder_iterate_dict_lock_held (PyEncoderObject * s , PyUnicodeWriter * writer ,
1789
+ bool * first , PyObject * dct , Py_ssize_t indent_level ,
1790
+ PyObject * indent_cache , PyObject * separator )
1791
+ {
1792
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED (dct );
1793
+ PyObject * key , * value ;
1794
+ Py_ssize_t pos = 0 ;
1795
+ while (PyDict_Next (dct , & pos , & key , & value )) {
1796
+ #ifdef Py_GIL_DISABLED
1797
+ // gh-119438: in the free-threading build the critical section on dct can get suspended
1798
+ Py_INCREF (key );
1799
+ Py_INCREF (value );
1800
+ #endif
1801
+ if (encoder_encode_key_value (s , writer , first , dct , key , value ,
1802
+ indent_level , indent_cache ,
1803
+ separator ) < 0 ) {
1804
+ #ifdef Py_GIL_DISABLED
1805
+ Py_DECREF (key );
1806
+ Py_DECREF (value );
1807
+ #endif
1808
+ return -1 ;
1809
+ }
1810
+ #ifdef Py_GIL_DISABLED
1811
+ Py_DECREF (key );
1812
+ Py_DECREF (value );
1813
+ #endif
1814
+ }
1815
+ return 0 ;
1816
+ }
1817
+
1746
1818
static int
1747
1819
encoder_listencode_dict (PyEncoderObject * s , PyUnicodeWriter * writer ,
1748
- PyObject * dct ,
1820
+ PyObject * dct ,
1749
1821
Py_ssize_t indent_level , PyObject * indent_cache )
1750
1822
{
1751
1823
/* Encode Python dict dct a JSON term */
1752
1824
PyObject * ident = NULL ;
1753
- PyObject * items = NULL ;
1754
- PyObject * key , * value ;
1755
1825
bool first = true;
1756
1826
1757
1827
if (PyDict_GET_SIZE (dct ) == 0 ) {
@@ -1788,34 +1858,30 @@ encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer,
1788
1858
}
1789
1859
1790
1860
if (s -> sort_keys || !PyDict_CheckExact (dct )) {
1791
- items = PyMapping_Items (dct );
1792
- if (items == NULL || (s -> sort_keys && PyList_Sort (items ) < 0 ))
1861
+ PyObject * items = PyMapping_Items (dct );
1862
+ if (items == NULL || (s -> sort_keys && PyList_Sort (items ) < 0 )) {
1863
+ Py_XDECREF (items );
1793
1864
goto bail ;
1865
+ }
1794
1866
1795
- for (Py_ssize_t i = 0 ; i < PyList_GET_SIZE (items ); i ++ ) {
1796
- PyObject * item = PyList_GET_ITEM (items , i );
1797
-
1798
- if (!PyTuple_Check (item ) || PyTuple_GET_SIZE (item ) != 2 ) {
1799
- PyErr_SetString (PyExc_ValueError , "items must return 2-tuples" );
1800
- goto bail ;
1801
- }
1802
-
1803
- key = PyTuple_GET_ITEM (item , 0 );
1804
- value = PyTuple_GET_ITEM (item , 1 );
1805
- if (encoder_encode_key_value (s , writer , & first , dct , key , value ,
1806
- indent_level , indent_cache ,
1807
- separator ) < 0 )
1808
- goto bail ;
1867
+ int result ;
1868
+ Py_BEGIN_CRITICAL_SECTION_SEQUENCE_FAST (items );
1869
+ result = _encoder_iterate_mapping_lock_held (s , writer , & first , dct ,
1870
+ items , indent_level , indent_cache , separator );
1871
+ Py_END_CRITICAL_SECTION_SEQUENCE_FAST ();
1872
+ Py_DECREF (items );
1873
+ if (result < 0 ) {
1874
+ goto bail ;
1809
1875
}
1810
- Py_CLEAR (items );
1811
1876
1812
1877
} else {
1813
- Py_ssize_t pos = 0 ;
1814
- while (PyDict_Next (dct , & pos , & key , & value )) {
1815
- if (encoder_encode_key_value (s , writer , & first , dct , key , value ,
1816
- indent_level , indent_cache ,
1817
- separator ) < 0 )
1818
- goto bail ;
1878
+ int result ;
1879
+ Py_BEGIN_CRITICAL_SECTION (dct );
1880
+ result = _encoder_iterate_dict_lock_held (s , writer , & first , dct ,
1881
+ indent_level , indent_cache , separator );
1882
+ Py_END_CRITICAL_SECTION ();
1883
+ if (result < 0 ) {
1884
+ goto bail ;
1819
1885
}
1820
1886
}
1821
1887
@@ -1837,22 +1903,52 @@ encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer,
1837
1903
return 0 ;
1838
1904
1839
1905
bail :
1840
- Py_XDECREF (items );
1841
1906
Py_XDECREF (ident );
1842
1907
return -1 ;
1843
1908
}
1844
1909
1910
+ static inline int
1911
+ _encoder_iterate_fast_seq_lock_held (PyEncoderObject * s , PyUnicodeWriter * writer ,
1912
+ PyObject * seq , PyObject * s_fast ,
1913
+ Py_ssize_t indent_level , PyObject * indent_cache , PyObject * separator )
1914
+ {
1915
+ for (Py_ssize_t i = 0 ; i < PySequence_Fast_GET_SIZE (s_fast ); i ++ ) {
1916
+ PyObject * obj = PySequence_Fast_GET_ITEM (s_fast , i );
1917
+ #ifdef Py_GIL_DISABLED
1918
+ // gh-119438: in the free-threading build the critical section on s_fast can get suspended
1919
+ Py_INCREF (obj );
1920
+ #endif
1921
+ if (i ) {
1922
+ if (PyUnicodeWriter_WriteStr (writer , separator ) < 0 ) {
1923
+ #ifdef Py_GIL_DISABLED
1924
+ Py_DECREF (obj );
1925
+ #endif
1926
+ return -1 ;
1927
+ }
1928
+ }
1929
+ if (encoder_listencode_obj (s , writer , obj , indent_level , indent_cache )) {
1930
+ _PyErr_FormatNote ("when serializing %T item %zd" , seq , i );
1931
+ #ifdef Py_GIL_DISABLED
1932
+ Py_DECREF (obj );
1933
+ #endif
1934
+ return -1 ;
1935
+ }
1936
+ #ifdef Py_GIL_DISABLED
1937
+ Py_DECREF (obj );
1938
+ #endif
1939
+ }
1940
+ return 0 ;
1941
+ }
1942
+
1845
1943
static int
1846
1944
encoder_listencode_list (PyEncoderObject * s , PyUnicodeWriter * writer ,
1847
1945
PyObject * seq ,
1848
1946
Py_ssize_t indent_level , PyObject * indent_cache )
1849
1947
{
1850
1948
PyObject * ident = NULL ;
1851
1949
PyObject * s_fast = NULL ;
1852
- Py_ssize_t i ;
1853
1950
1854
- ident = NULL ;
1855
- s_fast = PySequence_Fast (seq , "_iterencode_list needs a sequence" );
1951
+ s_fast = PySequence_Fast (seq , "encoder_listencode_list needs a sequence" );
1856
1952
if (s_fast == NULL )
1857
1953
return -1 ;
1858
1954
if (PySequence_Fast_GET_SIZE (s_fast ) == 0 ) {
@@ -1890,16 +1986,13 @@ encoder_listencode_list(PyEncoderObject *s, PyUnicodeWriter *writer,
1890
1986
goto bail ;
1891
1987
}
1892
1988
}
1893
- for (i = 0 ; i < PySequence_Fast_GET_SIZE (s_fast ); i ++ ) {
1894
- PyObject * obj = PySequence_Fast_GET_ITEM (s_fast , i );
1895
- if (i ) {
1896
- if (PyUnicodeWriter_WriteStr (writer , separator ) < 0 )
1897
- goto bail ;
1898
- }
1899
- if (encoder_listencode_obj (s , writer , obj , indent_level , indent_cache )) {
1900
- _PyErr_FormatNote ("when serializing %T item %zd" , seq , i );
1901
- goto bail ;
1902
- }
1989
+ int result ;
1990
+ Py_BEGIN_CRITICAL_SECTION_SEQUENCE_FAST (seq );
1991
+ result = _encoder_iterate_fast_seq_lock_held (s , writer , seq , s_fast ,
1992
+ indent_level , indent_cache , separator );
1993
+ Py_END_CRITICAL_SECTION_SEQUENCE_FAST ();
1994
+ if (result < 0 ) {
1995
+ goto bail ;
1903
1996
}
1904
1997
if (ident != NULL ) {
1905
1998
if (PyDict_DelItem (s -> markers , ident ))
0 commit comments