FFI for PEP 590 Vectorcall

https://www.python.org/dev/peps/pep-0590/

This was tested on 3.7 using _PyCFunctionFast and 3.8
using PyObject_Vectorcall. Extending pyo3-derive-backend
to generate code using vectorcall is not done here.

This exposes PyObject_Vectorcall with a link_name to the
underscored name on 3.8 because it is expected to be stabilized
on 3.9.

This fixes the "fast" objects being new in 3.7, not 3.6.
This commit is contained in:
ijl 2019-10-23 21:40:38 +00:00
parent bab05e8135
commit caf4713b3a
3 changed files with 53 additions and 3 deletions

View File

@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## Unreleased
### Added
* FFI compatibility for PEP 590 Vectorcall.
## [0.8.1]
### Added

View File

@ -15,7 +15,39 @@ pub unsafe fn PyCFunction_Check(op: *mut PyObject) -> c_int {
pub type PyCFunction =
unsafe extern "C" fn(slf: *mut PyObject, args: *mut PyObject) -> *mut PyObject;
#[cfg(all(Py_3_6, not(Py_LIMITED_API)))]
#[cfg(all(Py_3_8, not(Py_LIMITED_API)))]
#[cfg_attr(Py_3_8, link_name = "_PyObject_Vectorcall")]
pub type PyObject_Vectorcall = unsafe extern "C" fn(
slf: *mut PyObject,
// positional and keyword arguments
args: *const *mut PyObject,
// number of position arguments in args, after which values are kwargs
nargs: crate::ffi::pyport::Py_ssize_t,
// tuple of kwargs, if given, or null
kwnames: *mut PyObject,
) -> *mut PyObject;
#[cfg(all(Py_3_8, not(Py_LIMITED_API)))]
#[cfg_attr(Py_3_8, link_name = "PyVectorcall_Call")]
pub type PyVectorcall_Call = unsafe extern "C" fn(
obj: *mut PyObject,
tuple: *mut PyObject,
dict: *mut PyObject,
) -> *mut PyObject;
#[cfg(all(Py_3_7, not(Py_LIMITED_API)))]
const PY_VECTORCALL_ARGUMENTS_OFFSET: crate::ffi::pyport::Py_ssize_t =
1 << (8 * std::mem::size_of::<usize>() - 1);
#[cfg(all(Py_3_7, not(Py_LIMITED_API)))]
#[inline(always)]
pub unsafe fn PyVectorcall_NARGS(
n: crate::ffi::pyport::Py_ssize_t,
) -> crate::ffi::pyport::Py_ssize_t {
n & !PY_VECTORCALL_ARGUMENTS_OFFSET
}
#[cfg(all(Py_3_7, not(Py_LIMITED_API)))]
pub type _PyCFunctionFast = unsafe extern "C" fn(
slf: *mut PyObject,
args: *mut *mut PyObject,
@ -102,8 +134,10 @@ slot like sq_contains. */
pub const METH_COEXIST: c_int = 0x0040;
#[cfg(all(Py_3_6, not(Py_LIMITED_API)))]
pub const METHOD_FASTCALL: c_int = 0x0080;
/* METH_FASTCALL indicates the PEP 590 Vectorcall calling format. It may
be specified alone or with METH_KEYWORDS. */
#[cfg(all(Py_3_7, not(Py_LIMITED_API)))]
pub const METH_FASTCALL: c_int = 0x0080;
#[cfg_attr(windows, link(name = "pythonXY"))]
extern "C" {

View File

@ -463,7 +463,10 @@ mod typeobject {
pub tp_basicsize: Py_ssize_t,
pub tp_itemsize: Py_ssize_t,
pub tp_dealloc: Option<object::destructor>,
#[cfg(not(Py_3_8))]
pub tp_print: Option<object::printfunc>,
#[cfg(Py_3_8)]
pub tp_vectorcall_offset: Py_ssize_t,
pub tp_getattr: Option<object::getattrfunc>,
pub tp_setattr: Option<object::setattrfunc>,
pub tp_as_async: *mut PyAsyncMethods,
@ -529,7 +532,10 @@ mod typeobject {
tp_basicsize: 0,
tp_itemsize: 0,
tp_dealloc: None,
#[cfg(not(Py_3_8))]
tp_print: None,
#[cfg(Py_3_8)]
tp_vectorcall_offset: 0,
tp_getattr: None,
tp_setattr: None,
$tp_as_async: ptr::null_mut(),
@ -847,6 +853,10 @@ pub const Py_TPFLAGS_HEAPTYPE: c_ulong = (1 << 9);
/// Set if the type allows subclassing
pub const Py_TPFLAGS_BASETYPE: c_ulong = (1 << 10);
/// Set if the type implements the vectorcall protocol (PEP 590)
#[cfg(all(Py_3_8, not(Py_LIMITED_API)))]
pub const _Py_TPFLAGS_HAVE_VECTORCALL: c_ulong = (1 << 11);
/// Set if the type is 'ready' -- fully initialized
pub const Py_TPFLAGS_READY: c_ulong = (1 << 12);