@@ -1595,78 +1595,75 @@ static PyType_Spec attrgetter_type_spec = {
1595
1595
typedef struct {
1596
1596
PyObject_HEAD
1597
1597
PyObject * name ;
1598
- PyObject * xargs ; // reference to arguments passed in constructor
1598
+ PyObject * args ;
1599
1599
PyObject * kwds ;
1600
- PyObject * * vectorcall_args ; /* Borrowed references */
1600
+ PyObject * vectorcall_args ;
1601
1601
PyObject * vectorcall_kwnames ;
1602
1602
vectorcallfunc vectorcall ;
1603
1603
} methodcallerobject ;
1604
1604
1605
- #ifndef Py_GIL_DISABLED
1606
- static int _methodcaller_initialize_vectorcall (methodcallerobject * mc )
1607
- {
1608
- PyObject * args = mc -> xargs ;
1609
- PyObject * kwds = mc -> kwds ;
1610
-
1611
- Py_ssize_t nargs = PyTuple_GET_SIZE (args );
1612
- assert (nargs > 0 );
1613
- mc -> vectorcall_args = PyMem_Calloc (
1614
- nargs + (kwds ? PyDict_Size (kwds ) : 0 ),
1615
- sizeof (PyObject * ));
1616
- if (!mc -> vectorcall_args ) {
1617
- PyErr_NoMemory ();
1618
- return -1 ;
1619
- }
1620
- /* The first item of vectorcall_args will be filled with obj later */
1621
- if (nargs > 1 ) {
1622
- memcpy (mc -> vectorcall_args , PySequence_Fast_ITEMS (args ),
1623
- nargs * sizeof (PyObject * ));
1624
- }
1625
- if (kwds ) {
1626
- const Py_ssize_t nkwds = PyDict_Size (kwds );
1627
-
1628
- mc -> vectorcall_kwnames = PyTuple_New (nkwds );
1629
- if (!mc -> vectorcall_kwnames ) {
1630
- return -1 ;
1631
- }
1632
- Py_ssize_t i = 0 , ppos = 0 ;
1633
- PyObject * key , * value ;
1634
- while (PyDict_Next (kwds , & ppos , & key , & value )) {
1635
- PyTuple_SET_ITEM (mc -> vectorcall_kwnames , i , Py_NewRef (key ));
1636
- mc -> vectorcall_args [nargs + i ] = value ; // borrowed reference
1637
- ++ i ;
1638
- }
1639
- }
1640
- else {
1641
- mc -> vectorcall_kwnames = NULL ;
1642
- }
1643
- return 1 ;
1644
- }
1645
1605
1606
+ #define _METHODCALLER_MAX_ARGS 8
1646
1607
1647
1608
static PyObject *
1648
- methodcaller_vectorcall (
1649
- methodcallerobject * mc , PyObject * const * args , size_t nargsf , PyObject * kwnames )
1609
+ methodcaller_vectorcall (methodcallerobject * mc , PyObject * const * args ,
1610
+ size_t nargsf , PyObject * kwnames )
1650
1611
{
1651
1612
if (!_PyArg_CheckPositional ("methodcaller" , PyVectorcall_NARGS (nargsf ), 1 , 1 )
1652
1613
|| !_PyArg_NoKwnames ("methodcaller" , kwnames )) {
1653
1614
return NULL ;
1654
1615
}
1655
- if (mc -> vectorcall_args == NULL ) {
1656
- if (_methodcaller_initialize_vectorcall (mc ) < 0 ) {
1657
- return NULL ;
1658
- }
1659
- }
1616
+ assert (mc -> vectorcall_args != NULL );
1617
+
1618
+ PyObject * tmp_args [_METHODCALLER_MAX_ARGS ];
1619
+ tmp_args [0 ] = args [0 ];
1620
+ assert (1 + PyTuple_GET_SIZE (mc -> vectorcall_args ) <= _METHODCALLER_MAX_ARGS );
1621
+ memcpy (tmp_args + 1 , _PyTuple_ITEMS (mc -> vectorcall_args ), sizeof (PyObject * ) * PyTuple_GET_SIZE (mc -> vectorcall_args ));
1660
1622
1661
- assert (mc -> vectorcall_args != 0 );
1662
- mc -> vectorcall_args [0 ] = args [0 ];
1663
- return PyObject_VectorcallMethod (
1664
- mc -> name , mc -> vectorcall_args ,
1665
- (PyTuple_GET_SIZE (mc -> xargs )) | PY_VECTORCALL_ARGUMENTS_OFFSET ,
1623
+ return PyObject_VectorcallMethod (mc -> name , tmp_args ,
1624
+ (1 + PyTuple_GET_SIZE (mc -> args )) | PY_VECTORCALL_ARGUMENTS_OFFSET ,
1666
1625
mc -> vectorcall_kwnames );
1667
1626
}
1668
- #endif
1669
1627
1628
+ static int
1629
+ _methodcaller_initialize_vectorcall (methodcallerobject * mc )
1630
+ {
1631
+ PyObject * args = mc -> args ;
1632
+ PyObject * kwds = mc -> kwds ;
1633
+
1634
+ if (kwds && PyDict_Size (kwds )) {
1635
+ PyObject * values = PyDict_Values (kwds );
1636
+ if (!values ) {
1637
+ return -1 ;
1638
+ }
1639
+ PyObject * values_tuple = PySequence_Tuple (values );
1640
+ Py_DECREF (values );
1641
+ if (!values_tuple ) {
1642
+ return -1 ;
1643
+ }
1644
+ if (PyTuple_GET_SIZE (args )) {
1645
+ mc -> vectorcall_args = PySequence_Concat (args , values_tuple );
1646
+ Py_DECREF (values_tuple );
1647
+ if (mc -> vectorcall_args == NULL ) {
1648
+ return -1 ;
1649
+ }
1650
+ }
1651
+ else {
1652
+ mc -> vectorcall_args = values_tuple ;
1653
+ }
1654
+ mc -> vectorcall_kwnames = PySequence_Tuple (kwds );
1655
+ if (!mc -> vectorcall_kwnames ) {
1656
+ return -1 ;
1657
+ }
1658
+ }
1659
+ else {
1660
+ mc -> vectorcall_args = Py_NewRef (args );
1661
+ mc -> vectorcall_kwnames = NULL ;
1662
+ }
1663
+
1664
+ mc -> vectorcall = (vectorcallfunc )methodcaller_vectorcall ;
1665
+ return 0 ;
1666
+ }
1670
1667
1671
1668
/* AC 3.5: variable number of arguments, not currently support by AC */
1672
1669
static PyObject *
@@ -1694,25 +1691,30 @@ methodcaller_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1694
1691
if (mc == NULL ) {
1695
1692
return NULL ;
1696
1693
}
1694
+ mc -> vectorcall = NULL ;
1695
+ mc -> vectorcall_args = NULL ;
1696
+ mc -> vectorcall_kwnames = NULL ;
1697
+ mc -> kwds = Py_XNewRef (kwds );
1697
1698
1698
1699
Py_INCREF (name );
1699
1700
PyInterpreterState * interp = _PyInterpreterState_GET ();
1700
1701
_PyUnicode_InternMortal (interp , & name );
1701
1702
mc -> name = name ;
1702
1703
1703
- mc -> xargs = Py_XNewRef (args ); // allows us to use borrowed references
1704
- mc -> kwds = Py_XNewRef (kwds );
1705
- mc -> vectorcall_args = 0 ;
1706
-
1704
+ mc -> args = PyTuple_GetSlice (args , 1 , PyTuple_GET_SIZE (args ));
1705
+ if (mc -> args == NULL ) {
1706
+ Py_DECREF (mc );
1707
+ return NULL ;
1708
+ }
1707
1709
1708
- #ifdef Py_GIL_DISABLED
1709
- // gh-127065: The current implementation of methodcaller_vectorcall
1710
- // is not thread-safe because it modifies the `vectorcall_args` array,
1711
- // which is shared across calls.
1712
- mc -> vectorcall = NULL ;
1713
- #else
1714
- mc -> vectorcall = ( vectorcallfunc ) methodcaller_vectorcall ;
1715
- #endif
1710
+ Py_ssize_t vectorcall_size = PyTuple_GET_SIZE ( args )
1711
+ + ( kwds ? PyDict_Size ( kwds ) : 0 );
1712
+ if ( vectorcall_size < ( _METHODCALLER_MAX_ARGS )) {
1713
+ if ( _methodcaller_initialize_vectorcall ( mc ) < 0 ) {
1714
+ Py_DECREF ( mc ) ;
1715
+ return NULL ;
1716
+ }
1717
+ }
1716
1718
1717
1719
PyObject_GC_Track (mc );
1718
1720
return (PyObject * )mc ;
@@ -1722,13 +1724,10 @@ static void
1722
1724
methodcaller_clear (methodcallerobject * mc )
1723
1725
{
1724
1726
Py_CLEAR (mc -> name );
1725
- Py_CLEAR (mc -> xargs );
1727
+ Py_CLEAR (mc -> args );
1726
1728
Py_CLEAR (mc -> kwds );
1727
- if (mc -> vectorcall_args != NULL ) {
1728
- PyMem_Free (mc -> vectorcall_args );
1729
- mc -> vectorcall_args = 0 ;
1730
- Py_CLEAR (mc -> vectorcall_kwnames );
1731
- }
1729
+ Py_CLEAR (mc -> vectorcall_args );
1730
+ Py_CLEAR (mc -> vectorcall_kwnames );
1732
1731
}
1733
1732
1734
1733
static void
@@ -1745,8 +1744,10 @@ static int
1745
1744
methodcaller_traverse (methodcallerobject * mc , visitproc visit , void * arg )
1746
1745
{
1747
1746
Py_VISIT (mc -> name );
1748
- Py_VISIT (mc -> xargs );
1747
+ Py_VISIT (mc -> args );
1749
1748
Py_VISIT (mc -> kwds );
1749
+ Py_VISIT (mc -> vectorcall_args );
1750
+ Py_VISIT (mc -> vectorcall_kwnames );
1750
1751
Py_VISIT (Py_TYPE (mc ));
1751
1752
return 0 ;
1752
1753
}
@@ -1765,15 +1766,7 @@ methodcaller_call(methodcallerobject *mc, PyObject *args, PyObject *kw)
1765
1766
if (method == NULL )
1766
1767
return NULL ;
1767
1768
1768
-
1769
- PyObject * cargs = PyTuple_GetSlice (mc -> xargs , 1 , PyTuple_GET_SIZE (mc -> xargs ));
1770
- if (cargs == NULL ) {
1771
- Py_DECREF (method );
1772
- return NULL ;
1773
- }
1774
-
1775
- result = PyObject_Call (method , cargs , mc -> kwds );
1776
- Py_DECREF (cargs );
1769
+ result = PyObject_Call (method , mc -> args , mc -> kwds );
1777
1770
Py_DECREF (method );
1778
1771
return result ;
1779
1772
}
@@ -1791,7 +1784,7 @@ methodcaller_repr(methodcallerobject *mc)
1791
1784
}
1792
1785
1793
1786
numkwdargs = mc -> kwds != NULL ? PyDict_GET_SIZE (mc -> kwds ) : 0 ;
1794
- numposargs = PyTuple_GET_SIZE (mc -> xargs ) - 1 ;
1787
+ numposargs = PyTuple_GET_SIZE (mc -> args ) ;
1795
1788
numtotalargs = numposargs + numkwdargs ;
1796
1789
1797
1790
if (numtotalargs == 0 ) {
@@ -1807,7 +1800,7 @@ methodcaller_repr(methodcallerobject *mc)
1807
1800
}
1808
1801
1809
1802
for (i = 0 ; i < numposargs ; ++ i ) {
1810
- PyObject * onerepr = PyObject_Repr (PyTuple_GET_ITEM (mc -> xargs , i + 1 ));
1803
+ PyObject * onerepr = PyObject_Repr (PyTuple_GET_ITEM (mc -> args , i ));
1811
1804
if (onerepr == NULL )
1812
1805
goto done ;
1813
1806
PyTuple_SET_ITEM (argreprs , i , onerepr );
@@ -1859,14 +1852,14 @@ methodcaller_reduce(methodcallerobject *mc, PyObject *Py_UNUSED(ignored))
1859
1852
{
1860
1853
if (!mc -> kwds || PyDict_GET_SIZE (mc -> kwds ) == 0 ) {
1861
1854
Py_ssize_t i ;
1862
- Py_ssize_t newarg_size = PyTuple_GET_SIZE (mc -> xargs );
1863
- PyObject * newargs = PyTuple_New (newarg_size );
1855
+ Py_ssize_t callargcount = PyTuple_GET_SIZE (mc -> args );
1856
+ PyObject * newargs = PyTuple_New (1 + callargcount );
1864
1857
if (newargs == NULL )
1865
1858
return NULL ;
1866
1859
PyTuple_SET_ITEM (newargs , 0 , Py_NewRef (mc -> name ));
1867
- for (i = 1 ; i < newarg_size ; ++ i ) {
1868
- PyObject * arg = PyTuple_GET_ITEM (mc -> xargs , i );
1869
- PyTuple_SET_ITEM (newargs , i , Py_NewRef (arg ));
1860
+ for (i = 0 ; i < callargcount ; ++ i ) {
1861
+ PyObject * arg = PyTuple_GET_ITEM (mc -> args , i );
1862
+ PyTuple_SET_ITEM (newargs , i + 1 , Py_NewRef (arg ));
1870
1863
}
1871
1864
return Py_BuildValue ("ON" , Py_TYPE (mc ), newargs );
1872
1865
}
@@ -1884,12 +1877,7 @@ methodcaller_reduce(methodcallerobject *mc, PyObject *Py_UNUSED(ignored))
1884
1877
constructor = PyObject_VectorcallDict (partial , newargs , 2 , mc -> kwds );
1885
1878
1886
1879
Py_DECREF (partial );
1887
- PyObject * args = PyTuple_GetSlice (mc -> xargs , 1 , PyTuple_GET_SIZE (mc -> xargs ));
1888
- if (!args ) {
1889
- Py_DECREF (constructor );
1890
- return NULL ;
1891
- }
1892
- return Py_BuildValue ("NO" , constructor , args );
1880
+ return Py_BuildValue ("NO" , constructor , mc -> args );
1893
1881
}
1894
1882
}
1895
1883
0 commit comments