From b2ae501c13ebdaa85697462d39efca8ff5fe21ae Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 23 Nov 2018 01:05:37 +0100 Subject: [PATCH] WIP: bpo-35059: Replace inline with macros Replace static inline functions with C macros. Change only written to run a benchmark to compare "C macros" to "static inline functions". --- Include/internal/pycore_object.h | 62 ++++++----------- Include/object.h | 115 +++++++++++++------------------ Include/objimpl.h | 21 ++---- 3 files changed, 72 insertions(+), 126 deletions(-) diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index a88b626332f140..f02e3ff299f720 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -21,28 +21,18 @@ extern "C" { * * The PyObject_GC_Track() function is the public version of this macro. */ -static inline void _PyObject_GC_TRACK_impl(const char *filename, int lineno, - PyObject *op) -{ - _PyObject_ASSERT_FROM(op, !_PyObject_GC_IS_TRACKED(op), - "object already tracked by the garbage collector", - filename, lineno, "_PyObject_GC_TRACK"); - - PyGC_Head *gc = _Py_AS_GC(op); - _PyObject_ASSERT_FROM(op, - (gc->_gc_prev & _PyGC_PREV_MASK_COLLECTING) == 0, - "object is in generation which is garbage collected", - filename, lineno, "_PyObject_GC_TRACK"); - - PyGC_Head *last = (PyGC_Head*)(_PyRuntime.gc.generation0->_gc_prev); - _PyGCHead_SET_NEXT(last, gc); - _PyGCHead_SET_PREV(gc, last); - _PyGCHead_SET_NEXT(gc, _PyRuntime.gc.generation0); - _PyRuntime.gc.generation0->_gc_prev = (uintptr_t)gc; -} - -#define _PyObject_GC_TRACK(op) \ - _PyObject_GC_TRACK_impl(__FILE__, __LINE__, _PyObject_CAST(op)) +#define _PyObject_GC_TRACK(o) do { \ + PyGC_Head *g = _Py_AS_GC(o); \ + if (g->_gc_next != 0) { \ + Py_FatalError("GC object already tracked"); \ + } \ + assert((g->_gc_prev & _PyGC_PREV_MASK_COLLECTING) == 0); \ + PyGC_Head *last = (PyGC_Head*)(_PyRuntime.gc.generation0->_gc_prev); \ + _PyGCHead_SET_NEXT(last, g); \ + _PyGCHead_SET_PREV(g, last); \ + _PyGCHead_SET_NEXT(g, _PyRuntime.gc.generation0); \ + _PyRuntime.gc.generation0->_gc_prev = (uintptr_t)g; \ + } while (0); /* Tell the GC to stop tracking this object. * @@ -53,24 +43,16 @@ static inline void _PyObject_GC_TRACK_impl(const char *filename, int lineno, * * The PyObject_GC_UnTrack() function is the public version of this macro. */ -static inline void _PyObject_GC_UNTRACK_impl(const char *filename, int lineno, - PyObject *op) -{ - _PyObject_ASSERT_FROM(op, _PyObject_GC_IS_TRACKED(op), - "object not tracked by the garbage collector", - filename, lineno, "_PyObject_GC_UNTRACK"); - - PyGC_Head *gc = _Py_AS_GC(op); - PyGC_Head *prev = _PyGCHead_PREV(gc); - PyGC_Head *next = _PyGCHead_NEXT(gc); - _PyGCHead_SET_NEXT(prev, next); - _PyGCHead_SET_PREV(next, prev); - gc->_gc_next = 0; - gc->_gc_prev &= _PyGC_PREV_MASK_FINALIZED; -} - -#define _PyObject_GC_UNTRACK(op) \ - _PyObject_GC_UNTRACK_impl(__FILE__, __LINE__, _PyObject_CAST(op)) +#define _PyObject_GC_UNTRACK(o) do { \ + PyGC_Head *g = _Py_AS_GC(o); \ + PyGC_Head *prev = _PyGCHead_PREV(g); \ + PyGC_Head *next = _PyGCHead_NEXT(g); \ + assert(next != NULL); \ + _PyGCHead_SET_NEXT(prev, next); \ + _PyGCHead_SET_PREV(next, prev); \ + g->_gc_next = 0; \ + g->_gc_prev &= _PyGC_PREV_MASK_FINALIZED; \ + } while (0); #ifdef __cplusplus } diff --git a/Include/object.h b/Include/object.h index cdcdca85c633a1..d4d4f4612b6edc 100644 --- a/Include/object.h +++ b/Include/object.h @@ -740,7 +740,12 @@ PyAPI_FUNC(void) _Py_NegativeRefcount(const char *filename, int lineno, PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void); #define _Py_INC_REFTOTAL _Py_RefTotal++ #define _Py_DEC_REFTOTAL _Py_RefTotal-- - +#define _Py_REF_DEBUG_COMMA , +#define _Py_CHECK_REFCNT(OP) \ +{ if (((PyObject*)OP)->ob_refcnt < 0) \ + _Py_NegativeRefcount(__FILE__, __LINE__, \ + (PyObject *)(OP)); \ +} /* Py_REF_DEBUG also controls the display of refcounts and memory block * allocations at the interactive prompt and at interpreter shutdown */ @@ -748,6 +753,8 @@ PyAPI_FUNC(void) _PyDebug_PrintTotalRefs(void); #else #define _Py_INC_REFTOTAL #define _Py_DEC_REFTOTAL +#define _Py_REF_DEBUG_COMMA +#define _Py_CHECK_REFCNT(OP) /* a semicolon */; #endif /* Py_REF_DEBUG */ #ifdef COUNT_ALLOCS @@ -772,6 +779,7 @@ PyAPI_FUNC(int) _PyTraceMalloc_NewReference(PyObject *op); /* Py_TRACE_REFS is such major surgery that we call external routines. */ PyAPI_FUNC(void) _Py_NewReference(PyObject *); PyAPI_FUNC(void) _Py_ForgetReference(PyObject *); +PyAPI_FUNC(void) _Py_Dealloc(PyObject *); PyAPI_FUNC(void) _Py_PrintReferences(FILE *); PyAPI_FUNC(void) _Py_PrintReferenceAddresses(FILE *); PyAPI_FUNC(void) _Py_AddToAllObjects(PyObject *, int force); @@ -779,66 +787,39 @@ PyAPI_FUNC(void) _Py_AddToAllObjects(PyObject *, int force); #else /* Without Py_TRACE_REFS, there's little enough to do that we expand code inline. */ -static inline void _Py_NewReference(PyObject *op) -{ - if (_Py_tracemalloc_config.tracing) { - _PyTraceMalloc_NewReference(op); - } - _Py_INC_TPALLOCS(op); - _Py_INC_REFTOTAL; - Py_REFCNT(op) = 1; -} - -static inline void _Py_ForgetReference(PyObject *op) -{ - _Py_INC_TPFREES(op); -} -#endif /* !Py_TRACE_REFS */ +#define _Py_NewReference(op) ( \ + (_Py_tracemalloc_config.tracing \ + ? _PyTraceMalloc_NewReference(op) \ + : 0), \ + _Py_INC_TPALLOCS(op) _Py_COUNT_ALLOCS_COMMA \ + _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \ + Py_REFCNT(op) = 1) +#define _Py_ForgetReference(op) _Py_INC_TPFREES(op) +#ifdef Py_LIMITED_API PyAPI_FUNC(void) _Py_Dealloc(PyObject *); - -#ifndef Py_LIMITED_API -static inline void _Py_Dealloc_inline(PyObject *op) -{ - destructor dealloc = Py_TYPE(op)->tp_dealloc; -#ifdef Py_TRACE_REFS - _Py_ForgetReference(op); #else - _Py_INC_TPFREES(op); -#endif - (*dealloc)(op); -} - -# define _Py_Dealloc(op) _Py_Dealloc_inline(op) +#define _Py_Dealloc(op) ( \ + _Py_INC_TPFREES(op) _Py_COUNT_ALLOCS_COMMA \ + (*Py_TYPE(op)->tp_dealloc)((PyObject *)(op))) +#endif /* !Py_TRACE_REFS */ #endif /* !defined(Py_LIMITED_API) */ -static inline void _Py_INCREF(PyObject *op) -{ - _Py_INC_REFTOTAL; - op->ob_refcnt++; -} - -#define Py_INCREF(op) _Py_INCREF(_PyObject_CAST(op)) +#define Py_INCREF(op) ( \ + _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \ + ((PyObject *)(op))->ob_refcnt++) -static inline void _Py_DECREF(const char *filename, int lineno, - PyObject *op) -{ - _Py_DEC_REFTOTAL; - if (--op->ob_refcnt != 0) { -#ifdef Py_REF_DEBUG - if (op->ob_refcnt < 0) { - _Py_NegativeRefcount(filename, lineno, op); - } -#endif - } - else { - _Py_Dealloc(op); - } -} - -#define Py_DECREF(op) _Py_DECREF(__FILE__, __LINE__, _PyObject_CAST(op)) +#define Py_DECREF(op) \ + do { \ + PyObject *_py_decref_tmp = (PyObject *)(op); \ + if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \ + --(_py_decref_tmp)->ob_refcnt != 0) \ + _Py_CHECK_REFCNT(_py_decref_tmp) \ + else \ + _Py_Dealloc(_py_decref_tmp); \ + } while (0) /* Safely decref `op` and set `op` to NULL, especially useful in tp_clear @@ -885,23 +866,19 @@ static inline void _Py_DECREF(const char *filename, int lineno, } while (0) /* Function to use in case the object pointer can be NULL: */ -static inline void _Py_XINCREF(PyObject *op) -{ - if (op != NULL) { - Py_INCREF(op); - } -} - -#define Py_XINCREF(op) _Py_XINCREF(_PyObject_CAST(op)) - -static inline void _Py_XDECREF(PyObject *op) -{ - if (op != NULL) { - Py_DECREF(op); - } -} +#define Py_XINCREF(op) \ + do { \ + PyObject *_py_xincref_tmp = (PyObject *)(op); \ + if (_py_xincref_tmp != NULL) \ + Py_INCREF(_py_xincref_tmp); \ + } while (0) -#define Py_XDECREF(op) _Py_XDECREF(_PyObject_CAST(op)) +#define Py_XDECREF(op) \ + do { \ + PyObject *_py_xdecref_tmp = (PyObject *)(op); \ + if (_py_xdecref_tmp != NULL) \ + Py_DECREF(_py_xdecref_tmp); \ + } while (0) #ifndef Py_LIMITED_API /* Safely decref `op` and set `op` to `op2`. diff --git a/Include/objimpl.h b/Include/objimpl.h index 1c50d8bd6c045e..279dc34b295fd0 100644 --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -144,23 +144,10 @@ PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t); See also pymem.h. These inline functions expect non-NULL object pointers. */ -static inline PyObject* -PyObject_INIT(PyObject *op, PyTypeObject *typeobj) -{ - assert(op != NULL); - Py_TYPE(op) = typeobj; - _Py_NewReference(op); - return op; -} - -static inline PyVarObject* -PyObject_INIT_VAR(PyVarObject *op, PyTypeObject *typeobj, Py_ssize_t size) -{ - assert(op != NULL); - Py_SIZE(op) = size; - PyObject_INIT((PyObject *)op, typeobj); - return op; -} +#define PyObject_INIT(op, typeobj) \ + ( Py_TYPE(op) = (typeobj), _Py_NewReference((PyObject *)(op)), (op) ) +#define PyObject_INIT_VAR(op, typeobj, size) \ + ( Py_SIZE(op) = (size), PyObject_INIT((op), (typeobj)) ) #define _PyObject_SIZE(typeobj) ( (typeobj)->tp_basicsize )