@@ -825,6 +825,60 @@ object_vacall(PyThreadState *tstate, PyObject *base,
825825 return result ;
826826}
827827
828+ PyObject *
829+ _PyObject_VectorcallPrepend (PyThreadState * tstate , PyObject * callable ,
830+ PyObject * arg , PyObject * const * args ,
831+ size_t nargsf , PyObject * kwnames )
832+ {
833+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
834+ assert (nargs == 0 || args [nargs - 1 ]);
835+
836+ PyObject * result ;
837+ if (nargsf & PY_VECTORCALL_ARGUMENTS_OFFSET ) {
838+ /* PY_VECTORCALL_ARGUMENTS_OFFSET is set, so we are allowed to mutate the vector */
839+ PyObject * * newargs = (PyObject * * )args - 1 ;
840+ nargs += 1 ;
841+ PyObject * tmp = newargs [0 ];
842+ newargs [0 ] = arg ;
843+ assert (newargs [nargs - 1 ]);
844+ result = _PyObject_VectorcallTstate (tstate , callable , newargs ,
845+ nargs , kwnames );
846+ newargs [0 ] = tmp ;
847+ }
848+ else {
849+ Py_ssize_t nkwargs = (kwnames == NULL ) ? 0 : PyTuple_GET_SIZE (kwnames );
850+ Py_ssize_t totalargs = nargs + nkwargs ;
851+ if (totalargs == 0 ) {
852+ return _PyObject_VectorcallTstate (tstate , callable , & arg , 1 , NULL );
853+ }
854+
855+ PyObject * newargs_stack [_PY_FASTCALL_SMALL_STACK ];
856+ PyObject * * newargs ;
857+ if (totalargs <= (Py_ssize_t )Py_ARRAY_LENGTH (newargs_stack ) - 1 ) {
858+ newargs = newargs_stack ;
859+ }
860+ else {
861+ newargs = PyMem_Malloc ((totalargs + 1 ) * sizeof (PyObject * ));
862+ if (newargs == NULL ) {
863+ _PyErr_NoMemory (tstate );
864+ return NULL ;
865+ }
866+ }
867+ /* use borrowed references */
868+ newargs [0 ] = arg ;
869+ /* bpo-37138: since totalargs > 0, it's impossible that args is NULL.
870+ * We need this, since calling memcpy() with a NULL pointer is
871+ * undefined behaviour. */
872+ assert (args != NULL );
873+ memcpy (newargs + 1 , args , totalargs * sizeof (PyObject * ));
874+ result = _PyObject_VectorcallTstate (tstate , callable ,
875+ newargs , nargs + 1 , kwnames );
876+ if (newargs != newargs_stack ) {
877+ PyMem_Free (newargs );
878+ }
879+ }
880+ return result ;
881+ }
828882
829883PyObject *
830884PyObject_VectorcallMethod (PyObject * name , PyObject * const * args ,
@@ -835,28 +889,44 @@ PyObject_VectorcallMethod(PyObject *name, PyObject *const *args,
835889 assert (PyVectorcall_NARGS (nargsf ) >= 1 );
836890
837891 PyThreadState * tstate = _PyThreadState_GET ();
838- PyObject * callable = NULL ;
892+ _PyCStackRef self , method ;
893+ _PyThreadState_PushCStackRef (tstate , & self );
894+ _PyThreadState_PushCStackRef (tstate , & method );
839895 /* Use args[0] as "self" argument */
840- int unbound = _PyObject_GetMethod (args [0 ], name , & callable );
841- if (callable == NULL ) {
896+ self .ref = PyStackRef_FromPyObjectBorrow (args [0 ]);
897+ int unbound = _PyObject_GetMethodStackRef (tstate , & self .ref , name , & method .ref );
898+ if (unbound < 0 ) {
899+ _PyThreadState_PopCStackRef (tstate , & method );
900+ _PyThreadState_PopCStackRef (tstate , & self );
842901 return NULL ;
843902 }
844903
845- if (unbound ) {
904+ PyObject * callable = PyStackRef_AsPyObjectBorrow (method .ref );
905+ PyObject * self_obj = PyStackRef_AsPyObjectBorrow (self .ref );
906+ PyObject * result ;
907+
908+ EVAL_CALL_STAT_INC_IF_FUNCTION (EVAL_CALL_METHOD , callable );
909+ if (self_obj == NULL ) {
910+ /* Skip "self". We can keep PY_VECTORCALL_ARGUMENTS_OFFSET since
911+ * args[-1] in the onward call is args[0] here. */
912+ result = _PyObject_VectorcallTstate (tstate , callable ,
913+ args + 1 , nargsf - 1 , kwnames );
914+ }
915+ else if (self_obj == args [0 ]) {
846916 /* We must remove PY_VECTORCALL_ARGUMENTS_OFFSET since
847917 * that would be interpreted as allowing to change args[-1] */
848- nargsf &= ~PY_VECTORCALL_ARGUMENTS_OFFSET ;
918+ result = _PyObject_VectorcallTstate (tstate , callable , args ,
919+ nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET ,
920+ kwnames );
849921 }
850922 else {
851- /* Skip "self". We can keep PY_VECTORCALL_ARGUMENTS_OFFSET since
852- * args[-1] in the onward call is args[0] here . */
853- args ++ ;
854- nargsf -- ;
923+ /* classmethod: self_obj is the type, not args[0]. Replace
924+ * args[0] with self_obj and call the underlying callable . */
925+ result = _PyObject_VectorcallPrepend ( tstate , callable , self_obj ,
926+ args + 1 , nargsf - 1 , kwnames ) ;
855927 }
856- EVAL_CALL_STAT_INC_IF_FUNCTION (EVAL_CALL_METHOD , callable );
857- PyObject * result = _PyObject_VectorcallTstate (tstate , callable ,
858- args , nargsf , kwnames );
859- Py_DECREF (callable );
928+ _PyThreadState_PopCStackRef (tstate , & method );
929+ _PyThreadState_PopCStackRef (tstate , & self );
860930 return result ;
861931}
862932
@@ -869,19 +939,26 @@ PyObject_CallMethodObjArgs(PyObject *obj, PyObject *name, ...)
869939 return null_error (tstate );
870940 }
871941
872- PyObject * callable = NULL ;
873- int is_method = _PyObject_GetMethod (obj , name , & callable );
874- if (callable == NULL ) {
942+ _PyCStackRef self , method ;
943+ _PyThreadState_PushCStackRef (tstate , & self );
944+ _PyThreadState_PushCStackRef (tstate , & method );
945+ self .ref = PyStackRef_FromPyObjectBorrow (obj );
946+ int res = _PyObject_GetMethodStackRef (tstate , & self .ref , name , & method .ref );
947+ if (res < 0 ) {
948+ _PyThreadState_PopCStackRef (tstate , & method );
949+ _PyThreadState_PopCStackRef (tstate , & self );
875950 return NULL ;
876951 }
877- obj = is_method ? obj : NULL ;
952+ PyObject * callable = PyStackRef_AsPyObjectBorrow (method .ref );
953+ PyObject * self_obj = PyStackRef_AsPyObjectBorrow (self .ref );
878954
879955 va_list vargs ;
880956 va_start (vargs , name );
881- PyObject * result = object_vacall (tstate , obj , callable , vargs );
957+ PyObject * result = object_vacall (tstate , self_obj , callable , vargs );
882958 va_end (vargs );
883959
884- Py_DECREF (callable );
960+ _PyThreadState_PopCStackRef (tstate , & method );
961+ _PyThreadState_PopCStackRef (tstate , & self );
885962 return result ;
886963}
887964
0 commit comments