@@ -828,6 +828,60 @@ object_vacall(PyThreadState *tstate, PyObject *base,
828828 return result ;
829829}
830830
831+ PyObject *
832+ _PyObject_VectorcallPrepend (PyThreadState * tstate , PyObject * callable ,
833+ PyObject * arg , PyObject * const * args ,
834+ size_t nargsf , PyObject * kwnames )
835+ {
836+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
837+ assert (nargs == 0 || args [nargs - 1 ]);
838+
839+ PyObject * result ;
840+ if (nargsf & PY_VECTORCALL_ARGUMENTS_OFFSET ) {
841+ /* PY_VECTORCALL_ARGUMENTS_OFFSET is set, so we are allowed to mutate the vector */
842+ PyObject * * newargs = (PyObject * * )args - 1 ;
843+ nargs += 1 ;
844+ PyObject * tmp = newargs [0 ];
845+ newargs [0 ] = arg ;
846+ assert (newargs [nargs - 1 ]);
847+ result = _PyObject_VectorcallTstate (tstate , callable , newargs ,
848+ nargs , kwnames );
849+ newargs [0 ] = tmp ;
850+ }
851+ else {
852+ Py_ssize_t nkwargs = (kwnames == NULL ) ? 0 : PyTuple_GET_SIZE (kwnames );
853+ Py_ssize_t totalargs = nargs + nkwargs ;
854+ if (totalargs == 0 ) {
855+ return _PyObject_VectorcallTstate (tstate , callable , & arg , 1 , NULL );
856+ }
857+
858+ PyObject * newargs_stack [_PY_FASTCALL_SMALL_STACK ];
859+ PyObject * * newargs ;
860+ if (totalargs <= (Py_ssize_t )Py_ARRAY_LENGTH (newargs_stack ) - 1 ) {
861+ newargs = newargs_stack ;
862+ }
863+ else {
864+ newargs = PyMem_Malloc ((totalargs + 1 ) * sizeof (PyObject * ));
865+ if (newargs == NULL ) {
866+ _PyErr_NoMemory (tstate );
867+ return NULL ;
868+ }
869+ }
870+ /* use borrowed references */
871+ newargs [0 ] = arg ;
872+ /* bpo-37138: since totalargs > 0, it's impossible that args is NULL.
873+ * We need this, since calling memcpy() with a NULL pointer is
874+ * undefined behaviour. */
875+ assert (args != NULL );
876+ memcpy (newargs + 1 , args , totalargs * sizeof (PyObject * ));
877+ result = _PyObject_VectorcallTstate (tstate , callable ,
878+ newargs , nargs + 1 , kwnames );
879+ if (newargs != newargs_stack ) {
880+ PyMem_Free (newargs );
881+ }
882+ }
883+ return result ;
884+ }
831885
832886PyObject *
833887PyObject_VectorcallMethod (PyObject * name , PyObject * const * args ,
@@ -838,31 +892,44 @@ PyObject_VectorcallMethod(PyObject *name, PyObject *const *args,
838892 assert (PyVectorcall_NARGS (nargsf ) >= 1 );
839893
840894 PyThreadState * tstate = _PyThreadState_GET ();
841- _PyCStackRef method ;
895+ _PyCStackRef self , method ;
896+ _PyThreadState_PushCStackRef (tstate , & self );
842897 _PyThreadState_PushCStackRef (tstate , & method );
843898 /* Use args[0] as "self" argument */
844- int unbound = _PyObject_GetMethodStackRef (tstate , args [0 ], name , & method .ref );
845- if (PyStackRef_IsNull (method .ref )) {
899+ self .ref = PyStackRef_FromPyObjectBorrow (args [0 ]);
900+ int unbound = _PyObject_GetMethodStackRef (tstate , & self .ref , name , & method .ref );
901+ if (unbound < 0 ) {
846902 _PyThreadState_PopCStackRef (tstate , & method );
903+ _PyThreadState_PopCStackRef (tstate , & self );
847904 return NULL ;
848905 }
906+
849907 PyObject * callable = PyStackRef_AsPyObjectBorrow (method .ref );
908+ PyObject * self_obj = PyStackRef_AsPyObjectBorrow (self .ref );
909+ PyObject * result ;
850910
851- if (unbound ) {
911+ EVAL_CALL_STAT_INC_IF_FUNCTION (EVAL_CALL_METHOD , callable );
912+ if (self_obj == NULL ) {
913+ /* Skip "self". We can keep PY_VECTORCALL_ARGUMENTS_OFFSET since
914+ * args[-1] in the onward call is args[0] here. */
915+ result = _PyObject_VectorcallTstate (tstate , callable ,
916+ args + 1 , nargsf - 1 , kwnames );
917+ }
918+ else if (self_obj == args [0 ]) {
852919 /* We must remove PY_VECTORCALL_ARGUMENTS_OFFSET since
853920 * that would be interpreted as allowing to change args[-1] */
854- nargsf &= ~PY_VECTORCALL_ARGUMENTS_OFFSET ;
921+ result = _PyObject_VectorcallTstate (tstate , callable , args ,
922+ nargsf & ~PY_VECTORCALL_ARGUMENTS_OFFSET ,
923+ kwnames );
855924 }
856925 else {
857- /* Skip "self". We can keep PY_VECTORCALL_ARGUMENTS_OFFSET since
858- * args[-1] in the onward call is args[0] here . */
859- args ++ ;
860- nargsf -- ;
926+ /* classmethod: self_obj is the type, not args[0]. Replace
927+ * args[0] with self_obj and call the underlying callable . */
928+ result = _PyObject_VectorcallPrepend ( tstate , callable , self_obj ,
929+ args + 1 , nargsf - 1 , kwnames ) ;
861930 }
862- EVAL_CALL_STAT_INC_IF_FUNCTION (EVAL_CALL_METHOD , callable );
863- PyObject * result = _PyObject_VectorcallTstate (tstate , callable ,
864- args , nargsf , kwnames );
865931 _PyThreadState_PopCStackRef (tstate , & method );
932+ _PyThreadState_PopCStackRef (tstate , & self );
866933 return result ;
867934}
868935
@@ -875,22 +942,26 @@ PyObject_CallMethodObjArgs(PyObject *obj, PyObject *name, ...)
875942 return null_error (tstate );
876943 }
877944
878- _PyCStackRef method ;
945+ _PyCStackRef self , method ;
946+ _PyThreadState_PushCStackRef (tstate , & self );
879947 _PyThreadState_PushCStackRef (tstate , & method );
880- int is_method = _PyObject_GetMethodStackRef (tstate , obj , name , & method .ref );
881- if (PyStackRef_IsNull (method .ref )) {
948+ self .ref = PyStackRef_FromPyObjectBorrow (obj );
949+ int res = _PyObject_GetMethodStackRef (tstate , & self .ref , name , & method .ref );
950+ if (res < 0 ) {
882951 _PyThreadState_PopCStackRef (tstate , & method );
952+ _PyThreadState_PopCStackRef (tstate , & self );
883953 return NULL ;
884954 }
885955 PyObject * callable = PyStackRef_AsPyObjectBorrow (method .ref );
886- obj = is_method ? obj : NULL ;
956+ PyObject * self_obj = PyStackRef_AsPyObjectBorrow ( self . ref ) ;
887957
888958 va_list vargs ;
889959 va_start (vargs , name );
890- PyObject * result = object_vacall (tstate , obj , callable , vargs );
960+ PyObject * result = object_vacall (tstate , self_obj , callable , vargs );
891961 va_end (vargs );
892962
893963 _PyThreadState_PopCStackRef (tstate , & method );
964+ _PyThreadState_PopCStackRef (tstate , & self );
894965 return result ;
895966}
896967
0 commit comments