diff options
author | Victor Stinner <vstinner@redhat.com> | 2018-11-22 00:02:54 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-11-22 00:02:54 (GMT) |
commit | 271753a27aca2e13275f0827080b915fb438107a (patch) | |
tree | 63bb4ea49b621175c73e6a696466e5ef997ba911 /Include/internal | |
parent | f1d002c1e094922b0f17a820f90ff102d68ab253 (diff) | |
download | cpython-271753a27aca2e13275f0827080b915fb438107a.zip cpython-271753a27aca2e13275f0827080b915fb438107a.tar.gz cpython-271753a27aca2e13275f0827080b915fb438107a.tar.bz2 |
bpo-35059: Convert _PyObject_GC_TRACK() to inline function (GH-10643)
* Add _PyObject_ASSERT_FROM() and _PyObject_ASSERT_FAILED_MSG()
macros.
* PyObject_GC_Track() now calls _PyObject_ASSERT_FAILED_MSG(),
instead of Py_FatalError(), if the object is already tracked, to
dump more information on error.
* _PyObject_GC_TRACK() no longer checks if the object is already
tracked at runtime, use an assertion instead for best performances;
PyObject_GC_Track() still checks at runtime.
* pycore_object.h now includes pycore_pystate.h.
* Convert _PyObject_GC_TRACK() and _PyObject_GC_UNTRACK() macros to
inline functions.
Diffstat (limited to 'Include/internal')
-rw-r--r-- | Include/internal/pycore_object.h | 70 |
1 files changed, 46 insertions, 24 deletions
diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index a263834..347ab68 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -8,6 +8,8 @@ extern "C" { # error "this header requires Py_BUILD_CORE or Py_BUILD_CORE_BUILTIN defined" #endif +#include "pycore_pystate.h" /* _PyRuntime */ + /* Tell the GC to track this object. * * NB: While the object is tracked by the collector, it must be safe to call the @@ -19,36 +21,56 @@ extern "C" { * * The PyObject_GC_Track() function is the public version of this macro. */ -#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); +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 *)(op)) /* Tell the GC to stop tracking this object. * - * Internal note: This may be called while GC. So _PyGC_PREV_MASK_COLLECTING must - * be cleared. But _PyGC_PREV_MASK_FINALIZED bit is kept. + * Internal note: This may be called while GC. So _PyGC_PREV_MASK_COLLECTING + * must be cleared. But _PyGC_PREV_MASK_FINALIZED bit is kept. + * + * The object must be tracked by the GC. * * The PyObject_GC_UnTrack() function is the public version of this macro. */ -#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); +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 *)(op)) #ifdef __cplusplus } |