-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Open
Description
Currently, method calls are split into an AttributeNode
for the method lookup and a PyMethodCallNode
for the call (see ExprNodes.py
). Following an optimisation in CPython 3.7 (which brought about a 20% speedup), it would be nice to avoid the generic attribute lookup and replace it with a call to the __Pyx_PyObject_GetMethod()
utility function, which can avoid the instantiation of a bound method object. Instead, the underlying function can be called as unbound method, passing the self
argument explicitly.
Most of the infrastructure is already there, as well as a simpler optimisation in PyMethodCallNode
that should be replaced by this one. Look for usages of the CYTHON_UNPACK_METHODS
feature switch.
Design:
- special-case and separate out the "plain Python attribute" case in
PyMethodCallNode
as follows: - evaluate all arguments in order, but not the argument tuple itself
- for the 0, 1, 2 argument cases, simply call the helper functions
__Pyx_PyObject_CallMethod[012]()
, otherwise: - create a
PyObject*[]
C array with length1+len(args)
- put the attribute owner object in the first index, followed by all arguments (all borrowed references)
- write a call helper function (very similar to the
..._CallMethod()
hepers, but generalised) that accepts the object, the method name, the argument array and the arguments count as input - make it call
__Pyx_PyObject_GetMethod()
to look up the method - make it special case fast-call Py/C-functions as in the current implementation (and like all the
..._CallMethod[012]()
helpers do) - fall back to building a tuple and calling the function
- include the first (
self
) argument in the array only when theGetMethod()
was able to return an unbound (unpacked) method, and exclude it otherwise