[Python-Dev] On the METH_FASTCALL calling convention

Serhiy Storchaka storchaka at gmail.com
Sat Jul 7 04:55:22 EDT 2018


05.07.18 17:53, Jeroen Demeyer пише:
> In other words: I see nothing to improve in the calling convention of 
> METH_FASTCALL. I suggest to keep it and make it public as-is.

You have considered the bytecode for calling functions, but this 
actually is not directly related to the calling convention. All opcodes 
(CALL_FUNCTION, CALL_FUNCTION_KW, CALL_FUNCTION_EX and CALL_METHOD) can 
be used for calling any callable. CALL_FUNCTION, CALL_FUNCTION_KW was 
designed for reducing the overhead from the caller side for most common 
cases, and CALL_FUNCTION_EX is used for the rest.

Calling conventions METH_FASTCALL and METH_FASTCALL|METH_KEYWORDS was 
designed for reducing the overhead of creating a temporary tuple and 
dict. They allow to avoid allocation and copying in case of using 
opcodes CALL_FUNCTION, CALL_FUNCTION_KW and in most cases of using C API 
for calling function. But it is not the only possible way, there some 
details can be changed without performance loss, and may be even with a 
gain.

After passing positional and keyword arguments to the C function, we 
need to convert Python objects to C values. For positional-only 
parameters we can use PyArg_ParseTuple() (for METH_VARARGS) and 
_PyArg_ParseStack() (for METH_FASTCALL). If there are keyword 
parameters, we need to use more complicated API: 
PyArg_ParseTupleAndKeywords() or private 
_PyArg_ParseTupleAndKeywordsFast() (for METH_VARARGS|METH_KEYWORDS) and 
private _PyArg_ParseStackAndKeywords() (for 
METH_FASTCALL|METH_KEYWORDS). _PyArg_ParseTupleAndKeywordsFast() and 
_PyArg_ParseStackAndKeywords() are private, complex, unstable and can be 
used only internally in CPython (mostly in the code generated by 
Argument Clinic). They have complex signatures and their code is mostly 
duplicate one other (but with some important differences).

There is a wish of inlining argument parsing functions in the Argument 
Clinic generated code. It is easier to do for PyArg_ParseTuple() and 
_PyArg_UnpackStack(). But functions for parsing keyword arguments are 
more complex, because they perform two things: match keyword argument 
names to parameter positions and convert argument values to C.

There is my idea. Split every of keyword argument parsing functions on 
two parts. The first part linearize keyword arguments, it converts 
positional and keyword arguments (in whatever form they were presented) 
into a linear array of PyObject* (with NULLs for not specified optional 
arguments). The second part is common and similar to 
_PyArg_ParseStack(), but supports NULLs. It converts an array of 
PyObject* to a sequence of C values. I tried to implement this idea, is 
is not simple, and results were mixed, but I don't loss a hope.

And here we return to METH_FASTCALL|METH_KEYWORDS. The first part of 
handling arguments can be made outside of the C function, by the calling 
API. Then the signature of the C function can be simpler, the same as 
for METH_FASTCALL. But we need to expose the list of keyword parameter 
names as an attribute of CFunction.

I don't know whether this ides is vital or dead, but I' going to try it. 
And implementing it will change the METH_FASTCALL|METH_KEYWORDS calling 
convention a lot.



More information about the Python-Dev mailing list