[Python-Dev] PEP 590 discussion
Petr Viktorin
pviktori at redhat.com
Wed Apr 10 12:25:57 EDT 2019
Hello!
I've had time for a more thorough reading of PEP 590 and the reference
implementation. Thank you for the work!
Overall, I like PEP 590's direction. I'd now describe the fundamental
difference between PEP 580 and PEP 590 as:
- PEP 580 tries to optimize all existing calling conventions
- PEP 590 tries to optimize (and expose) the most general calling
convention (i.e. fastcall)
PEP 580 also does a number of other things, as listed in PEP 579. But I
think PEP 590 does not block future PEPs for the other items.
On the other hand, PEP 580 has a much more mature implementation -- and
that's where it picked up real-world complexity.
PEP 590's METH_VECTORCALL is designed to handle all existing use cases,
rather than mirroring the existing METH_* varieties.
But both PEPs require the callable's code to be modified, so requiring
it to switch calling conventions shouldn't be a problem.
Jeroen's analysis from
https://mail.python.org/pipermail/python-dev/2018-July/154238.html seems
to miss a step at the top:
a. CALL_FUNCTION* / CALL_METHOD opcode
calls
b. _PyObject_FastCallKeywords()
which calls
c. _PyCFunction_FastCallKeywords()
which calls
d. _PyMethodDef_RawFastCallKeywords()
which calls
e. the actual C function (*ml_meth)()
I think it's more useful to say that both PEPs bridge a->e (via
_Py_VectorCall or PyCCall_Call).
PEP 590 is built on a simple idea, formalizing fastcall. But it is
complicated by PY_VECTORCALL_ARGUMENTS_OFFSET and
Py_TPFLAGS_METHOD_DESCRIPTOR.
As far as I understand, both are there to avoid intermediate
bound-method object for LOAD_METHOD/CALL_METHOD. (They do try to be
general, but I don't see any other use case.)
Is that right?
(I'm running out of time today, but I'll write more on why I'm asking,
and on the case I called "impossible" (while avoiding creation of a
"bound method" object), later.)
The way `const` is handled in the function signatures strikes me as too
fragile for public API.
I'd like if, as much as possible, PY_VECTORCALL_ARGUMENTS_OFFSET was
treated as a special optimization that extension authors can either opt
in to, or blissfully ignore.
That might mean:
- vectorcall, PyObject_VectorCallWithCallable, PyObject_VectorCall,
PyCall_MakeTpCall all formally take "PyObject *const *args"
- a naïve callee must do "nargs &= ~PY_VECTORCALL_ARGUMENTS_OFFSET"
(maybe spelled as "nargs &= PY_VECTORCALL_NARGS_MASK"), but otherwise
writes compiler-enforced const-correct code.
- if PY_VECTORCALL_ARGUMENTS_OFFSET is set, the callee may modify
"args[-1]" (and only that, and after the author has read the docs).
Another point I'd like some discussion on is that vectorcall function
pointer is per-instance. It looks this is only useful for type objects,
but it will add a pointer to every new-style callable object (including
functions). That seems wasteful.
Why not have a per-type pointer, and for types that need it (like
PyTypeObject), make it dispatch to an instance-specific function?
Minor things:
- "Continued prohibition of callable classes as base classes" -- this
section reads as a final. Would you be OK wording this as something
other PEPs can tackle?
- "PyObject_VectorCall" -- this looks extraneous, and the reference
imlementation doesn't need it so far. Can it be removed, or justified?
- METH_VECTORCALL is *not* strictly "equivalent to the currently
undocumented METH_FASTCALL | METH_KEYWORD flags" (it has the
ARGUMENTS_OFFSET complication).
- I'd like to officially call this PEP "Vectorcall", see
https://github.com/python/peps/pull/984
Mark, what are your plans for next steps with PEP 590? If a volunteer
wanted to help you push this forward, what would be the best thing to
work on?
Jeroen, is there something in PEPs 579/580 that PEP 590 blocks, or
should address?
More information about the Python-Dev
mailing list