From 3f093d9e59df0140f6c3a0abbb6acaa439687b7f Mon Sep 17 00:00:00 2001 From: Nicholas Sim Date: Sun, 27 Dec 2020 10:53:18 +0800 Subject: [PATCH] ffi module cleanup (#1338) * initial work to clean up ffi module * ffi: mirror cpython Includes * ffi: start to alphebetise, note skipped headers * ffi: temporarily move _PyFrameEvalFunction back * ffi cleanup: fix pypy compilation * Update src/ffi/mod.rs Co-authored-by: Yuji Kanagawa * add suggested changes * ffi cleanup: remove unnecessary use stmt * ffi cleanup: add deprecation warning * ffi cleanup: transitively deprecate, update changelog Co-authored-by: Yuji Kanagawa --- CHANGELOG.md | 1 + src/ffi/boolobject.rs | 23 +++-- src/ffi/bytesobject.rs | 11 ++- src/ffi/ceval.rs | 39 +++++--- src/ffi/code.rs | 158 +------------------------------ src/ffi/codecs.rs | 10 ++ src/ffi/compile.rs | 23 ++++- src/ffi/complexobject.rs | 63 +++++++------ src/ffi/cpython/bytesobject.rs | 7 ++ src/ffi/cpython/ceval.rs | 16 ++++ src/ffi/cpython/code.rs | 166 +++++++++++++++++++++++++++++++++ src/ffi/cpython/mod.rs | 8 ++ src/ffi/frameobject.rs | 2 +- src/ffi/mod.rs | 65 +++++++++---- src/ffi/object.rs | 2 + 15 files changed, 367 insertions(+), 227 deletions(-) create mode 100644 src/ffi/cpython/bytesobject.rs create mode 100644 src/ffi/cpython/ceval.rs create mode 100644 src/ffi/cpython/code.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index ef1f1066..ac2b3024 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed - Stop including `Py_TRACE_REFS` config setting automatically if `Py_DEBUG` is set on Python 3.8 and up. [#1334](https://github.com/PyO3/pyo3/pull/1334) - Remove `#[deny(warnings)]` attribute (and instead refuse warnings only in CI). [#1340](https://github.com/PyO3/pyo3/pull/1340) +- Deprecate FFI definitions `PyEval_CallObjectWithKeywords`, `PyEval_CallObject`, `PyEval_CallFunction`, `PyEval_CallMethod` when building for Python 3.9. [#1338](https://github.com/PyO3/pyo3/pull/1338) ## [0.13.0] - 2020-12-22 ### Packaging diff --git a/src/ffi/boolobject.rs b/src/ffi/boolobject.rs index ea740c1f..c895638e 100644 --- a/src/ffi/boolobject.rs +++ b/src/ffi/boolobject.rs @@ -6,12 +6,6 @@ use std::os::raw::{c_int, c_long}; extern "C" { #[cfg_attr(PyPy, link_name = "PyPyBool_Type")] pub static mut PyBool_Type: PyTypeObject; - #[cfg_attr(PyPy, link_name = "_PyPy_FalseStruct")] - static mut _Py_FalseStruct: PyLongObject; - #[cfg_attr(PyPy, link_name = "_PyPy_TrueStruct")] - static mut _Py_TrueStruct: PyLongObject; - #[cfg_attr(PyPy, link_name = "PyPyBool_FromLong")] - pub fn PyBool_FromLong(arg1: c_long) -> *mut PyObject; } #[inline] @@ -19,6 +13,14 @@ pub unsafe fn PyBool_Check(op: *mut PyObject) -> c_int { (Py_TYPE(op) == &mut PyBool_Type) as c_int } +#[cfg_attr(windows, link(name = "pythonXY"))] +extern "C" { + #[cfg_attr(PyPy, link_name = "_PyPy_FalseStruct")] + static mut _Py_FalseStruct: PyLongObject; + #[cfg_attr(PyPy, link_name = "_PyPy_TrueStruct")] + static mut _Py_TrueStruct: PyLongObject; +} + #[inline] pub unsafe fn Py_False() -> *mut PyObject { &mut _Py_FalseStruct as *mut PyLongObject as *mut PyObject @@ -28,3 +30,12 @@ pub unsafe fn Py_False() -> *mut PyObject { pub unsafe fn Py_True() -> *mut PyObject { &mut _Py_TrueStruct as *mut PyLongObject as *mut PyObject } + +// skipped Py_RETURN_TRUE +// skipped Py_RETURN_FALSE + +#[cfg_attr(windows, link(name = "pythonXY"))] +extern "C" { + #[cfg_attr(PyPy, link_name = "PyPyBool_FromLong")] + pub fn PyBool_FromLong(arg1: c_long) -> *mut PyObject; +} diff --git a/src/ffi/bytesobject.rs b/src/ffi/bytesobject.rs index 06350638..1e52a47b 100644 --- a/src/ffi/bytesobject.rs +++ b/src/ffi/bytesobject.rs @@ -25,7 +25,8 @@ extern "C" { pub fn PyBytes_FromString(arg1: *const c_char) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyBytes_FromObject")] pub fn PyBytes_FromObject(arg1: *mut PyObject) -> *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyBytes_FromFormatV")] + // skipped PyBytes_FromFormatV + //#[cfg_attr(PyPy, link_name = "PyPyBytes_FromFormatV")] //pub fn PyBytes_FromFormatV(arg1: *const c_char, arg2: va_list) // -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyBytes_FromFormat")] @@ -52,6 +53,10 @@ extern "C" { s: *mut *mut c_char, len: *mut Py_ssize_t, ) -> c_int; - #[cfg(not(PyPy))] - pub fn _PyBytes_Resize(bytes: *mut *mut PyObject, newsize: Py_ssize_t) -> c_int; } + +// skipped F_LJUST +// skipped F_SIGN +// skipped F_BLANK +// skipped F_ALT +// skipped F_ZERO diff --git a/src/ffi/ceval.rs b/src/ffi/ceval.rs index 7ac31c71..b061c937 100644 --- a/src/ffi/ceval.rs +++ b/src/ffi/ceval.rs @@ -1,10 +1,13 @@ -#[cfg(not(Py_LIMITED_API))] -use crate::ffi::code::FreeFunc; use crate::ffi::object::PyObject; -use crate::ffi::pystate::{PyThreadState, Py_tracefunc}; +use crate::ffi::pystate::PyThreadState; use std::os::raw::{c_char, c_int, c_void}; +// TODO: move to cpython +pub type _PyFrameEvalFunction = + extern "C" fn(*mut crate::ffi::PyFrameObject, c_int) -> *mut PyObject; + extern "C" { + #[cfg_attr(Py_3_9, deprecated(note = "Python 3.9"))] #[cfg_attr(PyPy, link_name = "PyPyEval_CallObjectWithKeywords")] pub fn PyEval_CallObjectWithKeywords( func: *mut PyObject, @@ -13,14 +16,18 @@ extern "C" { ) -> *mut PyObject; } +#[cfg_attr(Py_3_9, deprecated(note = "Python 3.9"))] #[inline] pub unsafe fn PyEval_CallObject(func: *mut PyObject, arg: *mut PyObject) -> *mut PyObject { + #[allow(deprecated)] PyEval_CallObjectWithKeywords(func, arg, ::std::ptr::null_mut()) } extern "C" { + #[cfg_attr(Py_3_9, deprecated(note = "Python 3.9"))] #[cfg_attr(PyPy, link_name = "PyPyEval_CallFunction")] pub fn PyEval_CallFunction(obj: *mut PyObject, format: *const c_char, ...) -> *mut PyObject; + #[cfg_attr(Py_3_9, deprecated(note = "Python 3.9"))] #[cfg_attr(PyPy, link_name = "PyPyEval_CallMethod")] pub fn PyEval_CallMethod( obj: *mut PyObject, @@ -49,28 +56,20 @@ extern "C" { fn _Py_CheckRecursiveCall(_where: *mut c_char) -> c_int; } -// TODO: Py_EnterRecursiveCall etc -pub type _PyFrameEvalFunction = - extern "C" fn(*mut crate::ffi::PyFrameObject, c_int) -> *mut PyObject; +// TODO +// skipped Py_EnterRecursiveCall +// skipped Py_LeaveRecursiveCall extern "C" { pub fn PyEval_GetFuncName(arg1: *mut PyObject) -> *const c_char; pub fn PyEval_GetFuncDesc(arg1: *mut PyObject) -> *const c_char; pub fn PyEval_GetCallStats(arg1: *mut PyObject) -> *mut PyObject; pub fn PyEval_EvalFrame(arg1: *mut crate::ffi::PyFrameObject) -> *mut PyObject; - pub fn _PyEval_EvalFrameDefault( - arg1: *mut crate::ffi::PyFrameObject, - exc: c_int, - ) -> *mut PyObject; - #[cfg(not(Py_LIMITED_API))] - pub fn _PyEval_RequestCodeExtraIndex(func: FreeFunc) -> c_int; pub fn PyEval_EvalFrameEx(f: *mut crate::ffi::PyFrameObject, exc: c_int) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyEval_SaveThread")] pub fn PyEval_SaveThread() -> *mut PyThreadState; #[cfg_attr(PyPy, link_name = "PyPyEval_RestoreThread")] pub fn PyEval_RestoreThread(arg1: *mut PyThreadState); - pub fn PyEval_SetProfile(trace_func: Py_tracefunc, arg1: *mut PyObject); - pub fn PyEval_SetTrace(trace_func: Py_tracefunc, arg1: *mut PyObject); } #[cfg(py_sys_config = "WITH_THREAD")] @@ -88,3 +87,15 @@ extern "C" { #[cfg(not(Py_3_8))] pub fn PyEval_ReInitThreads(); } + +// skipped Py_BEGIN_ALLOW_THREADS +// skipped Py_BLOCK_THREADS +// skipped Py_UNBLOCK_THREADS +// skipped Py_END_ALLOW_THREADS +// skipped FVC_MASK +// skipped FVC_NONE +// skipped FVC_STR +// skipped FVC_REPR +// skipped FVC_ASCII +// skipped FVS_MASK +// skipped FVS_HAVE_SPEC diff --git a/src/ffi/code.rs b/src/ffi/code.rs index 59eb3fe0..76980102 100644 --- a/src/ffi/code.rs +++ b/src/ffi/code.rs @@ -1,156 +1,2 @@ -use crate::ffi::object::*; -use crate::ffi::pyport::Py_ssize_t; -use std::os::raw::{c_char, c_int, c_uchar, c_void}; - -#[cfg(Py_3_8)] -opaque_struct!(_PyOpcache); - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct PyCodeObject { - pub ob_base: PyObject, - pub co_argcount: c_int, - #[cfg(Py_3_8)] - pub co_posonlyargcount: c_int, - pub co_kwonlyargcount: c_int, - pub co_nlocals: c_int, - pub co_stacksize: c_int, - pub co_flags: c_int, - pub co_firstlineno: c_int, - pub co_code: *mut PyObject, - pub co_consts: *mut PyObject, - pub co_names: *mut PyObject, - pub co_varnames: *mut PyObject, - pub co_freevars: *mut PyObject, - pub co_cellvars: *mut PyObject, - pub co_cell2arg: *mut c_uchar, - pub co_filename: *mut PyObject, - pub co_name: *mut PyObject, - pub co_lnotab: *mut PyObject, - pub co_zombieframe: *mut c_void, - pub co_weakreflist: *mut PyObject, - pub co_extra: *mut c_void, - #[cfg(Py_3_8)] - pub co_opcache_map: *mut c_uchar, - #[cfg(Py_3_8)] - pub co_opcache: *mut _PyOpcache, - #[cfg(Py_3_8)] - pub co_opcache_flag: c_int, - #[cfg(Py_3_8)] - pub co_opcache_size: c_uchar, -} - -/* Masks for co_flags */ -pub const CO_OPTIMIZED: c_int = 0x0001; -pub const CO_NEWLOCALS: c_int = 0x0002; -pub const CO_VARARGS: c_int = 0x0004; -pub const CO_VARKEYWORDS: c_int = 0x0008; -pub const CO_NESTED: c_int = 0x0010; -pub const CO_GENERATOR: c_int = 0x0020; -/* The CO_NOFREE flag is set if there are no free or cell variables. - This information is redundant, but it allows a single flag test - to determine whether there is any extra work to be done when the - call frame it setup. -*/ -pub const CO_NOFREE: c_int = 0x0040; -/* The CO_COROUTINE flag is set for coroutine functions (defined with -``async def`` keywords) */ -pub const CO_COROUTINE: c_int = 0x0080; -pub const CO_ITERABLE_COROUTINE: c_int = 0x0100; -pub const CO_ASYNC_GENERATOR: c_int = 0x0200; - -pub const CO_FUTURE_DIVISION: c_int = 0x2000; -pub const CO_FUTURE_ABSOLUTE_IMPORT: c_int = 0x4000; /* do absolute imports by default */ -pub const CO_FUTURE_WITH_STATEMENT: c_int = 0x8000; -pub const CO_FUTURE_PRINT_FUNCTION: c_int = 0x1_0000; -pub const CO_FUTURE_UNICODE_LITERALS: c_int = 0x2_0000; -pub const CO_FUTURE_BARRY_AS_BDFL: c_int = 0x4_0000; -pub const CO_FUTURE_GENERATOR_STOP: c_int = 0x8_0000; - -pub const CO_MAXBLOCKS: usize = 20; -pub type FreeFunc = extern "C" fn(*mut c_void) -> c_void; - -#[cfg_attr(windows, link(name = "pythonXY"))] -extern "C" { - pub static mut PyCode_Type: PyTypeObject; -} - -extern "C" { - pub fn _PyCode_GetExtra( - code: *mut PyObject, - index: Py_ssize_t, - extra: *const *mut c_void, - ) -> c_int; - pub fn _PyCode_SetExtra(code: *mut PyObject, index: Py_ssize_t, extra: *mut c_void) -> c_int; - - #[cfg_attr(PyPy, link_name = "PyPyCode_New")] - pub fn PyCode_New( - argcount: c_int, - kwonlyargcount: c_int, - nlocals: c_int, - stacksize: c_int, - flags: c_int, - code: *mut PyObject, - consts: *mut PyObject, - names: *mut PyObject, - varnames: *mut PyObject, - freevars: *mut PyObject, - cellvars: *mut PyObject, - filename: *mut PyObject, - name: *mut PyObject, - firstlineno: c_int, - lnotab: *mut PyObject, - ) -> *mut PyCodeObject; - #[cfg(Py_3_8)] - pub fn PyCode_NewWithPosOnlyArgs( - argcount: c_int, - posonlyargcount: c_int, - kwonlyargcount: c_int, - nlocals: c_int, - stacksize: c_int, - flags: c_int, - code: *mut PyObject, - consts: *mut PyObject, - names: *mut PyObject, - varnames: *mut PyObject, - freevars: *mut PyObject, - cellvars: *mut PyObject, - filename: *mut PyObject, - name: *mut PyObject, - firstlineno: c_int, - lnotab: *mut PyObject, - ) -> *mut PyCodeObject; - #[cfg_attr(PyPy, link_name = "PyPyCode_NewEmpty")] - pub fn PyCode_NewEmpty( - filename: *const c_char, - funcname: *const c_char, - firstlineno: c_int, - ) -> *mut PyCodeObject; - pub fn PyCode_Addr2Line(arg1: *mut PyCodeObject, arg2: c_int) -> c_int; - pub fn PyCode_Optimize( - code: *mut PyObject, - consts: *mut PyObject, - names: *mut PyObject, - lnotab: *mut PyObject, - ) -> *mut PyObject; - - #[cfg(PyPy)] - #[link_name = "PyPyCode_Check"] - pub fn PyCode_Check(op: *mut PyObject) -> c_int; - - #[cfg(PyPy)] - #[link_name = "PyPyCode_GetNumFree"] - pub fn PyCode_GetNumFree(op: *mut PyCodeObject) -> Py_ssize_t; -} - -#[inline] -#[cfg(not(PyPy))] -pub unsafe fn PyCode_Check(op: *mut PyObject) -> c_int { - (Py_TYPE(op) == &mut PyCode_Type) as c_int -} - -#[inline] -#[cfg(not(PyPy))] -pub unsafe fn PyCode_GetNumFree(op: *mut PyCodeObject) -> Py_ssize_t { - crate::ffi::tupleobject::PyTuple_GET_SIZE((*op).co_freevars) -} +#[cfg(Py_LIMITED_API)] +opaque_struct!(PyCodeObject); diff --git a/src/ffi/codecs.rs b/src/ffi/codecs.rs index d7a26883..873686e9 100644 --- a/src/ffi/codecs.rs +++ b/src/ffi/codecs.rs @@ -3,6 +3,9 @@ use std::os::raw::{c_char, c_int}; extern "C" { pub fn PyCodec_Register(search_function: *mut PyObject) -> c_int; + // skipped PyCodec_Unregister + // skipped non-limited _PyCodec_Lookup from Include/codecs.h + // skipped non-limited _PyCodec_Forget from Include/codecs.h pub fn PyCodec_KnownEncoding(encoding: *const c_char) -> c_int; pub fn PyCodec_Encode( object: *mut PyObject, @@ -14,6 +17,11 @@ extern "C" { encoding: *const c_char, errors: *const c_char, ) -> *mut PyObject; + // skipped non-limited _PyCodec_LookupTextEncoding from Include/codecs.h + // skipped non-limited _PyCodec_EncodeText from Include/codecs.h + // skipped non-limited _PyCodec_DecodeText from Include/codecs.h + // skipped non-limited _PyCodecInfo_GetIncrementalDecoder from Include/codecs.h + // skipped non-limited _PyCodecInfo_GetIncrementalEncoder from Include/codecs.h pub fn PyCodec_Encoder(encoding: *const c_char) -> *mut PyObject; pub fn PyCodec_Decoder(encoding: *const c_char) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyCodec_IncrementalEncoder")] @@ -43,4 +51,6 @@ extern "C" { pub fn PyCodec_ReplaceErrors(exc: *mut PyObject) -> *mut PyObject; pub fn PyCodec_XMLCharRefReplaceErrors(exc: *mut PyObject) -> *mut PyObject; pub fn PyCodec_BackslashReplaceErrors(exc: *mut PyObject) -> *mut PyObject; +// skipped non-limited PyCodec_NameReplaceErrors from Include/codecs.h +// skipped non-limited Py_hexdigits from Include/codecs.h } diff --git a/src/ffi/compile.rs b/src/ffi/compile.rs index 022719f0..8627dce1 100644 --- a/src/ffi/compile.rs +++ b/src/ffi/compile.rs @@ -1,9 +1,22 @@ -use crate::ffi::code::*; use crate::ffi::object::PyObject; use crate::ffi::pyarena::*; use crate::ffi::pythonrun::*; +use crate::ffi::PyCodeObject; use std::os::raw::{c_char, c_int}; +// skipped non-limited PyCF_MASK +// skipped non-limited PyCF_MASK_OBSOLETE +// skipped non-limited PyCF_SOURCE_IS_UTF8 +// skipped non-limited PyCF_DONT_IMPLY_DEDENT +// skipped non-limited PyCF_ONLY_AST +// skipped non-limited PyCF_IGNORE_COOKIE +// skipped non-limited PyCF_TYPE_COMMENTS +// skipped non-limited PyCF_ALLOW_TOP_LEVEL_AWAIT +// skipped non-limited PyCF_COMPILE_MASK + +// skipped non-limited PyCompilerFlags +// skipped non-limited _PyCompilerFlags_INIT + #[repr(C)] #[derive(Copy, Clone)] #[cfg(not(Py_LIMITED_API))] @@ -30,6 +43,7 @@ pub const FUTURE_UNICODE_LITERALS: &str = "unicode_literals"; pub const FUTURE_BARRY_AS_BDFL: &str = "barry_as_FLUFL"; #[cfg(not(Py_LIMITED_API))] pub const FUTURE_GENERATOR_STOP: &str = "generator_stop"; +// skipped non-limited FUTURE_ANNOTATIONS #[cfg(not(Py_LIMITED_API))] extern "C" { @@ -58,10 +72,16 @@ extern "C" { filename: *mut PyObject, ) -> *mut PyFutureFeatures; + // skipped non-limited _Py_Mangle + // skipped non-limited PY_INVALID_STACK_EFFECT + pub fn PyCompile_OpcodeStackEffect(opcode: c_int, oparg: c_int) -> c_int; #[cfg(Py_3_8)] pub fn PyCompile_OpcodeStackEffectWithJump(opcode: c_int, oparg: c_int, jump: c_int) -> c_int; + +// skipped non-limited _PyASTOptimizeState +// skipped non-limited _PyAST_Optimize } pub const Py_single_input: c_int = 256; @@ -69,3 +89,4 @@ pub const Py_file_input: c_int = 257; pub const Py_eval_input: c_int = 258; #[cfg(Py_3_8)] pub const Py_func_type_input: c_int = 345; +// skipped Py_fstring_input diff --git a/src/ffi/complexobject.rs b/src/ffi/complexobject.rs index 946193a4..4ec2adab 100644 --- a/src/ffi/complexobject.rs +++ b/src/ffi/complexobject.rs @@ -1,6 +1,37 @@ use crate::ffi::object::*; use std::os::raw::{c_double, c_int}; +#[repr(C)] +#[derive(Copy, Clone)] +// non-limited +pub struct Py_complex { + pub real: c_double, + pub imag: c_double, +} + +#[cfg(not(Py_LIMITED_API))] +extern "C" { + pub fn _Py_c_sum(left: Py_complex, right: Py_complex) -> Py_complex; + pub fn _Py_c_diff(left: Py_complex, right: Py_complex) -> Py_complex; + pub fn _Py_c_neg(complex: Py_complex) -> Py_complex; + pub fn _Py_c_prod(left: Py_complex, right: Py_complex) -> Py_complex; + pub fn _Py_c_quot(dividend: Py_complex, divisor: Py_complex) -> Py_complex; + pub fn _Py_c_pow(num: Py_complex, exp: Py_complex) -> Py_complex; + pub fn _Py_c_abs(arg: Py_complex) -> c_double; + #[cfg_attr(PyPy, link_name = "PyPyComplex_FromCComplex")] + pub fn PyComplex_FromCComplex(v: Py_complex) -> *mut PyObject; + #[cfg_attr(PyPy, link_name = "PyPyComplex_AsCComplex")] + pub fn PyComplex_AsCComplex(op: *mut PyObject) -> Py_complex; +} + +#[repr(C)] +#[derive(Copy, Clone)] +// non-limited +pub struct PyComplexObject { + pub ob_base: PyObject, + pub cval: Py_complex, +} + #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { #[cfg_attr(PyPy, link_name = "PyPyComplex_Type")] @@ -18,39 +49,13 @@ pub unsafe fn PyComplex_CheckExact(op: *mut PyObject) -> c_int { } extern "C" { + // skipped non-limited PyComplex_FromCComplex #[cfg_attr(PyPy, link_name = "PyPyComplex_FromDoubles")] pub fn PyComplex_FromDoubles(real: c_double, imag: c_double) -> *mut PyObject; #[cfg_attr(PyPy, link_name = "PyPyComplex_RealAsDouble")] pub fn PyComplex_RealAsDouble(op: *mut PyObject) -> c_double; #[cfg_attr(PyPy, link_name = "PyPyComplex_ImagAsDouble")] pub fn PyComplex_ImagAsDouble(op: *mut PyObject) -> c_double; -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct Py_complex { - pub real: c_double, - pub imag: c_double, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct PyComplexObject { - pub ob_base: PyObject, - pub cval: Py_complex, -} - -#[cfg(not(Py_LIMITED_API))] -extern "C" { - pub fn _Py_c_sum(left: Py_complex, right: Py_complex) -> Py_complex; - pub fn _Py_c_diff(left: Py_complex, right: Py_complex) -> Py_complex; - pub fn _Py_c_neg(complex: Py_complex) -> Py_complex; - pub fn _Py_c_prod(left: Py_complex, right: Py_complex) -> Py_complex; - pub fn _Py_c_quot(dividend: Py_complex, divisor: Py_complex) -> Py_complex; - pub fn _Py_c_pow(num: Py_complex, exp: Py_complex) -> Py_complex; - pub fn _Py_c_abs(arg: Py_complex) -> c_double; - #[cfg_attr(PyPy, link_name = "PyPyComplex_FromCComplex")] - pub fn PyComplex_FromCComplex(v: Py_complex) -> *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyComplex_AsCComplex")] - pub fn PyComplex_AsCComplex(op: *mut PyObject) -> Py_complex; +// skipped non-limited PyComplex_AsCComplex +// skipped non-limited _PyComplex_FormatAdvancedWriter } diff --git a/src/ffi/cpython/bytesobject.rs b/src/ffi/cpython/bytesobject.rs new file mode 100644 index 00000000..108dbb0c --- /dev/null +++ b/src/ffi/cpython/bytesobject.rs @@ -0,0 +1,7 @@ +use crate::ffi::object::PyObject; +use crate::ffi::pyport::Py_ssize_t; +use std::os::raw::c_int; + +extern "C" { + pub fn _PyBytes_Resize(bytes: *mut *mut PyObject, newsize: Py_ssize_t) -> c_int; +} diff --git a/src/ffi/cpython/ceval.rs b/src/ffi/cpython/ceval.rs new file mode 100644 index 00000000..66608a0a --- /dev/null +++ b/src/ffi/cpython/ceval.rs @@ -0,0 +1,16 @@ +#[cfg(not(Py_LIMITED_API))] +use crate::ffi::object::FreeFunc; +use crate::ffi::object::PyObject; +use crate::ffi::pystate::Py_tracefunc; +use std::os::raw::c_int; + +extern "C" { + pub fn _PyEval_EvalFrameDefault( + arg1: *mut crate::ffi::PyFrameObject, + exc: c_int, + ) -> *mut PyObject; + #[cfg(not(Py_LIMITED_API))] + pub fn _PyEval_RequestCodeExtraIndex(func: FreeFunc) -> c_int; + pub fn PyEval_SetProfile(trace_func: Py_tracefunc, arg1: *mut PyObject); + pub fn PyEval_SetTrace(trace_func: Py_tracefunc, arg1: *mut PyObject); +} diff --git a/src/ffi/cpython/code.rs b/src/ffi/cpython/code.rs new file mode 100644 index 00000000..12e852d4 --- /dev/null +++ b/src/ffi/cpython/code.rs @@ -0,0 +1,166 @@ +use crate::ffi::object::*; +use crate::ffi::pyport::Py_ssize_t; +use std::os::raw::{c_char, c_int, c_uchar, c_void}; + +// skipped _Py_CODEUNIT +// skipped _Py_OPCODE +// skipped _Py_OPARG + +#[cfg(Py_3_8)] +opaque_struct!(_PyOpcache); + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct PyCodeObject { + pub ob_base: PyObject, + pub co_argcount: c_int, + #[cfg(Py_3_8)] + pub co_posonlyargcount: c_int, + pub co_kwonlyargcount: c_int, + pub co_nlocals: c_int, + pub co_stacksize: c_int, + pub co_flags: c_int, + pub co_firstlineno: c_int, + pub co_code: *mut PyObject, + pub co_consts: *mut PyObject, + pub co_names: *mut PyObject, + pub co_varnames: *mut PyObject, + pub co_freevars: *mut PyObject, + pub co_cellvars: *mut PyObject, + pub co_cell2arg: *mut c_uchar, + pub co_filename: *mut PyObject, + pub co_name: *mut PyObject, + pub co_lnotab: *mut PyObject, + pub co_zombieframe: *mut c_void, + pub co_weakreflist: *mut PyObject, + pub co_extra: *mut c_void, + #[cfg(Py_3_8)] + pub co_opcache_map: *mut c_uchar, + #[cfg(Py_3_8)] + pub co_opcache: *mut _PyOpcache, + #[cfg(Py_3_8)] + pub co_opcache_flag: c_int, + #[cfg(Py_3_8)] + pub co_opcache_size: c_uchar, +} + +/* Masks for co_flags */ +pub const CO_OPTIMIZED: c_int = 0x0001; +pub const CO_NEWLOCALS: c_int = 0x0002; +pub const CO_VARARGS: c_int = 0x0004; +pub const CO_VARKEYWORDS: c_int = 0x0008; +pub const CO_NESTED: c_int = 0x0010; +pub const CO_GENERATOR: c_int = 0x0020; +/* The CO_NOFREE flag is set if there are no free or cell variables. + This information is redundant, but it allows a single flag test + to determine whether there is any extra work to be done when the + call frame it setup. +*/ +pub const CO_NOFREE: c_int = 0x0040; +/* The CO_COROUTINE flag is set for coroutine functions (defined with +``async def`` keywords) */ +pub const CO_COROUTINE: c_int = 0x0080; +pub const CO_ITERABLE_COROUTINE: c_int = 0x0100; +pub const CO_ASYNC_GENERATOR: c_int = 0x0200; + +pub const CO_FUTURE_DIVISION: c_int = 0x2000; +pub const CO_FUTURE_ABSOLUTE_IMPORT: c_int = 0x4000; /* do absolute imports by default */ +pub const CO_FUTURE_WITH_STATEMENT: c_int = 0x8000; +pub const CO_FUTURE_PRINT_FUNCTION: c_int = 0x1_0000; +pub const CO_FUTURE_UNICODE_LITERALS: c_int = 0x2_0000; + +pub const CO_FUTURE_BARRY_AS_BDFL: c_int = 0x4_0000; +pub const CO_FUTURE_GENERATOR_STOP: c_int = 0x8_0000; +// skipped CO_FUTURE_ANNOTATIONS +// skipped CO_CELL_NOT_AN_ARG + +pub const CO_MAXBLOCKS: usize = 20; + +#[cfg_attr(windows, link(name = "pythonXY"))] +extern "C" { + pub static mut PyCode_Type: PyTypeObject; +} + +#[inline] +#[cfg(not(PyPy))] +pub unsafe fn PyCode_Check(op: *mut PyObject) -> c_int { + (Py_TYPE(op) == &mut PyCode_Type) as c_int +} + +#[inline] +#[cfg(not(PyPy))] +pub unsafe fn PyCode_GetNumFree(op: *mut PyCodeObject) -> Py_ssize_t { + crate::ffi::tupleobject::PyTuple_GET_SIZE((*op).co_freevars) +} + +extern "C" { + #[cfg(PyPy)] + #[link_name = "PyPyCode_Check"] + pub fn PyCode_Check(op: *mut PyObject) -> c_int; + + #[cfg(PyPy)] + #[link_name = "PyPyCode_GetNumFree"] + pub fn PyCode_GetNumFree(op: *mut PyCodeObject) -> Py_ssize_t; +} + +extern "C" { + #[cfg_attr(PyPy, link_name = "PyPyCode_New")] + pub fn PyCode_New( + argcount: c_int, + kwonlyargcount: c_int, + nlocals: c_int, + stacksize: c_int, + flags: c_int, + code: *mut PyObject, + consts: *mut PyObject, + names: *mut PyObject, + varnames: *mut PyObject, + freevars: *mut PyObject, + cellvars: *mut PyObject, + filename: *mut PyObject, + name: *mut PyObject, + firstlineno: c_int, + lnotab: *mut PyObject, + ) -> *mut PyCodeObject; + #[cfg(Py_3_8)] + pub fn PyCode_NewWithPosOnlyArgs( + argcount: c_int, + posonlyargcount: c_int, + kwonlyargcount: c_int, + nlocals: c_int, + stacksize: c_int, + flags: c_int, + code: *mut PyObject, + consts: *mut PyObject, + names: *mut PyObject, + varnames: *mut PyObject, + freevars: *mut PyObject, + cellvars: *mut PyObject, + filename: *mut PyObject, + name: *mut PyObject, + firstlineno: c_int, + lnotab: *mut PyObject, + ) -> *mut PyCodeObject; + #[cfg_attr(PyPy, link_name = "PyPyCode_NewEmpty")] + pub fn PyCode_NewEmpty( + filename: *const c_char, + funcname: *const c_char, + firstlineno: c_int, + ) -> *mut PyCodeObject; + pub fn PyCode_Addr2Line(arg1: *mut PyCodeObject, arg2: c_int) -> c_int; + // skipped PyCodeAddressRange "for internal use only" + // skipped _PyCode_CheckLineNumber + // skipped _PyCode_ConstantKey + pub fn PyCode_Optimize( + code: *mut PyObject, + consts: *mut PyObject, + names: *mut PyObject, + lnotab: *mut PyObject, + ) -> *mut PyObject; + pub fn _PyCode_GetExtra( + code: *mut PyObject, + index: Py_ssize_t, + extra: *const *mut c_void, + ) -> c_int; + pub fn _PyCode_SetExtra(code: *mut PyObject, index: Py_ssize_t, extra: *mut c_void) -> c_int; +} diff --git a/src/ffi/cpython/mod.rs b/src/ffi/cpython/mod.rs index 7164f260..76513bde 100644 --- a/src/ffi/cpython/mod.rs +++ b/src/ffi/cpython/mod.rs @@ -1,3 +1,11 @@ pub mod abstract_; +#[cfg(not(PyPy))] +pub mod bytesobject; +pub mod ceval; +pub mod code; pub use self::abstract_::*; +#[cfg(not(PyPy))] +pub use self::bytesobject::*; +pub use self::ceval::*; +pub use self::code::*; diff --git a/src/ffi/frameobject.rs b/src/ffi/frameobject.rs index 6640920c..6178ab87 100644 --- a/src/ffi/frameobject.rs +++ b/src/ffi/frameobject.rs @@ -1,4 +1,4 @@ -use crate::ffi::code::{PyCodeObject, CO_MAXBLOCKS}; +use crate::ffi::cpython::code::{PyCodeObject, CO_MAXBLOCKS}; use crate::ffi::object::*; use crate::ffi::pystate::PyThreadState; use std::os::raw::{c_char, c_int}; diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index 97994caa..4f9b394b 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -46,7 +46,7 @@ pub use self::methodobject::*; pub use self::modsupport::*; pub use self::moduleobject::*; pub use self::object::*; -pub use self::objectabstract::*; +pub use self::objectabstract::*; // FIXME: no matching objectabstract.h in cpython master pub use self::objimpl::*; pub use self::osmodule::*; pub use self::pyarena::*; @@ -75,6 +75,53 @@ pub use self::weakrefobject::*; #[cfg(not(Py_LIMITED_API))] pub use self::cpython::*; +// skipped abstract.h +// skipped asdl.h +// skipped ast.h +mod bltinmodule; +mod boolobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 +mod bytearrayobject; +mod bytesobject; +// skipped cellobject.h +mod ceval; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 + +// skipped classobject.h +mod code; +mod codecs; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 +mod compile; // TODO: incomplete +mod complexobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 + +// skipped dynamic_annotations.h +// skipped errcode.h +// skipped exports.h +// skipped fileutils.h +// skipped genericaliasobject.h +// skipped interpreteridobject.h +// skipped longintrepr.h +// skipped namespaceobject.h +// skipped odictobject.h +// skipped opcode.h +// skipped osdefs.h +// skipped parser_interface.h +// skipped patchlevel.h +// skipped picklebufobject.h +// skipped pyctype.h +// skipped py_curses.h +// skipped pydecimal.h +// skipped pydtrace.h +// skipped pyexpat.h +// skipped pyfpe.h +// skipped pyframe.h +// skipped pymacconfig.h +// skipped pymacro.h +// skipped pymath.h +// skipped pystrcmp.h +// skipped pystrhex.h +// skipped Python-ast.h +// this file is Python.h +// skipped pythread.h +// skipped pytime.h + mod pyport; // mod pymacro; contains nothing of interest for Rust // mod pyatomic; contains nothing of interest for Rust @@ -92,13 +139,9 @@ mod pyhash; mod pymem; mod typeslots; -mod bytearrayobject; -mod bytesobject; mod longobject; mod unicodeobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 // mod longintrepr; TODO excluded by PEP-384 -mod boolobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 -mod complexobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 mod dictobject; mod floatobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 mod listobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 @@ -123,9 +166,6 @@ mod iterobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 a mod structseq; mod warnings; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 mod weakrefobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 - // mod namespaceobject; TODO - -mod codecs; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 mod pyerrors; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 mod pylifecycle; @@ -138,22 +178,13 @@ mod modsupport; // TODO supports PEP-384 only; needs adjustment for Python 3.3 a mod pyarena; // TODO: incomplete mod pythonrun; // TODO some functions need to be moved to pylifecycle //mod pylifecycle; // TODO new in 3.5 -mod ceval; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 mod import; mod intrcheck; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 mod osmodule; mod sysmodule; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 -mod bltinmodule; mod objectabstract; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 -#[cfg(Py_LIMITED_API)] -mod code {} -#[cfg(not(Py_LIMITED_API))] -mod code; - -mod compile; // TODO: incomplete - #[cfg(all(Py_3_8, not(Py_LIMITED_API)))] mod context; // It's actually 3.7.1, but no cfg for patches. diff --git a/src/ffi/object.rs b/src/ffi/object.rs index 18671cd8..aa7ec8d7 100644 --- a/src/ffi/object.rs +++ b/src/ffi/object.rs @@ -3,6 +3,8 @@ use std::mem; use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void}; use std::ptr; +pub type FreeFunc = extern "C" fn(*mut c_void) -> c_void; + #[repr(C)] #[derive(Copy, Clone, Debug)] #[cfg(not(PyPy))]