diff --git a/newsfragments/3402.added.md b/newsfragments/3402.added.md new file mode 100644 index 00000000000..69383de1d6b --- /dev/null +++ b/newsfragments/3402.added.md @@ -0,0 +1 @@ +Add FFI definitions `PyObject_GC_IsTracked` and `PyObject_GC_IsFinalized` on Python 3.9 and up (PyPy 3.10 and up). diff --git a/newsfragments/3402.fixed.md b/newsfragments/3402.fixed.md new file mode 100644 index 00000000000..9098773dfb3 --- /dev/null +++ b/newsfragments/3402.fixed.md @@ -0,0 +1 @@ +Disable removed FFI definitions `_Py_GetAllocatedBlocks`, `_PyObject_GC_Malloc`, and `_PyObject_GC_Calloc` on Python 3.11 and up. diff --git a/pyo3-ffi/src/cpython/mod.rs b/pyo3-ffi/src/cpython/mod.rs index 30c5d3b9a65..57d5a3798b5 100644 --- a/pyo3-ffi/src/cpython/mod.rs +++ b/pyo3-ffi/src/cpython/mod.rs @@ -21,6 +21,7 @@ pub(crate) mod listobject; #[cfg(all(Py_3_9, not(PyPy)))] pub(crate) mod methodobject; pub(crate) mod object; +pub(crate) mod objimpl; pub(crate) mod pydebug; pub(crate) mod pyerrors; #[cfg(all(Py_3_8, not(PyPy)))] @@ -54,6 +55,7 @@ pub use self::listobject::*; #[cfg(all(Py_3_9, not(PyPy)))] pub use self::methodobject::*; pub use self::object::*; +pub use self::objimpl::*; pub use self::pydebug::*; pub use self::pyerrors::*; #[cfg(all(Py_3_8, not(PyPy)))] diff --git a/pyo3-ffi/src/cpython/objimpl.rs b/pyo3-ffi/src/cpython/objimpl.rs new file mode 100644 index 00000000000..300ba938cc9 --- /dev/null +++ b/pyo3-ffi/src/cpython/objimpl.rs @@ -0,0 +1,65 @@ +use libc::size_t; +use std::os::raw::{c_int, c_void}; + +use crate::object::*; + +// skipped _PyObject_SIZE +// skipped _PyObject_VAR_SIZE + +#[cfg(not(Py_3_11))] +pub fn _Py_GetAllocatedBlocks() -> Py_ssize_t; + +#[cfg(not(PyPy))] +#[repr(C)] +#[derive(Copy, Clone)] +pub struct PyObjectArenaAllocator { + pub ctx: *mut c_void, + pub alloc: Option *mut c_void>, + pub free: Option, +} + +#[cfg(not(PyPy))] +impl Default for PyObjectArenaAllocator { + #[inline] + fn default() -> Self { + unsafe { std::mem::zeroed() } + } +} + +extern "C" { + #[cfg(not(PyPy))] + pub fn PyObject_GetArenaAllocator(allocator: *mut PyObjectArenaAllocator); + #[cfg(not(PyPy))] + pub fn PyObject_SetArenaAllocator(allocator: *mut PyObjectArenaAllocator); + + #[cfg(Py_3_9)] + pub fn PyObject_IS_GC(o: *mut PyObject) -> c_int; +} + +#[inline] +#[cfg(not(Py_3_9))] +pub unsafe fn PyObject_IS_GC(o: *mut PyObject) -> c_int { + (PyType_IS_GC(Py_TYPE(o)) != 0 + && match (*Py_TYPE(o)).tp_is_gc { + Some(tp_is_gc) => tp_is_gc(o) != 0, + None => true, + }) as c_int +} + +#[cfg(not(Py_3_11))] +pub fn _PyObject_GC_Malloc(size: size_t) -> *mut PyObject; +#[cfg(not(Py_3_11))] +pub fn _PyObject_GC_Calloc(size: size_t) -> *mut PyObject; + +#[inline] +pub unsafe fn PyType_SUPPORTS_WEAKREFS(t: *mut PyTypeObject) -> c_int { + ((*t).tp_weaklistoffset > 0) as c_int +} + +#[inline] +pub unsafe fn PyObject_GET_WEAKREFS_LISTPTR(o: *mut PyObject) -> *mut *mut PyObject { + let weaklistoffset = (*Py_TYPE(o)).tp_weaklistoffset; + o.offset(weaklistoffset) as *mut *mut PyObject +} + +// skipped PyUnstable_Object_GC_NewWithExtraData diff --git a/pyo3-ffi/src/objimpl.rs b/pyo3-ffi/src/objimpl.rs index a6fbf9e8e56..5ce199934b7 100644 --- a/pyo3-ffi/src/objimpl.rs +++ b/pyo3-ffi/src/objimpl.rs @@ -1,8 +1,9 @@ -use crate::object::*; -use crate::pyport::Py_ssize_t; use libc::size_t; use std::os::raw::{c_int, c_void}; +use crate::object::*; +use crate::pyport::Py_ssize_t; + extern "C" { #[cfg_attr(PyPy, link_name = "PyPyObject_Malloc")] pub fn PyObject_Malloc(size: size_t) -> *mut c_void; @@ -12,8 +13,12 @@ extern "C" { #[cfg_attr(PyPy, link_name = "PyPyObject_Free")] pub fn PyObject_Free(ptr: *mut c_void); - #[cfg(not(Py_LIMITED_API))] - pub fn _Py_GetAllocatedBlocks() -> Py_ssize_t; + // skipped PyObject_MALLOC + // skipped PyObject_REALLOC + // skipped PyObject_FREE + // skipped PyObject_Del + // skipped PyObject_DEL + #[cfg_attr(PyPy, link_name = "PyPyObject_Init")] pub fn PyObject_Init(arg1: *mut PyObject, arg2: *mut PyTypeObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyObject_InitVar")] @@ -22,11 +27,20 @@ extern "C" { arg2: *mut PyTypeObject, arg3: Py_ssize_t, ) -> *mut PyVarObject; + + // skipped PyObject_INIT + // skipped PyObject_INIT_VAR + #[cfg_attr(PyPy, link_name = "_PyPyObject_New")] pub fn _PyObject_New(arg1: *mut PyTypeObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "_PyPyObject_NewVar")] pub fn _PyObject_NewVar(arg1: *mut PyTypeObject, arg2: Py_ssize_t) -> *mut PyVarObject; + // skipped PyObject_New + // skipped PyObject_NEW + // skipped PyObject_NewVar + // skipped PyObject_NEW_VAR + pub fn PyGC_Collect() -> Py_ssize_t; #[cfg(Py_3_10)] @@ -40,56 +54,20 @@ extern "C" { #[cfg(Py_3_10)] #[cfg_attr(PyPy, link_name = "PyPyGC_IsEnabled")] pub fn PyGC_IsEnabled() -> c_int; -} - -#[cfg(not(any(Py_LIMITED_API, PyPy)))] -#[repr(C)] -#[derive(Copy, Clone)] -pub struct PyObjectArenaAllocator { - pub ctx: *mut c_void, - pub alloc: Option *mut c_void>, - pub free: Option, -} -#[cfg(not(any(Py_LIMITED_API, PyPy)))] -impl Default for PyObjectArenaAllocator { - #[inline] - fn default() -> Self { - unsafe { std::mem::zeroed() } - } + // skipped PyUnstable_GC_VisitObjects } -extern "C" { - #[cfg(not(any(Py_LIMITED_API, PyPy)))] - pub fn PyObject_GetArenaAllocator(allocator: *mut PyObjectArenaAllocator); - #[cfg(not(any(Py_LIMITED_API, PyPy)))] - pub fn PyObject_SetArenaAllocator(allocator: *mut PyObjectArenaAllocator); -} - -/// Test if a type has a GC head #[inline] pub unsafe fn PyType_IS_GC(t: *mut PyTypeObject) -> c_int { PyType_HasFeature(t, Py_TPFLAGS_HAVE_GC) } -/// Test if an object has a GC head -#[inline] -#[cfg(not(Py_LIMITED_API))] -pub unsafe fn PyObject_IS_GC(o: *mut PyObject) -> c_int { - (PyType_IS_GC(Py_TYPE(o)) != 0 - && match (*Py_TYPE(o)).tp_is_gc { - Some(tp_is_gc) => tp_is_gc(o) != 0, - None => true, - }) as c_int -} - extern "C" { pub fn _PyObject_GC_Resize(arg1: *mut PyVarObject, arg2: Py_ssize_t) -> *mut PyVarObject; - #[cfg(not(Py_LIMITED_API))] - pub fn _PyObject_GC_Malloc(size: size_t) -> *mut PyObject; - #[cfg(not(Py_LIMITED_API))] - pub fn _PyObject_GC_Calloc(size: size_t) -> *mut PyObject; + // skipped PyObject_GC_Resize + #[cfg_attr(PyPy, link_name = "_PyPyObject_GC_New")] pub fn _PyObject_GC_New(arg1: *mut PyTypeObject) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "_PyPyObject_GC_NewVar")] @@ -98,18 +76,16 @@ extern "C" { pub fn PyObject_GC_UnTrack(arg1: *mut c_void); #[cfg_attr(PyPy, link_name = "PyPyObject_GC_Del")] pub fn PyObject_GC_Del(arg1: *mut c_void); -} -/// Test if a type supports weak references -#[inline] -#[cfg(not(Py_LIMITED_API))] -pub unsafe fn PyType_SUPPORTS_WEAKREFS(t: *mut PyTypeObject) -> c_int { - ((*t).tp_weaklistoffset > 0) as c_int -} + // skipped PyObject_GC_New + // skipped PyObject_GC_NewVar -#[inline] -#[cfg(not(Py_LIMITED_API))] -pub unsafe fn PyObject_GET_WEAKREFS_LISTPTR(o: *mut PyObject) -> *mut *mut PyObject { - let weaklistoffset = (*Py_TYPE(o)).tp_weaklistoffset; - o.offset(weaklistoffset) as *mut *mut PyObject + #[cfg(any(all(Py_3_9), not(PyPy), Py_3_10))] // added in 3.9, or 3.10 on PyPy + #[cfg_attr(PyPy, link_name = "PyPyObject_GC_IsTracked")] + pub fn PyObject_GC_IsTracked(arg1: *mut PyObject) -> c_int; + #[cfg(any(all(Py_3_9), not(PyPy), Py_3_10))] // added in 3.9, or 3.10 on PyPy + #[cfg_attr(PyPy, link_name = "PyPyObject_GC_IsFinalized")] + pub fn PyObject_GC_IsFinalized(arg1: *mut PyObject) -> c_int; } + +// skipped Py_VISIT