Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-37151: remove special case for PyCFunction from PyObject_Call #14684

Merged
merged 3 commits into from
Sep 11, 2019

Conversation

jdemeyer
Copy link
Contributor

@jdemeyer jdemeyer commented Jul 10, 2019

The function PyObject_Call contains a special case for calling instances of PyCFunction with METH_VARARGS. This is to avoid a double recursion check: cfunction_call_varargs already calls Py_EnterRecursiveCall, so PyObject_Call should not. We can simplify this by removing the recursion check from cfunction_call_varargs and removing the special case from PyObject_Call.

In addition, we fold cfunction_call_varargs into PyCFunction_Call and move it back to Objects/methodobject.c which already contains the vectorcall functions of PyCFunction.

https://bugs.python.org/issue37151

@jdemeyer jdemeyer force-pushed the PyObject_Call_cfunction branch from 567d118 to e0f6c09 Compare July 10, 2019 14:46
@mangrisano
Copy link
Contributor


assert(PyCFunction_GET_FLAGS(func) & METH_VARARGS);
if (PyCFunction_GET_FLAGS(func) & METH_KEYWORDS) {
if (Py_EnterRecursiveCall(" while calling a Python object")) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The recursion check is gone now. Was that intentional? Any reason why you think we don't need it any more?
Since you're dealing with a public C-API function here, I would advise to keep the current semantics.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The recursion check is gone from PyCFunction_Call but it is in PyObject_Call.

Note that PyCFunction_Call is not a documented C API function, so I assumed that this minor change in behaviour (no longer doing the recursion check) would be acceptable.

@vstinner
Copy link
Member

Note that PyCFunction_Call is not a documented C API function, so I assumed that this minor change in behaviour (no longer doing the recursion check) would be acceptable.

That's the kind of function that projects like Cython call directly.

@jdemeyer
Copy link
Contributor Author

That's the kind of function that projects like Cython call directly.

What point are you trying to make? It that just a comment or is it saying something about this PR? Or are you just complaining about Cython? Or is it a joke somehow?

@vstinner
Copy link
Member

I suggest to ensure that any PyCFunction_Call behavior change will not break anything, especially in Cython.

@encukou
Copy link
Member

encukou commented Jul 16, 2019

It is undocumented, so the only documentation available to people who wanted to use this function was the code itself.
It would be OK to remove/rename PyCFunction_Call, if we needed to do that, but I don't think we should subtly change its behavior.

Perhaps CPython could use cfunction_call_varargs internally, and that would have the check removed; PyCFunction_Call could then be a wrapper that does the check?

@jdemeyer
Copy link
Contributor Author

I checked and Cython doesn't use PyCFunction_Call. I'm not sure if that function was ever intended to be public. It's quite special, there are no such functions for other classes. It's not documented. And what's the use case? You can only use PyCFunction_Call if you somehow know in advance that some object is a builtin_function_or_method, which you typically don't know. And if you somehow do know that it's a builtin_function_or_method and care about speed, you will want to use the vectorcall calling convention instead of the slow tp_call convention used by PyCFunction_Call.

@jdemeyer
Copy link
Contributor Author

PyCFunction_Call could then be a wrapper that does the check?

At that point, probably best would be to just alias it to PyObject_Call.

@encukou
Copy link
Member

encukou commented Jul 16, 2019

Right, it's quite useless as public API. Remove it in 3.9. But:

  • Don't keep the same name if the semantics changed.
  • Mention the removal in the news file, so anyone who did use it may know the removal was intentional.

It was probably never intended to be public (and probably predates discussions on what should be public), but it is an exported symbol.

@jdemeyer
Copy link
Contributor Author

We need to keep it for the stable ABI, but that's easily solved by making it an alias of PyObject_Call.

I updated my branch to do this.

@jdemeyer
Copy link
Contributor Author

Added a deprecation for PyCFunction_Call.

@@ -39,7 +39,7 @@ PyAPI_FUNC(int) PyCFunction_GetFlags(PyObject *);
#define PyCFunction_GET_FLAGS(func) \
(((PyCFunctionObject *)func) -> m_ml -> ml_flags)
#endif
PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *);
Py_DEPRECATED(3.9) PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vstinner, is this the right way to deprecate an undocumented part of the stable ABI?

(I'll merge regardless, but I wanted to bring this to your attention.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stable ABI is supposed to remain unchanged :-) "Py_DEPRECATED(3.9) PyAPI_FUNC(PyObject *) PyCFunction_Call" is the right usage of Py_DEPRECATED().

I don't know why PyCFunction_Call "leaked" into the stable ABI. I'm in favor of removing it. Start with a deprecation is a good start ;)

Copy link
Member

@encukou encukou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I'm now comfortable merging this, especially since it's for 3.9.

@encukou encukou merged commit 7a6873c into python:master Sep 11, 2019
DinoV pushed a commit to DinoV/cpython that referenced this pull request Sep 12, 2019
…thonGH-14684)

bpo-37151: remove special case for PyCFunction from PyObject_Call

Alse, make the undocumented function PyCFunction_Call an alias
of PyObject_Call and deprecate it.
websurfer5 pushed a commit to websurfer5/cpython that referenced this pull request Jul 20, 2020
…thonGH-14684)

bpo-37151: remove special case for PyCFunction from PyObject_Call

Alse, make the undocumented function PyCFunction_Call an alias
of PyObject_Call and deprecate it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants