-
-
Notifications
You must be signed in to change notification settings - Fork 53
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
Calling Python functions from HPy #122
Comments
@mattip kindly grep'ed pandas, scipy and numpy for us to see which calling conventions they use. The full results are at https://paste.ubuntu.com/p/3xs6dC5Gy9/. The summary is that the most frequent calls are PyObject_Call, PyObject_CallObject, PyObject_CallMethod, PyObject_CallFunctionObjArgs. |
|
Some random considerations:
|
I've opened PR #122 to implement HPy_Call, HPy_CallObject and HPyCallable_Check. Once that lands, the plan is to write two new issues for:
and summarize what is left to do in each of those. We don't have an urgent need for either of those, so hopefully we can defer implementing them until after other things (e.g. the numpy port might suggest which other calling options are needed). |
FWIW, the link in the pastebin is expired. Maybe for the future we should avoid using it in the issues. |
Update as of 2021-11-29. In the meantime, we merged #147 and we added In the meantime, #251 aims to introduce an API to call functions by passing arguments as a C array of I think that this should be the "blessed" and fastest calling API. I propose to just call it I also think that it should closely match the signature of our
Moreover, I think we should think more about how to play nicely with
We should investigate whether we want to change Another question is what to do with HPy args[] = {....};
HPy result = HPy_CallMethod(ctx, myobj, "method_name", args, nargs}; However, HPy args[] = {myobj, ...};
HPy result = HPy_CallMethod(ctx, "method_name", args, nargs); I think this is a bit uglier from the API point of view, but it allows a more efficient implementation on CPython because we can implement Final point to consider: PEP 590/Vectorcall support a special flag called def foo(self, *args, **kwargs):
return some_other_obj.bar(*args, **kwargs) So we need to decide whether it is something which we want to support as well. I couldn't find any real world usage so it's a bit hard to judge at the moment. To summarize, I propose the following plan (but feel free to disagree and/or amend the proposal):
HPy HPy_Call(HPy callable, HPy args[], HPy_ssize_t nargs, HPy kwnames); // ==> PyObject_VectorCall
HPy HPy_CallDict(HPy callable, HPy args[], HPy_ssize_t nargs, HPy kwdict); // ==> PyObject_VectorCallDict
HPy HPy_CallMethod(HPy name, HPy args[], HPy_ssize_t nargs, HPy kwdict); // ==> PyObject_VectorCallMethod
HPy HPy_CallMethod_s(const char *s, HPy args[], HPy_ssize_t nargs, HPy kwnames);
Points 1 and 2 should be done together. Point 3 can be done separately, probably by updating #251. |
This seems reasonable. I think one of the design goals should be to do whatever is fastest on CPython, if it doesn't cause too many problems for the other interpreters, . |
1, 2 & 4 sound good to me. I'm not sure what postponing the decision about I'm happy with the call methods listed in 3. |
It means that for now we just ignore it. From the CPython point of view, Maybe we should just ask @markshannon who is the author of the PEP.
|
It seems to me that the use case is that when you're allocating the args array, you prepend a NULL (or anything else that you happen to have there) then pass in this flag. If the callable is a method, it then doesn't have to allocate & copy the args array to add on the function. Here's a use in ceval.c when a with statement calls PyObject *stack[4] = {NULL, exc, val, tb};
res = PyObject_Vectorcall(exit_func, stack + 1,
3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); So if you wanted to take advantage of this, one way would be to say have an API where the first element of the array is the callable, then the callee can temporarily swap that out. |
We need to pick some APIs to provide for calling Python functions from HPy.
The existing C API has a large zoo of methods for making functions calls. The zoo is documented at https://docs.python.org/3/c-api/call.html#object-calling-api.
Under the hood there are two main calling conventions --
tp_call
andvectorcall
. I propose that we largely ignore these and instead focus on what fits well with the Python language syntax and what is convenient to call from C.Most Pythonic
Of the zoo,
PyObject_Call
most clearly matches a genericf(*args, **kw)
in Python, and I propose that we adapt is as follows for HPy:Note that this differs from
PyObject_Call
in thatargs
may beNULL
. I'm not sure why this was a requirement in the existing API.A some point in the future we might want to implement Py_BuildValue to allow tuples of C values to be constructed easily (and maybe even something similar for easily constructing dictionaries from C values).
Most C-like (Most Scenic? :)
PyObject_VectorcallDict
closely matches the signature we chose forHPyFunc_KEYWORDS
methods, but while this is convenient for receiving arguments from Python, I'm not convinced it's a great fit for calling Python functions from C because one has to construct a dictionary of keyword arguments.PyObject_Vectorcall
takes only the names of the keyword arguments (as a tuple), which seems slightly more convenient.All of the vectorcall methods have the strange behaviour that
nargs
also functions as a flag selecting whetherargs[-1]
(orargs[0]
forPyObject_VectorcallMethod
) may temporarily be overwritten by the called function. I propose that we ensure we do NOT copy this behaviour.The best suggestion I have at the moment for a convenient C-like calling convention is:
I'm uncertain whether this is to big a departure from existing APIs or whether there are better options.
Other considerations
HPyCallable_Check
at the same time.HPy_CallMethod
andHPy_CallMethodArray
, but I propose that we decide on these first and then ensure those match later.The text was updated successfully, but these errors were encountered: