Faster calling conventions, "hasty call". #374
Replies: 7 comments 3 replies
-
if (!PyLong_Check(a_obj)) {
goto error;
}
if (!PyLong_Check(b_obj)) {
goto error;
} Can these checks be moved into the caller too if it knows and guarantees that |
Beta Was this translation helpful? Give feedback.
-
This is also a goal of HPy, although so far we just discussed it without doing any implementation. This is probably the best summary of our thoughts so far: hpyproject/hpy#129 I think we should coordinate on this. Something to consider is how to encode the C-level signatures and how fast it is to check whether a certain callable supports a certain C-level signature. For JITs, the check can be "slow" (e.g. a I wonder if hasty-calls can be integrated in such a scheme. We could imagine to have a system in which a Python callable can support multiple signatures and calling conventions. In the examble above, the Python function In your proposal, how does a function declares that it supports hasty-calls? Do you also plan to offer a way to do hasty-calls from normal C API code, or it will be used only by JITs? |
Beta Was this translation helpful? Give feedback.
-
Adding self to the discussion so I can follow along. |
Beta Was this translation helpful? Give feedback.
-
I don't see how this would work, but exactly the same information is available to Cython compiled code as to the VM, so maybe they can come up with something.
With a flag.
C call can call the the hasty call function pointer, but they caller is responsible for ensuring the arguments are in the correct order, which is tricky unless you know exactly which method you are calling in advance. In which case you might as well call the lower level C function directly. |
Beta Was this translation helpful? Give feedback.
-
Is the plan for a JIT to be able to avoid boxing and unboxing objects when calling Python methods backed by C implementations at some point in the future? |
Beta Was this translation helpful? Give feedback.
-
I should probably elaborate on what a builtin function object supporting "hasty" call would look like in CPython. First of all it would have set the char **parameter_names;
PyObject *parameter_names_object; /* Should be set to NULL, will be patched by the VM */
uint8_t total_parameter;
uint8_t positional_only_arguments;
uint8_t keyword_only_arguments;
uint8_t default_values;
uint8_t defaults[1]; /* Index into a table of "simple" values, like `None`, `0`, etc, or `NULL`. Default values that are not "simple", will be need to handled by setting the default value to We could also add, in future, these fields for JITs: funcptr low_level_func; /* The low-level C function */
char *low_level_desc /* String describing the low-level function's types */ |
Beta Was this translation helpful? Give feedback.
-
FWIW Cinder has something like what you describe as "in the future for JITs" for builtin functions, except that the typed signature description is structured, not a string (https://github.com/facebookincubator/cinder/blob/cinder/3.8/Include/methodobject.h#L111). We use this for fast calls to builtin functions from Static Python, where we can ensure in advance that the argument types are all correct. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Cffi and argument clinic take a typed description of the arguments to a function and a low-level implementation that does no dispatch, typechecking or unboxing.
Ultimately we want to be able to call directly into those low-level functions from JIT compiled code.
With that ultimate goal in mind, we also want an intermediate calling convention suitable for calling from a specializing interpreter.
Nicknamed "hasty call" as nod to "fast call", this calling convention would leave parsing, checking and re-ordering the arguments to the caller.
The callable object would be need to provide the "hasty" function pointer and a signature to enable validation and argument reordering.
For example, consider a function with the Python signature
foo(a:int, b:int, *, c:Any=None)->None
with the underlying C implementation signature
void foo_impl(Py_ssize_t a, Py_ssize_t b, PyObject *c)
.The "hasty call" signature for
foo
would bePyObject *foo_hasty(PyObject *func, PyObject *args[3])
It will be up to the caller to reorder arguments and fill in defaults, so that if we call
foo(b=1, a=0)
the VM would swap
a
andb
and pushNone
, before calling the C functionfoo_hasty
.It will be up to the tooling, whether cffi, argument clinic or something else, to create
foo_hasty
, which in this case would look something like:The tooling will also need to create the
vectorcall
form to handle argument parsing when called fromunspecialized code or from other C extensions.
Beta Was this translation helpful? Give feedback.
All reactions