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 )