@@ -1595,78 +1595,75 @@ static PyType_Spec attrgetter_type_spec = {
15951595typedef struct {
15961596 PyObject_HEAD
15971597 PyObject * name ;
1598- PyObject * xargs ; // reference to arguments passed in constructor
1598+ PyObject * args ;
15991599 PyObject * kwds ;
1600- PyObject * * vectorcall_args ; /* Borrowed references */
1600+ PyObject * vectorcall_args ;
16011601 PyObject * vectorcall_kwnames ;
16021602 vectorcallfunc vectorcall ;
16031603} methodcallerobject ;
16041604
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- }
16451605
1606+ #define _METHODCALLER_MAX_ARGS 8
16461607
16471608static 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 )
16501611{
16511612 if (!_PyArg_CheckPositional ("methodcaller" , PyVectorcall_NARGS (nargsf ), 1 , 1 )
16521613 || !_PyArg_NoKwnames ("methodcaller" , kwnames )) {
16531614 return NULL ;
16541615 }
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 ));
16601622
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 ,
16661625 mc -> vectorcall_kwnames );
16671626}
1668- #endif
16691627
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+ }
16701667
16711668/* AC 3.5: variable number of arguments, not currently support by AC */
16721669static PyObject *
@@ -1694,25 +1691,30 @@ methodcaller_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
16941691 if (mc == NULL ) {
16951692 return NULL ;
16961693 }
1694+ mc -> vectorcall = NULL ;
1695+ mc -> vectorcall_args = NULL ;
1696+ mc -> vectorcall_kwnames = NULL ;
1697+ mc -> kwds = Py_XNewRef (kwds );
16971698
16981699 Py_INCREF (name );
16991700 PyInterpreterState * interp = _PyInterpreterState_GET ();
17001701 _PyUnicode_InternMortal (interp , & name );
17011702 mc -> name = name ;
17021703
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+ }
17071709
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+ }
17161718
17171719 PyObject_GC_Track (mc );
17181720 return (PyObject * )mc ;
@@ -1722,13 +1724,10 @@ static void
17221724methodcaller_clear (methodcallerobject * mc )
17231725{
17241726 Py_CLEAR (mc -> name );
1725- Py_CLEAR (mc -> xargs );
1727+ Py_CLEAR (mc -> args );
17261728 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 );
17321731}
17331732
17341733static void
@@ -1745,8 +1744,10 @@ static int
17451744methodcaller_traverse (methodcallerobject * mc , visitproc visit , void * arg )
17461745{
17471746 Py_VISIT (mc -> name );
1748- Py_VISIT (mc -> xargs );
1747+ Py_VISIT (mc -> args );
17491748 Py_VISIT (mc -> kwds );
1749+ Py_VISIT (mc -> vectorcall_args );
1750+ Py_VISIT (mc -> vectorcall_kwnames );
17501751 Py_VISIT (Py_TYPE (mc ));
17511752 return 0 ;
17521753}
@@ -1765,15 +1766,7 @@ methodcaller_call(methodcallerobject *mc, PyObject *args, PyObject *kw)
17651766 if (method == NULL )
17661767 return NULL ;
17671768
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 );
17771770 Py_DECREF (method );
17781771 return result ;
17791772}
@@ -1791,7 +1784,7 @@ methodcaller_repr(methodcallerobject *mc)
17911784 }
17921785
17931786 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 ) ;
17951788 numtotalargs = numposargs + numkwdargs ;
17961789
17971790 if (numtotalargs == 0 ) {
@@ -1807,7 +1800,7 @@ methodcaller_repr(methodcallerobject *mc)
18071800 }
18081801
18091802 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 ));
18111804 if (onerepr == NULL )
18121805 goto done ;
18131806 PyTuple_SET_ITEM (argreprs , i , onerepr );
@@ -1859,14 +1852,14 @@ methodcaller_reduce(methodcallerobject *mc, PyObject *Py_UNUSED(ignored))
18591852{
18601853 if (!mc -> kwds || PyDict_GET_SIZE (mc -> kwds ) == 0 ) {
18611854 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 );
18641857 if (newargs == NULL )
18651858 return NULL ;
18661859 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 ));
18701863 }
18711864 return Py_BuildValue ("ON" , Py_TYPE (mc ), newargs );
18721865 }
@@ -1884,12 +1877,7 @@ methodcaller_reduce(methodcallerobject *mc, PyObject *Py_UNUSED(ignored))
18841877 constructor = PyObject_VectorcallDict (partial , newargs , 2 , mc -> kwds );
18851878
18861879 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 );
18931881 }
18941882}
18951883
0 commit comments