cpython/Include/cpython/object.h

#ifndef Py_CPYTHON_OBJECT_H
#  error "this header file must not be included directly"
#endif

PyAPI_FUNC(void) _Py_NewReference(PyObject *op);
PyAPI_FUNC(void) _Py_NewReferenceNoTotal(PyObject *op);
PyAPI_FUNC(void) _Py_ResurrectReference(PyObject *op);

#ifdef Py_REF_DEBUG
/* These are useful as debugging aids when chasing down refleaks. */
PyAPI_FUNC(Py_ssize_t) _Py_GetGlobalRefTotal(void);
#define _Py_GetRefTotal
PyAPI_FUNC(Py_ssize_t) _Py_GetLegacyRefTotal(void);
PyAPI_FUNC(Py_ssize_t) _PyInterpreterState_GetRefTotal(PyInterpreterState *);
#endif


/********************* String Literals ****************************************/
/* This structure helps managing static strings. The basic usage goes like this:
   Instead of doing

       r = PyObject_CallMethod(o, "foo", "args", ...);

   do

       _Py_IDENTIFIER(foo);
       ...
       r = _PyObject_CallMethodId(o, &PyId_foo, "args", ...);

   PyId_foo is a static variable, either on block level or file level. On first
   usage, the string "foo" is interned, and the structures are linked. On interpreter
   shutdown, all strings are released.

   Alternatively, _Py_static_string allows choosing the variable name.
   _PyUnicode_FromId returns a borrowed reference to the interned string.
   _PyObject_{Get,Set,Has}AttrId are __getattr__ versions using _Py_Identifier*.
*/
_Py_Identifier;

#ifndef Py_BUILD_CORE
// For now we are keeping _Py_IDENTIFIER for continued use
// in non-builtin extensions (and naughty PyPI modules).

#define _Py_static_string_init
#define _Py_static_string
#define _Py_IDENTIFIER

#endif /* !Py_BUILD_CORE */


PyNumberMethods;

PySequenceMethods;

PyMappingMethods;

sendfunc;

PyAsyncMethods;

PyBufferProcs;

/* Allow printfunc in the tp_vectorcall_offset slot for
 * backwards-compatibility */
printfunc;

// If this structure is modified, Doc/includes/typestruct.h should be updated
// as well.
struct _typeobject {};

/* This struct is used by the specializer
 * It should be treated as an opaque blob
 * by code other than the specializer and interpreter. */
struct _specialization_cache {};

/* The *real* layout of a type object when allocated on the heap */
PyHeapTypeObject;

PyAPI_FUNC(const char *) _PyType_Name(PyTypeObject *);
PyAPI_FUNC(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *);
PyAPI_FUNC(PyObject *) _PyType_LookupRef(PyTypeObject *, PyObject *);
PyAPI_FUNC(PyObject *) PyType_GetDict(PyTypeObject *);

PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);
PyAPI_FUNC(void) _Py_BreakPoint(void);
PyAPI_FUNC(void) _PyObject_Dump(PyObject *);

PyAPI_FUNC(PyObject*) _PyObject_GetAttrId(PyObject *, _Py_Identifier *);

PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *);
PyAPI_FUNC(void) PyObject_CallFinalizer(PyObject *);
PyAPI_FUNC(int) PyObject_CallFinalizerFromDealloc(PyObject *);

PyAPI_FUNC(void) PyUnstable_Object_ClearWeakRefsNoCallbacks(PyObject *);

/* Same as PyObject_Generic{Get,Set}Attr, but passing the attributes
   dict as the last parameter. */
PyAPI_FUNC(PyObject *)
_PyObject_GenericGetAttrWithDict(PyObject *, PyObject *, PyObject *, int);
PyAPI_FUNC(int)
_PyObject_GenericSetAttrWithDict(PyObject *, PyObject *,
                                 PyObject *, PyObject *);

PyAPI_FUNC(PyObject *) _PyObject_FunctionStr(PyObject *);

/* Safely decref `dst` and set `dst` to `src`.
 *
 * As in case of Py_CLEAR "the obvious" code can be deadly:
 *
 *     Py_DECREF(dst);
 *     dst = src;
 *
 * The safe way is:
 *
 *      Py_SETREF(dst, src);
 *
 * That arranges to set `dst` to `src` _before_ decref'ing, so that any code
 * triggered as a side-effect of `dst` getting torn down no longer believes
 * `dst` points to a valid object.
 *
 * Temporary variables are used to only evaluate macro arguments once and so
 * avoid the duplication of side effects. _Py_TYPEOF() or memcpy() is used to
 * avoid a miscompilation caused by type punning. See Py_CLEAR() comment for
 * implementation details about type punning.
 *
 * The memcpy() implementation does not emit a compiler warning if 'src' has
 * not the same type than 'src': any pointer type is accepted for 'src'.
 */
#ifdef _Py_TYPEOF
#define Py_SETREF(dst, src)
#else
#define Py_SETREF
#endif

/* Py_XSETREF() is a variant of Py_SETREF() that uses Py_XDECREF() instead of
 * Py_DECREF().
 */
#ifdef _Py_TYPEOF
#define Py_XSETREF(dst, src)
#else
#define Py_XSETREF
#endif


/* Define a pair of assertion macros:
   _PyObject_ASSERT_FROM(), _PyObject_ASSERT_WITH_MSG() and _PyObject_ASSERT().

   These work like the regular C assert(), in that they will abort the
   process with a message on stderr if the given condition fails to hold,
   but compile away to nothing if NDEBUG is defined.

   However, before aborting, Python will also try to call _PyObject_Dump() on
   the given object.  This may be of use when investigating bugs in which a
   particular object is corrupt (e.g. buggy a tp_visit method in an extension
   module breaking the garbage collector), to help locate the broken objects.

   The WITH_MSG variant allows you to supply an additional message that Python
   will attempt to print to stderr, after the object dump. */
