gh-151157: Speed up PyObject_CallMethod via _PyObject_GetMethod (#151158)
* Speed up PyObject_CallMethod via _PyObject_GetMethod
PyObject_CallMethod (and _PyObject_CallMethod, PyEval_CallMethod,
_PyObject_CallMethodId and the _SizeT variant) resolved the method with
PyObject_GetAttr, which builds a temporary bound-method object on every call,
then called it.
Resolve the method with _PyObject_GetMethod instead (the same lookup the
interpreter uses for obj.name(...)) and call it directly via
_PyObject_VectorcallPrepend, skipping the bound-method allocation. Behaviour
is unchanged: same attribute semantics, same "attribute of type ... is not
callable" error, and the historical
PyObject_CallMethod(o, m, "O", tuple) -> o.m(*tuple) unpacking.
The shared helper callmethod() and _PyObject_CallMethodFormat() are no longer
needed: their only caller (traceback.c) now uses PyObject_CallFunction, so both
are removed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Use _PyObject_GetMethodStackRef so method calls scale in free-threading
Resolve the method in callmethod_va() via _PyObject_GetMethodStackRef()
instead of _PyObject_GetMethod(). The StackRef variant returns the method
as a deferred reference, avoiding the per-call atomic refcount on the
shared method object that otherwise serializes threads in the
free-threaded build.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* rename to callmethod
* review comments
* review comments
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Kumar Aditya <kumaraditya@python.org>
Co-authored-by: Inada Naoki <songofacandy@gmail.com>
3 files changed