@@ -612,18 +612,66 @@ _PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...)
612612}
613613
614614
615- static PyObject *
616- callmethod (PyThreadState * tstate , PyObject * callable , const char * format , va_list va )
615+ /* Resolve 'name' on 'obj' with _PyObject_GetMethod and call it directly,
616+ avoiding the bound-method object that PyObject_GetAttr()+call would allocate. */
617+ static PyObject *
618+ callmethod_va (PyObject * obj , PyObject * name ,
619+ const char * format , va_list va )
617620{
618- assert (callable != NULL );
619- if (!PyCallable_Check (callable )) {
621+ PyThreadState * tstate = _PyThreadState_GET ();
622+
623+ PyObject * method = NULL ;
624+ /* unbound: 1 -> 'method' is an unbound function, call method(obj, *args);
625+ 0 -> 'method' is the resolved attribute, call method(*args). */
626+ int unbound = _PyObject_GetMethod (obj , name , & method );
627+ if (method == NULL ) {
628+ return NULL ;
629+ }
630+ if (!PyCallable_Check (method )) {
620631 _PyErr_Format (tstate , PyExc_TypeError ,
621632 "attribute of type '%.200s' is not callable" ,
622- Py_TYPE (callable )-> tp_name );
633+ Py_TYPE (method )-> tp_name );
634+ Py_DECREF (method );
623635 return NULL ;
624636 }
625637
626- return _PyObject_CallFunctionVa (tstate , callable , format , va );
638+ /* Build the positional arguments from the format string. */
639+ PyObject * small_stack [_PY_FASTCALL_SMALL_STACK ];
640+ Py_ssize_t nargs = 0 ;
641+ PyObject * * built = NULL ;
642+ if (format != NULL && * format != '\0' ) {
643+ built = _Py_VaBuildStack (small_stack , _PY_FASTCALL_SMALL_STACK ,
644+ format , va , & nargs );
645+ if (built == NULL ) {
646+ Py_DECREF (method );
647+ return NULL ;
648+ }
649+ }
650+
651+ /* Backward compat: a single tuple from "O" is unpacked. */
652+ PyObject * const * args = built ;
653+ Py_ssize_t n = nargs ;
654+ if (nargs == 1 && PyTuple_Check (built [0 ])) {
655+ args = _PyTuple_ITEMS (built [0 ]);
656+ n = PyTuple_GET_SIZE (built [0 ]);
657+ }
658+
659+ PyObject * result ;
660+ if (unbound ) {
661+ result = _PyObject_VectorcallPrepend (tstate , method , obj , args , n , NULL );
662+ }
663+ else {
664+ result = _PyObject_VectorcallTstate (tstate , method , args , n , NULL );
665+ }
666+
667+ for (Py_ssize_t i = 0 ; i < nargs ; i ++ ) {
668+ Py_DECREF (built [i ]);
669+ }
670+ if (built != NULL && built != small_stack ) {
671+ PyMem_Free (built );
672+ }
673+ Py_DECREF (method );
674+ return result ;
627675}
628676
629677PyObject *
@@ -635,17 +683,17 @@ PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...)
635683 return null_error (tstate );
636684 }
637685
638- PyObject * callable = PyObject_GetAttrString ( obj , name );
639- if (callable == NULL ) {
686+ PyObject * name_obj = PyUnicode_FromString ( name );
687+ if (name_obj == NULL ) {
640688 return NULL ;
641689 }
642690
643691 va_list va ;
644692 va_start (va , format );
645- PyObject * retval = callmethod ( tstate , callable , format , va );
693+ PyObject * retval = callmethod_va ( obj , name_obj , format , va );
646694 va_end (va );
647695
648- Py_DECREF (callable );
696+ Py_DECREF (name_obj );
649697 return retval ;
650698}
651699
@@ -660,17 +708,17 @@ PyEval_CallMethod(PyObject *obj, const char *name, const char *format, ...)
660708 return null_error (tstate );
661709 }
662710
663- PyObject * callable = PyObject_GetAttrString ( obj , name );
664- if (callable == NULL ) {
711+ PyObject * name_obj = PyUnicode_FromString ( name );
712+ if (name_obj == NULL ) {
665713 return NULL ;
666714 }
667715
668716 va_list va ;
669717 va_start (va , format );
670- PyObject * retval = callmethod ( tstate , callable , format , va );
718+ PyObject * retval = callmethod_va ( obj , name_obj , format , va );
671719 va_end (va );
672720
673- Py_DECREF (callable );
721+ Py_DECREF (name_obj );
674722 return retval ;
675723}
676724
@@ -684,17 +732,11 @@ _PyObject_CallMethod(PyObject *obj, PyObject *name,
684732 return null_error (tstate );
685733 }
686734
687- PyObject * callable = PyObject_GetAttr (obj , name );
688- if (callable == NULL ) {
689- return NULL ;
690- }
691-
692735 va_list va ;
693736 va_start (va , format );
694- PyObject * retval = callmethod ( tstate , callable , format , va );
737+ PyObject * retval = callmethod_va ( obj , name , format , va );
695738 va_end (va );
696739
697- Py_DECREF (callable );
698740 return retval ;
699741}
700742
@@ -710,30 +752,17 @@ _PyObject_CallMethodId(PyObject *obj, _Py_Identifier *name,
710752
711753_Py_COMP_DIAG_PUSH
712754_Py_COMP_DIAG_IGNORE_DEPR_DECLS
713- PyObject * callable = _PyObject_GetAttrId ( obj , name );
755+ PyObject * name_obj = _PyUnicode_FromId ( name ); /* borrowed */
714756_Py_COMP_DIAG_POP
715- if (callable == NULL) {
757+ if (name_obj == NULL) {
716758 return NULL ;
717759 }
718760
719761 va_list va ;
720762 va_start (va , format );
721- PyObject * retval = callmethod ( tstate , callable , format , va );
763+ PyObject * retval = callmethod_va ( obj , name_obj , format , va );
722764 va_end (va );
723765
724- Py_DECREF (callable );
725- return retval ;
726- }
727-
728-
729- PyObject * _PyObject_CallMethodFormat (PyThreadState * tstate , PyObject * callable ,
730- const char * format , ...)
731- {
732- assert (callable != NULL );
733- va_list va ;
734- va_start (va , format );
735- PyObject * retval = callmethod (tstate , callable , format , va );
736- va_end (va );
737766 return retval ;
738767}
739768
@@ -749,17 +778,17 @@ _PyObject_CallMethod_SizeT(PyObject *obj, const char *name,
749778 return null_error (tstate );
750779 }
751780
752- PyObject * callable = PyObject_GetAttrString ( obj , name );
753- if (callable == NULL ) {
781+ PyObject * name_obj = PyUnicode_FromString ( name );
782+ if (name_obj == NULL ) {
754783 return NULL ;
755784 }
756785
757786 va_list va ;
758787 va_start (va , format );
759- PyObject * retval = callmethod ( tstate , callable , format , va );
788+ PyObject * retval = callmethod_va ( obj , name_obj , format , va );
760789 va_end (va );
761790
762- Py_DECREF (callable );
791+ Py_DECREF (name_obj );
763792 return retval ;
764793}
765794
0 commit comments