• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef Py_INTERNAL_OBJECT_H
2 #define Py_INTERNAL_OBJECT_H
3 #ifdef __cplusplus
4 extern "C" {
5 #endif
6 
7 #ifndef Py_BUILD_CORE
8 #  error "this header requires Py_BUILD_CORE define"
9 #endif
10 
11 #include "pycore_gc.h"         // _PyObject_GC_IS_TRACKED()
12 #include "pycore_interp.h"     // PyInterpreterState.gc
13 #include "pycore_pystate.h"    // _PyThreadState_GET()
14 
15 PyAPI_FUNC(int) _PyType_CheckConsistency(PyTypeObject *type);
16 PyAPI_FUNC(int) _PyDict_CheckConsistency(PyObject *mp, int check_content);
17 
18 /* Tell the GC to track this object.
19  *
20  * NB: While the object is tracked by the collector, it must be safe to call the
21  * ob_traverse method.
22  *
23  * Internal note: interp->gc.generation0->_gc_prev doesn't have any bit flags
24  * because it's not object header.  So we don't use _PyGCHead_PREV() and
25  * _PyGCHead_SET_PREV() for it to avoid unnecessary bitwise operations.
26  *
27  * The PyObject_GC_Track() function is the public version of this macro.
28  */
_PyObject_GC_TRACK_impl(const char * filename,int lineno,PyObject * op)29 static inline void _PyObject_GC_TRACK_impl(const char *filename, int lineno,
30                                            PyObject *op)
31 {
32     _PyObject_ASSERT_FROM(op, !_PyObject_GC_IS_TRACKED(op),
33                           "object already tracked by the garbage collector",
34                           filename, lineno, "_PyObject_GC_TRACK");
35 
36     PyGC_Head *gc = _Py_AS_GC(op);
37     _PyObject_ASSERT_FROM(op,
38                           (gc->_gc_prev & _PyGC_PREV_MASK_COLLECTING) == 0,
39                           "object is in generation which is garbage collected",
40                           filename, lineno, "_PyObject_GC_TRACK");
41 
42     PyThreadState *tstate = _PyThreadState_GET();
43     PyGC_Head *generation0 = tstate->interp->gc.generation0;
44     PyGC_Head *last = (PyGC_Head*)(generation0->_gc_prev);
45     _PyGCHead_SET_NEXT(last, gc);
46     _PyGCHead_SET_PREV(gc, last);
47     _PyGCHead_SET_NEXT(gc, generation0);
48     generation0->_gc_prev = (uintptr_t)gc;
49 }
50 
51 #define _PyObject_GC_TRACK(op) \
52     _PyObject_GC_TRACK_impl(__FILE__, __LINE__, _PyObject_CAST(op))
53 
54 /* Tell the GC to stop tracking this object.
55  *
56  * Internal note: This may be called while GC. So _PyGC_PREV_MASK_COLLECTING
57  * must be cleared. But _PyGC_PREV_MASK_FINALIZED bit is kept.
58  *
59  * The object must be tracked by the GC.
60  *
61  * The PyObject_GC_UnTrack() function is the public version of this macro.
62  */
_PyObject_GC_UNTRACK_impl(const char * filename,int lineno,PyObject * op)63 static inline void _PyObject_GC_UNTRACK_impl(const char *filename, int lineno,
64                                              PyObject *op)
65 {
66     _PyObject_ASSERT_FROM(op, _PyObject_GC_IS_TRACKED(op),
67                           "object not tracked by the garbage collector",
68                           filename, lineno, "_PyObject_GC_UNTRACK");
69 
70     PyGC_Head *gc = _Py_AS_GC(op);
71     PyGC_Head *prev = _PyGCHead_PREV(gc);
72     PyGC_Head *next = _PyGCHead_NEXT(gc);
73     _PyGCHead_SET_NEXT(prev, next);
74     _PyGCHead_SET_PREV(next, prev);
75     gc->_gc_next = 0;
76     gc->_gc_prev &= _PyGC_PREV_MASK_FINALIZED;
77 }
78 
79 #define _PyObject_GC_UNTRACK(op) \
80     _PyObject_GC_UNTRACK_impl(__FILE__, __LINE__, _PyObject_CAST(op))
81 
82 #ifdef Py_REF_DEBUG
83 extern void _PyDebug_PrintTotalRefs(void);
84 #endif
85 
86 #ifdef Py_TRACE_REFS
87 extern void _Py_AddToAllObjects(PyObject *op, int force);
88 extern void _Py_PrintReferences(FILE *);
89 extern void _Py_PrintReferenceAddresses(FILE *);
90 #endif
91 
92 static inline PyObject **
_PyObject_GET_WEAKREFS_LISTPTR(PyObject * op)93 _PyObject_GET_WEAKREFS_LISTPTR(PyObject *op)
94 {
95     Py_ssize_t offset = Py_TYPE(op)->tp_weaklistoffset;
96     return (PyObject **)((char *)op + offset);
97 }
98 
99 // Fast inlined version of PyType_HasFeature()
100 static inline int
_PyType_HasFeature(PyTypeObject * type,unsigned long feature)101 _PyType_HasFeature(PyTypeObject *type, unsigned long feature) {
102     return ((type->tp_flags & feature) != 0);
103 }
104 
105 // Fast inlined version of PyObject_IS_GC()
106 static inline int
_PyObject_IS_GC(PyObject * obj)107 _PyObject_IS_GC(PyObject *obj)
108 {
109     return (PyType_IS_GC(Py_TYPE(obj))
110             && (Py_TYPE(obj)->tp_is_gc == NULL
111                 || Py_TYPE(obj)->tp_is_gc(obj)));
112 }
113 
114 // Fast inlined version of PyType_IS_GC()
115 #define _PyType_IS_GC(t) _PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC)
116 
117 #ifdef __cplusplus
118 }
119 #endif
120 #endif /* !Py_INTERNAL_OBJECT_H */
121