diff --git a/newsfragments/5942.added.md b/newsfragments/5942.added.md new file mode 100644 index 00000000000..ca170d67e23 --- /dev/null +++ b/newsfragments/5942.added.md @@ -0,0 +1 @@ +Add FFI definitions `PyObject_GetAIter`, `PyAIter_Check`, `PyMapping_HasKeyWithError`, `PyMapping_HasKeyStringWithError`, `PyMapping_GetOptionalItem`, `PyMapping_GetOptionalItemString`, `PySequence_ITEM`, `PySequence_Fast_GET_SIZE`, `PySequence_Fast_GET_ITEM`, and `PySequence_Fast_ITEMS`. diff --git a/newsfragments/5942.removed.md b/newsfragments/5942.removed.md new file mode 100644 index 00000000000..a041c333801 --- /dev/null +++ b/newsfragments/5942.removed.md @@ -0,0 +1,3 @@ +Remove private FFI definitions `_PyStack_AsDict`, `_PyObject_CallNoArg`, `_PyObject_FastCall`, `_PyObject_FastCallTstate`. `_PyObject_VectorcallTstate`, `_PyObject_MakeTpCall`, `_Py_CheckFunctionResult`, `_PyObject_CallFunction_SizeT`, `_PyObject_CallMethod_SizeT`, and `_PySequence_IterSearch`. + +Remove FFI definitions `PY_ITERSEARCH_COUNT`, `PY_ITERSEARCH_INDEX`, and `PY_ITERSEARCH_CONTAINS`. diff --git a/pyo3-ffi/src/abstract_.rs b/pyo3-ffi/src/abstract_.rs index 714e6d0d3f0..c2b141b0c6e 100644 --- a/pyo3-ffi/src/abstract_.rs +++ b/pyo3-ffi/src/abstract_.rs @@ -54,21 +54,13 @@ extern_libpython! { ... ) -> *mut PyObject; - #[cfg(not(Py_3_13))] + #[cfg(all(PyPy, not(Py_3_13)))] // called internally in PyUnicodeDecodeError_Create on PyPy #[cfg_attr(PyPy, link_name = "_PyPyObject_CallFunction_SizeT")] - pub fn _PyObject_CallFunction_SizeT( + pub(crate) fn _PyObject_CallFunction_SizeT( callable_object: *mut PyObject, format: *const c_char, ... ) -> *mut PyObject; - #[cfg(not(Py_3_13))] - #[cfg_attr(PyPy, link_name = "_PyPyObject_CallMethod_SizeT")] - pub fn _PyObject_CallMethod_SizeT( - o: *mut PyObject, - method: *const c_char, - format: *const c_char, - ... - ) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyObject_CallFunctionObjArgs")] pub fn PyObject_CallFunctionObjArgs(callable: *mut PyObject, ...) -> *mut PyObject; @@ -78,10 +70,24 @@ extern_libpython! { method: *mut PyObject, ... ) -> *mut PyObject; + + #[cfg(all(Py_3_12, Py_LIMITED_API))] // is an inline function in cpython/abstract.rs on version-specific ABI + #[cfg_attr(PyPy, link_name = "PyPyVectorcall_NARGS")] + pub fn PyVectorcall_NARGS(nargsf: size_t) -> Py_ssize_t; + + #[cfg_attr(not(any(Py_3_12, PyPy)), link_name = "_PyVectorcall_Call")] // symbol made public in 3.12 + #[cfg_attr(PyPy, link_name = "PyPyVectorcall_Call")] + pub fn PyVectorcall_Call( + callable: *mut PyObject, + tuple: *mut PyObject, + dict: *mut PyObject, + ) -> *mut PyObject; } + #[cfg(any(Py_3_12, not(Py_LIMITED_API)))] -pub const PY_VECTORCALL_ARGUMENTS_OFFSET: size_t = - 1 << (8 * std::mem::size_of::() as size_t - 1); +pub const PY_VECTORCALL_ARGUMENTS_OFFSET: size_t = (1 as size_t) + .checked_shl((8 * std::mem::size_of::() - 1) as u32) + .expect("size_t should fit the flag bits"); extern_libpython! { #[cfg_attr(PyPy, link_name = "PyPyObject_Vectorcall")] @@ -104,14 +110,12 @@ extern_libpython! { pub fn PyObject_Type(o: *mut PyObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyObject_Size")] pub fn PyObject_Size(o: *mut PyObject) -> Py_ssize_t; -} -#[inline] -pub unsafe fn PyObject_Length(o: *mut PyObject) -> Py_ssize_t { - PyObject_Size(o) -} + // PyObject_Length is a direct alias for PyObject_Size + #[cfg_attr(not(PyPy), link_name = "PyObject_Size")] + #[cfg_attr(PyPy, link_name = "PyPyObject_Size")] + pub fn PyObject_Length(o: *mut PyObject) -> Py_ssize_t; -extern_libpython! { #[cfg_attr(PyPy, link_name = "PyPyObject_GetItem")] pub fn PyObject_GetItem(o: *mut PyObject, key: *mut PyObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyObject_SetItem")] @@ -120,18 +124,20 @@ extern_libpython! { pub fn PyObject_DelItemString(o: *mut PyObject, key: *const c_char) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyObject_DelItem")] pub fn PyObject_DelItem(o: *mut PyObject, key: *mut PyObject) -> c_int; -} -extern_libpython! { #[cfg_attr(PyPy, link_name = "PyPyObject_Format")] pub fn PyObject_Format(obj: *mut PyObject, format_spec: *mut PyObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyObject_GetIter")] pub fn PyObject_GetIter(arg1: *mut PyObject) -> *mut PyObject; -} + #[cfg(Py_3_10)] + #[cfg_attr(PyPy, link_name = "PyPyObject_GetAIter")] + pub fn PyObject_GetAIter(arg1: *mut PyObject) -> *mut PyObject; -extern_libpython! { #[cfg_attr(PyPy, link_name = "PyPyIter_Check")] pub fn PyIter_Check(obj: *mut PyObject) -> c_int; + #[cfg(Py_3_10)] + #[cfg_attr(PyPy, link_name = "PyPyAIter_Check")] + pub fn PyAIter_Check(obj: *mut PyObject) -> c_int; #[cfg(Py_3_14)] #[cfg_attr(PyPy, link_name = "PyPyIter_NextItem")] @@ -185,20 +191,8 @@ extern_libpython! { pub fn PyNumber_Xor(o1: *mut PyObject, o2: *mut PyObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyNumber_Or")] pub fn PyNumber_Or(o1: *mut PyObject, o2: *mut PyObject) -> *mut PyObject; -} - -// Defined as this macro in Python limited API, but relies on -// non-limited PyTypeObject. Don't expose this since it cannot be used. -#[cfg(not(any(Py_LIMITED_API, PyPy)))] -#[inline] -pub unsafe fn PyIndex_Check(o: *mut PyObject) -> c_int { - let tp_as_number = (*Py_TYPE(o)).tp_as_number; - (!tp_as_number.is_null() && (*tp_as_number).nb_index.is_some()) as c_int -} -extern_libpython! { - #[cfg(any(Py_LIMITED_API, PyPy))] - #[link_name = "PyPyIndex_Check"] + #[cfg_attr(PyPy, link_name = "PyPyIndex_Check")] pub fn PyIndex_Check(o: *mut PyObject) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyNumber_Index")] @@ -246,18 +240,11 @@ extern_libpython! { #[cfg_attr(PyPy, link_name = "PyPySequence_Size")] pub fn PySequence_Size(o: *mut PyObject) -> Py_ssize_t; - #[cfg(PyPy)] - #[link_name = "PyPySequence_Length"] + // PySequence_Length is a direct alias for PySequence_Size + #[cfg_attr(not(PyPy), link_name = "PySequence_Size")] + #[cfg_attr(PyPy, link_name = "PyPySequence_Size")] pub fn PySequence_Length(o: *mut PyObject) -> Py_ssize_t; -} -#[inline] -#[cfg(not(PyPy))] -pub unsafe fn PySequence_Length(o: *mut PyObject) -> Py_ssize_t { - PySequence_Size(o) -} - -extern_libpython! { #[cfg_attr(PyPy, link_name = "PyPySequence_Concat")] pub fn PySequence_Concat(o1: *mut PyObject, o2: *mut PyObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPySequence_Repeat")] @@ -285,20 +272,15 @@ extern_libpython! { pub fn PySequence_List(o: *mut PyObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPySequence_Fast")] pub fn PySequence_Fast(o: *mut PyObject, m: *const c_char) -> *mut PyObject; - // skipped PySequence_Fast_GET_SIZE - // skipped PySequence_Fast_GET_ITEM - // skipped PySequence_Fast_GET_ITEMS pub fn PySequence_Count(o: *mut PyObject, value: *mut PyObject) -> Py_ssize_t; #[cfg_attr(PyPy, link_name = "PyPySequence_Contains")] pub fn PySequence_Contains(seq: *mut PyObject, ob: *mut PyObject) -> c_int; -} -#[inline] -pub unsafe fn PySequence_In(o: *mut PyObject, value: *mut PyObject) -> c_int { - PySequence_Contains(o, value) -} + // PySequence_In is a direct alias for PySequence_Contains + #[cfg_attr(not(PyPy), link_name = "PySequence_Contains")] + #[cfg_attr(PyPy, link_name = "PyPySequence_Contains")] + pub fn PySequence_In(o: *mut PyObject, value: *mut PyObject) -> c_int; -extern_libpython! { #[cfg_attr(PyPy, link_name = "PyPySequence_Index")] pub fn PySequence_Index(o: *mut PyObject, value: *mut PyObject) -> Py_ssize_t; #[cfg_attr(PyPy, link_name = "PyPySequence_InPlaceConcat")] @@ -310,17 +292,12 @@ extern_libpython! { #[cfg_attr(PyPy, link_name = "PyPyMapping_Size")] pub fn PyMapping_Size(o: *mut PyObject) -> Py_ssize_t; - #[cfg(PyPy)] - #[link_name = "PyPyMapping_Length"] + // PyMapping_Length is a direct alias for PyMapping_Size + #[cfg_attr(not(PyPy), link_name = "PyMapping_Size")] + #[cfg_attr(PyPy, link_name = "PyPyMapping_Size")] pub fn PyMapping_Length(o: *mut PyObject) -> Py_ssize_t; } -#[inline] -#[cfg(not(PyPy))] -pub unsafe fn PyMapping_Length(o: *mut PyObject) -> Py_ssize_t { - PyMapping_Size(o) -} - #[inline] pub unsafe fn PyMapping_DelItemString(o: *mut PyObject, key: *mut c_char) -> c_int { PyObject_DelItemString(o, key) @@ -336,6 +313,12 @@ extern_libpython! { pub fn PyMapping_HasKeyString(o: *mut PyObject, key: *const c_char) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyMapping_HasKey")] pub fn PyMapping_HasKey(o: *mut PyObject, key: *mut PyObject) -> c_int; + #[cfg(Py_3_13)] + #[cfg_attr(PyPy, link_name = "PyPyMapping_HasKeyWithError")] + pub fn PyMapping_HasKeyWithError(o: *mut PyObject, key: *mut PyObject) -> c_int; + #[cfg(Py_3_13)] + #[cfg_attr(PyPy, link_name = "PyPyMapping_HasKeyStringWithError")] + pub fn PyMapping_HasKeyStringWithError(o: *mut PyObject, key: *const c_char) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyMapping_Keys")] pub fn PyMapping_Keys(o: *mut PyObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyMapping_Values")] @@ -344,6 +327,20 @@ extern_libpython! { pub fn PyMapping_Items(o: *mut PyObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyMapping_GetItemString")] pub fn PyMapping_GetItemString(o: *mut PyObject, key: *const c_char) -> *mut PyObject; + #[cfg(Py_3_13)] + #[cfg_attr(PyPy, link_name = "PyPyMapping_GetOptionalItem")] + pub fn PyMapping_GetOptionalItem( + o: *mut PyObject, + key: *mut PyObject, + result: *mut *mut PyObject, + ) -> c_int; + #[cfg(Py_3_13)] + #[cfg_attr(PyPy, link_name = "PyPyMapping_GetOptionalItemString")] + pub fn PyMapping_GetOptionalItemString( + o: *mut PyObject, + key: *const c_char, + result: *mut *mut PyObject, + ) -> c_int; #[cfg_attr(PyPy, link_name = "PyPyMapping_SetItemString")] pub fn PyMapping_SetItemString( o: *mut PyObject, diff --git a/pyo3-ffi/src/cpython/abstract_.rs b/pyo3-ffi/src/cpython/abstract_.rs index b6358f854ff..aea3740ed3c 100644 --- a/pyo3-ffi/src/cpython/abstract_.rs +++ b/pyo3-ffi/src/cpython/abstract_.rs @@ -1,29 +1,31 @@ -use crate::{PyObject, Py_ssize_t}; -#[cfg(any(not(PyPy), not(Py_3_11)))] +use crate::{vectorcallfunc, PyObject, Py_TYPE, Py_ssize_t}; +#[cfg(all(any(not(PyPy), not(Py_3_11)), not(Py_3_12)))] use std::ffi::c_char; +#[cfg(not(Py_3_11))] use std::ffi::c_int; +#[cfg(not(any(PyPy, GraalPy)))] +use crate::{ + PyListObject, PyList_Check, PyList_GET_ITEM, PyList_GET_SIZE, PyTupleObject, PyTuple_GET_ITEM, + PyTuple_GET_SIZE, +}; + #[cfg(not(Py_3_11))] use crate::Py_buffer; -#[cfg(not(PyPy))] -use crate::{ - vectorcallfunc, PyCallable_Check, PyThreadState, PyThreadState_GET, PyTuple_Check, - PyType_HasFeature, Py_TPFLAGS_HAVE_VECTORCALL, -}; +#[cfg(not(any(PyPy, Py_3_11)))] +use crate::{PyCallable_Check, PyType_HasFeature, Py_TPFLAGS_HAVE_VECTORCALL}; +#[cfg(not(any(Py_3_12, PyPy)))] +use crate::{PyThreadState, PyThreadState_GET, PyTuple_Check}; use libc::size_t; -extern_libpython! { - #[cfg(not(any(PyPy, GraalPy)))] - pub fn _PyStack_AsDict(values: *const *mut PyObject, kwnames: *mut PyObject) -> *mut PyObject; -} - -#[cfg(not(any(PyPy, GraalPy)))] -const _PY_FASTCALL_SMALL_STACK: size_t = 5; +// skipped private _PyObject_CallMethodId +// skipped private _PyStack_AsDict +#[cfg(not(Py_3_12))] extern_libpython! { #[cfg(not(PyPy))] - pub fn _Py_CheckFunctionResult( + fn _Py_CheckFunctionResult( tstate: *mut PyThreadState, callable: *mut PyObject, result: *mut PyObject, @@ -31,7 +33,7 @@ extern_libpython! { ) -> *mut PyObject; #[cfg(not(PyPy))] - pub fn _PyObject_MakeTpCall( + fn _PyObject_MakeTpCall( tstate: *mut PyThreadState, callable: *mut PyObject, args: *const *mut PyObject, @@ -40,8 +42,13 @@ extern_libpython! { ) -> *mut PyObject; } -const PY_VECTORCALL_ARGUMENTS_OFFSET: size_t = - 1 << (8 * std::mem::size_of::() as size_t - 1); +#[cfg(not(Py_3_12))] +const PY_VECTORCALL_ARGUMENTS_OFFSET: size_t = (1 as size_t) + .checked_shl((8 * std::mem::size_of::() - 1) as u32) + .expect("size_t should fit the flag bits"); + +#[cfg(Py_3_12)] // public API from 3.12 +use crate::PY_VECTORCALL_ARGUMENTS_OFFSET; #[inline(always)] pub unsafe fn PyVectorcall_NARGS(n: size_t) -> Py_ssize_t { @@ -49,7 +56,13 @@ pub unsafe fn PyVectorcall_NARGS(n: size_t) -> Py_ssize_t { n.try_into().expect("cannot fail due to mask") } -#[cfg(not(PyPy))] +#[cfg(any(PyPy, Py_3_11))] +extern_libpython! { + #[cfg_attr(PyPy, link_name = "PyPyVectorcall_Function")] + pub fn PyVectorcall_Function(callable: *mut PyObject) -> Option; +} + +#[cfg(not(any(PyPy, Py_3_11)))] #[inline(always)] pub unsafe fn PyVectorcall_Function(callable: *mut PyObject) -> Option { assert!(!callable.is_null()); @@ -64,9 +77,10 @@ pub unsafe fn PyVectorcall_Function(callable: *mut PyObject) -> Option *mut PyObject; - - #[cfg_attr(not(any(Py_3_9, PyPy)), link_name = "_PyVectorcall_Call")] - #[cfg_attr(PyPy, link_name = "PyPyVectorcall_Call")] - pub fn PyVectorcall_Call( - callable: *mut PyObject, - tuple: *mut PyObject, - dict: *mut PyObject, - ) -> *mut PyObject; -} - -#[cfg(not(any(PyPy, GraalPy)))] -#[inline(always)] -pub unsafe fn _PyObject_FastCallTstate( - tstate: *mut PyThreadState, - func: *mut PyObject, - args: *const *mut PyObject, - nargs: Py_ssize_t, -) -> *mut PyObject { - _PyObject_VectorcallTstate(tstate, func, args, nargs as size_t, std::ptr::null_mut()) -} - -#[cfg(not(any(PyPy, GraalPy)))] -#[inline(always)] -pub unsafe fn _PyObject_FastCall( - func: *mut PyObject, - args: *const *mut PyObject, - nargs: Py_ssize_t, -) -> *mut PyObject { - _PyObject_FastCallTstate(PyThreadState_GET(), func, args, nargs) -} - -#[cfg(not(PyPy))] -#[inline(always)] -pub unsafe fn _PyObject_CallNoArg(func: *mut PyObject) -> *mut PyObject { - _PyObject_VectorcallTstate( - PyThreadState_GET(), - func, - std::ptr::null_mut(), - 0, - std::ptr::null_mut(), - ) -} - -extern_libpython! { - #[cfg(PyPy)] - #[link_name = "_PyPyObject_CallNoArg"] - pub fn _PyObject_CallNoArg(func: *mut PyObject) -> *mut PyObject; } -#[cfg(not(PyPy))] +#[cfg(not(any(Py_3_12, PyPy)))] #[inline(always)] pub unsafe fn PyObject_CallOneArg(func: *mut PyObject, arg: *mut PyObject) -> *mut PyObject { assert!(!arg.is_null()); @@ -172,6 +139,12 @@ pub unsafe fn PyObject_CallOneArg(func: *mut PyObject, arg: *mut PyObject) -> *m _PyObject_VectorcallTstate(tstate, func, args, nargsf, std::ptr::null_mut()) } +extern_libpython! { + #[cfg(any(Py_3_12, PyPy))] + #[cfg_attr(PyPy, link_name = "PyPyObject_CallOneArg")] + pub fn PyObject_CallOneArg(func: *mut PyObject, arg: *mut PyObject) -> *mut PyObject; +} + #[cfg(all(Py_3_9, not(PyPy)))] #[inline(always)] pub unsafe fn PyObject_CallMethodNoArgs( @@ -203,12 +176,6 @@ pub unsafe fn PyObject_CallMethodOneArg( ) } -// skipped _PyObject_VectorcallMethodId -// skipped _PyObject_CallMethodIdNoArgs -// skipped _PyObject_CallMethodIdOneArg - -// skipped _PyObject_HasLen - extern_libpython! { #[cfg_attr(PyPy, link_name = "PyPyObject_LengthHint")] pub fn PyObject_LengthHint(o: *mut PyObject, arg1: Py_ssize_t) -> Py_ssize_t; @@ -273,31 +240,37 @@ extern_libpython! { pub fn PyBuffer_Release(view: *mut Py_buffer); } -// skipped PySequence_ITEM - -pub const PY_ITERSEARCH_COUNT: c_int = 1; -pub const PY_ITERSEARCH_INDEX: c_int = 2; -pub const PY_ITERSEARCH_CONTAINS: c_int = 3; - -extern_libpython! { - #[cfg(not(any(PyPy, GraalPy)))] - pub fn _PySequence_IterSearch( - seq: *mut PyObject, - obj: *mut PyObject, - operation: c_int, - ) -> Py_ssize_t; +#[inline(always)] +pub unsafe fn PySequence_ITEM(seq: *mut PyObject, i: Py_ssize_t) -> *mut PyObject { + (*(*Py_TYPE(seq)).tp_as_sequence).sq_item.unwrap_unchecked()(seq, i) } -// skipped _PyObject_RealIsInstance -// skipped _PyObject_RealIsSubclass - -// skipped _PySequence_BytesToCharpArray - -// skipped _Py_FreeCharPArray - -// skipped _Py_add_one_to_index_F -// skipped _Py_add_one_to_index_C +#[inline(always)] +#[cfg(not(any(PyPy, GraalPy)))] +pub unsafe fn PySequence_Fast_GET_SIZE(seq: *mut PyObject) -> Py_ssize_t { + if PyList_Check(seq) == 1 { + PyList_GET_SIZE(seq) + } else { + PyTuple_GET_SIZE(seq) + } +} -// skipped _Py_convert_optional_to_ssize_t +#[inline(always)] +#[cfg(not(any(PyPy, GraalPy)))] +pub unsafe fn PySequence_Fast_GET_ITEM(seq: *mut PyObject, i: Py_ssize_t) -> *mut PyObject { + if PyList_Check(seq) == 1 { + PyList_GET_ITEM(seq, i) + } else { + PyTuple_GET_ITEM(seq, i) + } +} -// skipped _PyNumber_Index(*mut PyObject o) +#[inline(always)] +#[cfg(not(any(PyPy, GraalPy)))] +pub unsafe fn PySequence_Fast_ITEMS(seq: *mut PyObject) -> *mut *mut PyObject { + if PyList_Check(seq) == 1 { + (*seq.cast::()).ob_item + } else { + (*seq.cast::()).ob_item.as_mut_ptr() + } +} diff --git a/pyo3-ffi/src/impl_/macros.rs b/pyo3-ffi/src/impl_/macros.rs index c493157186c..be3b0418866 100644 --- a/pyo3-ffi/src/impl_/macros.rs +++ b/pyo3-ffi/src/impl_/macros.rs @@ -38,30 +38,12 @@ macro_rules! extern_libpython_maybe_private_fn { ) => { extern_libpython_cpython_private_fn! { $(#[$attrs])* $vis $name($($args)*) $(-> $ret)? } }; - ( - [_PyObject_CallMethod_SizeT] - $(#[$attrs:meta])* $vis:vis fn $name:ident($($args:tt)*) $(-> $ret:ty)? - ) => { - extern_libpython_cpython_private_fn! { $(#[$attrs])* $vis $name($($args)*) $(-> $ret)? } - }; ( [_PyObject_MakeTpCall] $(#[$attrs:meta])* $vis:vis fn $name:ident($($args:tt)*) $(-> $ret:ty)? ) => { extern_libpython_cpython_private_fn! { $(#[$attrs])* $vis $name($($args)*) $(-> $ret)? } }; - ( - [_PySequence_IterSearch] - $(#[$attrs:meta])* $vis:vis fn $name:ident($($args:tt)*) $(-> $ret:ty)? - ) => { - extern_libpython_cpython_private_fn! { $(#[$attrs])* $vis $name($($args)*) $(-> $ret)? } - }; - ( - [_PyStack_AsDict] - $(#[$attrs:meta])* $vis:vis fn $name:ident($($args:tt)*) $(-> $ret:ty)? - ) => { - extern_libpython_cpython_private_fn! { $(#[$attrs])* $vis $name($($args)*) $(-> $ret)? } - }; ( [_Py_CheckFunctionResult] $(#[$attrs:meta])* $vis:vis fn $name:ident($($args:tt)*) $(-> $ret:ty)?