#ifdef NDEBUG
   /* No debugging: compile away the assertions: */
#define _PyObject_ASSERT_FROM(obj, expr, msg, filename, lineno, func)
#else
   /* With debugging: generate checks: */
#define _PyObject_ASSERT_FROM
#endif

#define _PyObject_ASSERT_WITH_MSG(obj, expr, msg)
#define _PyObject_ASSERT(obj, expr)

#define _PyObject_ASSERT_FAILED_MSG(obj, msg)

/* Declare and define _PyObject_AssertFailed() even when NDEBUG is defined,
   to avoid causing compiler/linker errors when building extensions without
   NDEBUG against a Python built with NDEBUG defined.

   msg, expr and function can be NULL. */
PyAPI_FUNC(void) _Py_NO_RETURN _PyObject_AssertFailed(
    PyObject *obj,
    const char *expr,
    const char *msg,
    const char *file,
    int line,
    const char *function);


/* Trashcan mechanism, thanks to Christian Tismer.

When deallocating a container object, it's possible to trigger an unbounded
chain of deallocations, as each Py_DECREF in turn drops the refcount on "the
next" object in the chain to 0.  This can easily lead to stack overflows,
especially in threads (which typically have less stack space to work with).

A container object can avoid this by bracketing the body of its tp_dealloc
function with a pair of macros:

static void
mytype_dealloc(mytype *p)
{
    ... declarations go here ...

    PyObject_GC_UnTrack(p);        // must untrack first
    Py_TRASHCAN_BEGIN(p, mytype_dealloc)
    ... The body of the deallocator goes here, including all calls ...
    ... to Py_DECREF on contained objects.                         ...
    Py_TRASHCAN_END                // there should be no code after this
}

CAUTION:  Never return from the middle of the body!  If the body needs to
"get out early", put a label immediately before the Py_TRASHCAN_END
call, and goto it.  Else the call-depth counter (see below) will stay
above 0 forever, and the trashcan will never get emptied.

How it works:  The BEGIN macro increments a call-depth counter.  So long
as this counter is small, the body of the deallocator is run directly without
further ado.  But if the counter gets large, it instead adds p to a list of
objects to be deallocated later, skips the body of the deallocator, and
resumes execution after the END macro.  The tp_dealloc routine then returns
without deallocating anything (and so unbounded call-stack depth is avoided).

When the call stack finishes unwinding again, code generated by the END macro
notices this, and calls another routine to deallocate all the objects that
may have been added to the list of deferred deallocations.  In effect, a
chain of N deallocations is broken into (N-1)/(Py_TRASHCAN_HEADROOM-1) pieces,
with the call stack never exceeding a depth of Py_TRASHCAN_HEADROOM.

Since the tp_dealloc of a subclass typically calls the tp_dealloc of the base
class, we need to ensure that the trashcan is only triggered on the tp_dealloc
of the actual class being deallocated. Otherwise we might end up with a
partially-deallocated object. To check this, the tp_dealloc function must be
passed as second argument to Py_TRASHCAN_BEGIN().
*/

/* Python 3.9 private API, invoked by the macros below. */
PyAPI_FUNC(int) _PyTrash_begin(PyThreadState *tstate, PyObject *op);
PyAPI_FUNC(void) _PyTrash_end(PyThreadState *tstate);

PyAPI_FUNC(void) _PyTrash_thread_deposit_object(PyThreadState *tstate, PyObject *op);
PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(PyThreadState *tstate);


/* Python 3.10 private API, invoked by the Py_TRASHCAN_BEGIN(). */

/* To avoid raising recursion errors during dealloc trigger trashcan before we reach
 * recursion limit. To avoid trashing, we don't attempt to empty the trashcan until
 * we have headroom above the trigger limit */
#define Py_TRASHCAN_HEADROOM

#define Py_TRASHCAN_BEGIN(op, dealloc)
    /* The body of the deallocator is here. */
#define Py_TRASHCAN_END


PyAPI_FUNC(void *) PyObject_GetItemData(PyObject *obj);

PyAPI_FUNC(int) PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg);
PyAPI_FUNC(int) _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict);
PyAPI_FUNC(void) PyObject_ClearManagedDict(PyObject *obj);

#define TYPE_MAX_WATCHERS

PyType_WatchCallback;
PyAPI_FUNC(int) PyType_AddWatcher(PyType_WatchCallback callback);
PyAPI_FUNC(int) PyType_ClearWatcher(int watcher_id);
PyAPI_FUNC(int) PyType_Watch(int watcher_id, PyObject *type);
PyAPI_FUNC(int) PyType_Unwatch(int watcher_id, PyObject *type);

/* Attempt to assign a version tag to the given type.
 *
 * Returns 1 if the type already had a valid version tag or a new one was
 * assigned, or 0 if a new tag could not be assigned.
 */
PyAPI_FUNC(int) PyUnstable_Type_AssignVersionTag(PyTypeObject *type);


PyRefTracerEvent;

PyRefTracer;
PyAPI_FUNC(int) PyRefTracer_SetTracer(PyRefTracer tracer, void *data);
PyAPI_FUNC(PyRefTracer) PyRefTracer_GetTracer(void**);

/* Enable PEP-703 deferred reference counting on the object.
 *
 * Returns 1 if deferred reference counting was successfully enabled, and
 * 0 if the runtime ignored it. This function cannot fail.
 */
PyAPI_FUNC(int) PyUnstable_Object_EnableDeferredRefcount(PyObject *);