diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
commit | 718c552901d703c502ccbefdfc3c9028d608b947 (patch) | |
tree | 46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/tools/python3/src/Objects/object.c | |
parent | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff) | |
download | ydb-718c552901d703c502ccbefdfc3c9028d608b947.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/tools/python3/src/Objects/object.c')
-rw-r--r-- | contrib/tools/python3/src/Objects/object.c | 3324 |
1 files changed, 1662 insertions, 1662 deletions
diff --git a/contrib/tools/python3/src/Objects/object.c b/contrib/tools/python3/src/Objects/object.c index 623ee52eb1..e0c362e5fd 100644 --- a/contrib/tools/python3/src/Objects/object.c +++ b/contrib/tools/python3/src/Objects/object.c @@ -1,7 +1,7 @@ - -/* Generic object operations; and implementation of None */ - -#include "Python.h" + +/* Generic object operations; and implementation of None */ + +#include "Python.h" #include "pycore_ceval.h" // _Py_EnterRecursiveCall() #include "pycore_context.h" #include "pycore_initconfig.h" @@ -10,21 +10,21 @@ #include "pycore_pylifecycle.h" #include "pycore_pymem.h" // _PyMem_IsPtrFreed() #include "pycore_pystate.h" // _PyThreadState_GET() -#include "frameobject.h" +#include "frameobject.h" #include "interpreteridobject.h" - -#ifdef __cplusplus -extern "C" { -#endif - + +#ifdef __cplusplus +extern "C" { +#endif + /* Defined in tracemalloc.c */ extern void _PyMem_DumpTraceback(int fd, const void *ptr); -_Py_IDENTIFIER(Py_Repr); -_Py_IDENTIFIER(__bytes__); -_Py_IDENTIFIER(__dir__); -_Py_IDENTIFIER(__isabstractmethod__); - +_Py_IDENTIFIER(Py_Repr); +_Py_IDENTIFIER(__bytes__); +_Py_IDENTIFIER(__dir__); +_Py_IDENTIFIER(__isabstractmethod__); + int _PyObject_CheckConsistency(PyObject *op, int check_content) @@ -49,169 +49,169 @@ _PyObject_CheckConsistency(PyObject *op, int check_content) } -#ifdef Py_REF_DEBUG -Py_ssize_t _Py_RefTotal; - -Py_ssize_t -_Py_GetRefTotal(void) -{ - PyObject *o; - Py_ssize_t total = _Py_RefTotal; - o = _PySet_Dummy; - if (o != NULL) +#ifdef Py_REF_DEBUG +Py_ssize_t _Py_RefTotal; + +Py_ssize_t +_Py_GetRefTotal(void) +{ + PyObject *o; + Py_ssize_t total = _Py_RefTotal; + o = _PySet_Dummy; + if (o != NULL) total -= Py_REFCNT(o); - return total; -} - -void -_PyDebug_PrintTotalRefs(void) { - fprintf(stderr, - "[%" PY_FORMAT_SIZE_T "d refs, " - "%" PY_FORMAT_SIZE_T "d blocks]\n", - _Py_GetRefTotal(), _Py_GetAllocatedBlocks()); -} -#endif /* Py_REF_DEBUG */ - -/* Object allocation routines used by NEWOBJ and NEWVAROBJ macros. - These are used by the individual routines for object creation. - Do not call them otherwise, they do not initialize the object! */ - -#ifdef Py_TRACE_REFS -/* Head of circular doubly-linked list of all objects. These are linked - * together via the _ob_prev and _ob_next members of a PyObject, which - * exist only in a Py_TRACE_REFS build. - */ -static PyObject refchain = {&refchain, &refchain}; - -/* Insert op at the front of the list of all objects. If force is true, - * op is added even if _ob_prev and _ob_next are non-NULL already. If - * force is false amd _ob_prev or _ob_next are non-NULL, do nothing. - * force should be true if and only if op points to freshly allocated, - * uninitialized memory, or you've unlinked op from the list and are - * relinking it into the front. - * Note that objects are normally added to the list via _Py_NewReference, - * which is called by PyObject_Init. Not all objects are initialized that - * way, though; exceptions include statically allocated type objects, and - * statically allocated singletons (like Py_True and Py_None). - */ -void -_Py_AddToAllObjects(PyObject *op, int force) -{ -#ifdef Py_DEBUG - if (!force) { - /* If it's initialized memory, op must be in or out of - * the list unambiguously. - */ + return total; +} + +void +_PyDebug_PrintTotalRefs(void) { + fprintf(stderr, + "[%" PY_FORMAT_SIZE_T "d refs, " + "%" PY_FORMAT_SIZE_T "d blocks]\n", + _Py_GetRefTotal(), _Py_GetAllocatedBlocks()); +} +#endif /* Py_REF_DEBUG */ + +/* Object allocation routines used by NEWOBJ and NEWVAROBJ macros. + These are used by the individual routines for object creation. + Do not call them otherwise, they do not initialize the object! */ + +#ifdef Py_TRACE_REFS +/* Head of circular doubly-linked list of all objects. These are linked + * together via the _ob_prev and _ob_next members of a PyObject, which + * exist only in a Py_TRACE_REFS build. + */ +static PyObject refchain = {&refchain, &refchain}; + +/* Insert op at the front of the list of all objects. If force is true, + * op is added even if _ob_prev and _ob_next are non-NULL already. If + * force is false amd _ob_prev or _ob_next are non-NULL, do nothing. + * force should be true if and only if op points to freshly allocated, + * uninitialized memory, or you've unlinked op from the list and are + * relinking it into the front. + * Note that objects are normally added to the list via _Py_NewReference, + * which is called by PyObject_Init. Not all objects are initialized that + * way, though; exceptions include statically allocated type objects, and + * statically allocated singletons (like Py_True and Py_None). + */ +void +_Py_AddToAllObjects(PyObject *op, int force) +{ +#ifdef Py_DEBUG + if (!force) { + /* If it's initialized memory, op must be in or out of + * the list unambiguously. + */ _PyObject_ASSERT(op, (op->_ob_prev == NULL) == (op->_ob_next == NULL)); - } -#endif - if (force || op->_ob_prev == NULL) { - op->_ob_next = refchain._ob_next; - op->_ob_prev = &refchain; - refchain._ob_next->_ob_prev = op; - refchain._ob_next = op; - } -} -#endif /* Py_TRACE_REFS */ - -#ifdef Py_REF_DEBUG -/* Log a fatal error; doesn't return. */ -void + } +#endif + if (force || op->_ob_prev == NULL) { + op->_ob_next = refchain._ob_next; + op->_ob_prev = &refchain; + refchain._ob_next->_ob_prev = op; + refchain._ob_next = op; + } +} +#endif /* Py_TRACE_REFS */ + +#ifdef Py_REF_DEBUG +/* Log a fatal error; doesn't return. */ +void _Py_NegativeRefcount(const char *filename, int lineno, PyObject *op) -{ +{ _PyObject_AssertFailed(op, NULL, "object has negative ref count", filename, lineno, __func__); -} - -#endif /* Py_REF_DEBUG */ - -void -Py_IncRef(PyObject *o) -{ - Py_XINCREF(o); -} - -void -Py_DecRef(PyObject *o) -{ - Py_XDECREF(o); -} - -PyObject * -PyObject_Init(PyObject *op, PyTypeObject *tp) -{ +} + +#endif /* Py_REF_DEBUG */ + +void +Py_IncRef(PyObject *o) +{ + Py_XINCREF(o); +} + +void +Py_DecRef(PyObject *o) +{ + Py_XDECREF(o); +} + +PyObject * +PyObject_Init(PyObject *op, PyTypeObject *tp) +{ /* Any changes should be reflected in PyObject_INIT() macro */ if (op == NULL) { - return PyErr_NoMemory(); + return PyErr_NoMemory(); } return PyObject_INIT(op, tp); -} - -PyVarObject * -PyObject_InitVar(PyVarObject *op, PyTypeObject *tp, Py_ssize_t size) -{ +} + +PyVarObject * +PyObject_InitVar(PyVarObject *op, PyTypeObject *tp, Py_ssize_t size) +{ /* Any changes should be reflected in PyObject_INIT_VAR() macro */ if (op == NULL) { - return (PyVarObject *) PyErr_NoMemory(); + return (PyVarObject *) PyErr_NoMemory(); } return PyObject_INIT_VAR(op, tp, size); -} - -PyObject * -_PyObject_New(PyTypeObject *tp) -{ +} + +PyObject * +_PyObject_New(PyTypeObject *tp) +{ PyObject *op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp)); if (op == NULL) { - return PyErr_NoMemory(); + return PyErr_NoMemory(); } PyObject_INIT(op, tp); return op; -} - -PyVarObject * -_PyObject_NewVar(PyTypeObject *tp, Py_ssize_t nitems) -{ - PyVarObject *op; - const size_t size = _PyObject_VAR_SIZE(tp, nitems); - op = (PyVarObject *) PyObject_MALLOC(size); - if (op == NULL) - return (PyVarObject *)PyErr_NoMemory(); - return PyObject_INIT_VAR(op, tp, nitems); -} - -void -PyObject_CallFinalizer(PyObject *self) -{ - PyTypeObject *tp = Py_TYPE(self); - +} + +PyVarObject * +_PyObject_NewVar(PyTypeObject *tp, Py_ssize_t nitems) +{ + PyVarObject *op; + const size_t size = _PyObject_VAR_SIZE(tp, nitems); + op = (PyVarObject *) PyObject_MALLOC(size); + if (op == NULL) + return (PyVarObject *)PyErr_NoMemory(); + return PyObject_INIT_VAR(op, tp, nitems); +} + +void +PyObject_CallFinalizer(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + if (tp->tp_finalize == NULL) - return; - /* tp_finalize should only be called once. */ + return; + /* tp_finalize should only be called once. */ if (_PyType_IS_GC(tp) && _PyGC_FINALIZED(self)) - return; - - tp->tp_finalize(self); + return; + + tp->tp_finalize(self); if (_PyType_IS_GC(tp)) { _PyGC_SET_FINALIZED(self); } -} - -int -PyObject_CallFinalizerFromDealloc(PyObject *self) -{ +} + +int +PyObject_CallFinalizerFromDealloc(PyObject *self) +{ if (Py_REFCNT(self) != 0) { _PyObject_ASSERT_FAILED_MSG(self, "PyObject_CallFinalizerFromDealloc called " "on object with a non-zero refcount"); } - - /* Temporarily resurrect the object. */ + + /* Temporarily resurrect the object. */ Py_SET_REFCNT(self, 1); - - PyObject_CallFinalizer(self); - + + PyObject_CallFinalizer(self); + _PyObject_ASSERT_WITH_MSG(self, Py_REFCNT(self) > 0, "refcount is too small"); @@ -220,15 +220,15 @@ PyObject_CallFinalizerFromDealloc(PyObject *self) * cause a recursive call. */ Py_SET_REFCNT(self, Py_REFCNT(self) - 1); if (Py_REFCNT(self) == 0) { - return 0; /* this is the normal path out */ + return 0; /* this is the normal path out */ } - - /* tp_finalize resurrected it! Make it look like the original Py_DECREF + + /* tp_finalize resurrected it! Make it look like the original Py_DECREF * never happened. */ Py_ssize_t refcnt = Py_REFCNT(self); - _Py_NewReference(self); + _Py_NewReference(self); Py_SET_REFCNT(self, refcnt); - + _PyObject_ASSERT(self, (!_PyType_IS_GC(Py_TYPE(self)) || _PyObject_GC_IS_TRACKED(self))); @@ -236,132 +236,132 @@ PyObject_CallFinalizerFromDealloc(PyObject *self) _Py_RefTotal, so we need to undo that. */ #ifdef Py_REF_DEBUG _Py_RefTotal--; -#endif - return -1; -} - -int -PyObject_Print(PyObject *op, FILE *fp, int flags) -{ - int ret = 0; - if (PyErr_CheckSignals()) - return -1; -#ifdef USE_STACKCHECK - if (PyOS_CheckStack()) { - PyErr_SetString(PyExc_MemoryError, "stack overflow"); - return -1; - } -#endif - clearerr(fp); /* Clear any previous error condition */ - if (op == NULL) { - Py_BEGIN_ALLOW_THREADS - fprintf(fp, "<nil>"); - Py_END_ALLOW_THREADS - } - else { +#endif + return -1; +} + +int +PyObject_Print(PyObject *op, FILE *fp, int flags) +{ + int ret = 0; + if (PyErr_CheckSignals()) + return -1; +#ifdef USE_STACKCHECK + if (PyOS_CheckStack()) { + PyErr_SetString(PyExc_MemoryError, "stack overflow"); + return -1; + } +#endif + clearerr(fp); /* Clear any previous error condition */ + if (op == NULL) { + Py_BEGIN_ALLOW_THREADS + fprintf(fp, "<nil>"); + Py_END_ALLOW_THREADS + } + else { if (Py_REFCNT(op) <= 0) { - /* XXX(twouters) cast refcount to long until %zd is - universally available */ - Py_BEGIN_ALLOW_THREADS - fprintf(fp, "<refcnt %ld at %p>", + /* XXX(twouters) cast refcount to long until %zd is + universally available */ + Py_BEGIN_ALLOW_THREADS + fprintf(fp, "<refcnt %ld at %p>", (long)Py_REFCNT(op), (void *)op); - Py_END_ALLOW_THREADS + Py_END_ALLOW_THREADS } - else { - PyObject *s; - if (flags & Py_PRINT_RAW) - s = PyObject_Str(op); - else - s = PyObject_Repr(op); - if (s == NULL) - ret = -1; - else if (PyBytes_Check(s)) { - fwrite(PyBytes_AS_STRING(s), 1, - PyBytes_GET_SIZE(s), fp); - } - else if (PyUnicode_Check(s)) { - PyObject *t; - t = PyUnicode_AsEncodedString(s, "utf-8", "backslashreplace"); - if (t == NULL) { - ret = -1; - } - else { - fwrite(PyBytes_AS_STRING(t), 1, - PyBytes_GET_SIZE(t), fp); - Py_DECREF(t); - } - } - else { - PyErr_Format(PyExc_TypeError, - "str() or repr() returned '%.100s'", + else { + PyObject *s; + if (flags & Py_PRINT_RAW) + s = PyObject_Str(op); + else + s = PyObject_Repr(op); + if (s == NULL) + ret = -1; + else if (PyBytes_Check(s)) { + fwrite(PyBytes_AS_STRING(s), 1, + PyBytes_GET_SIZE(s), fp); + } + else if (PyUnicode_Check(s)) { + PyObject *t; + t = PyUnicode_AsEncodedString(s, "utf-8", "backslashreplace"); + if (t == NULL) { + ret = -1; + } + else { + fwrite(PyBytes_AS_STRING(t), 1, + PyBytes_GET_SIZE(t), fp); + Py_DECREF(t); + } + } + else { + PyErr_Format(PyExc_TypeError, + "str() or repr() returned '%.100s'", Py_TYPE(s)->tp_name); - ret = -1; - } - Py_XDECREF(s); - } - } - if (ret == 0) { - if (ferror(fp)) { - PyErr_SetFromErrno(PyExc_OSError); - clearerr(fp); - ret = -1; - } - } - return ret; -} - -/* For debugging convenience. Set a breakpoint here and call it from your DLL */ -void -_Py_BreakPoint(void) -{ -} - - + ret = -1; + } + Py_XDECREF(s); + } + } + if (ret == 0) { + if (ferror(fp)) { + PyErr_SetFromErrno(PyExc_OSError); + clearerr(fp); + ret = -1; + } + } + return ret; +} + +/* For debugging convenience. Set a breakpoint here and call it from your DLL */ +void +_Py_BreakPoint(void) +{ +} + + /* Heuristic checking if the object memory is uninitialized or deallocated. Rely on the debug hooks on Python memory allocators: see _PyMem_IsPtrFreed(). - - The function can be used to prevent segmentation fault on dereferencing + + The function can be used to prevent segmentation fault on dereferencing pointers like 0xDDDDDDDDDDDDDDDD. */ -int -_PyObject_IsFreed(PyObject *op) -{ +int +_PyObject_IsFreed(PyObject *op) +{ if (_PyMem_IsPtrFreed(op) || _PyMem_IsPtrFreed(Py_TYPE(op))) { - return 1; - } + return 1; + } /* ignore op->ob_ref: its value can have be modified - by Py_INCREF() and Py_DECREF(). */ -#ifdef Py_TRACE_REFS + by Py_INCREF() and Py_DECREF(). */ +#ifdef Py_TRACE_REFS if (op->_ob_next != NULL && _PyMem_IsPtrFreed(op->_ob_next)) { return 1; } if (op->_ob_prev != NULL && _PyMem_IsPtrFreed(op->_ob_prev)) { return 1; } -#endif +#endif return 0; -} - - -/* For debugging convenience. See Misc/gdbinit for some useful gdb hooks */ -void -_PyObject_Dump(PyObject* op) -{ - if (_PyObject_IsFreed(op)) { - /* It seems like the object memory has been freed: - don't access it to prevent a segmentation fault. */ +} + + +/* For debugging convenience. See Misc/gdbinit for some useful gdb hooks */ +void +_PyObject_Dump(PyObject* op) +{ + if (_PyObject_IsFreed(op)) { + /* It seems like the object memory has been freed: + don't access it to prevent a segmentation fault. */ fprintf(stderr, "<object at %p is freed>\n", op); fflush(stderr); - return; - } - + return; + } + /* first, write fields which are the least likely to crash */ fprintf(stderr, "object address : %p\n", (void *)op); /* XXX(twouters) cast refcount to long until %zd is universally available */ fprintf(stderr, "object refcount : %ld\n", (long)Py_REFCNT(op)); fflush(stderr); - + PyTypeObject *type = Py_TYPE(op); fprintf(stderr, "object type : %p\n", type); fprintf(stderr, "object type name: %s\n", @@ -369,195 +369,195 @@ _PyObject_Dump(PyObject* op) /* the most dangerous part */ fprintf(stderr, "object repr : "); - fflush(stderr); - + fflush(stderr); + PyGILState_STATE gil = PyGILState_Ensure(); PyObject *error_type, *error_value, *error_traceback; - PyErr_Fetch(&error_type, &error_value, &error_traceback); + PyErr_Fetch(&error_type, &error_value, &error_traceback); - (void)PyObject_Print(op, stderr, 0); - fflush(stderr); + (void)PyObject_Print(op, stderr, 0); + fflush(stderr); - PyErr_Restore(error_type, error_value, error_traceback); + PyErr_Restore(error_type, error_value, error_traceback); PyGILState_Release(gil); - + fprintf(stderr, "\n"); - fflush(stderr); -} - -PyObject * -PyObject_Repr(PyObject *v) -{ - PyObject *res; - if (PyErr_CheckSignals()) - return NULL; -#ifdef USE_STACKCHECK - if (PyOS_CheckStack()) { - PyErr_SetString(PyExc_MemoryError, "stack overflow"); - return NULL; - } -#endif - if (v == NULL) - return PyUnicode_FromString("<NULL>"); - if (Py_TYPE(v)->tp_repr == NULL) - return PyUnicode_FromFormat("<%s object at %p>", + fflush(stderr); +} + +PyObject * +PyObject_Repr(PyObject *v) +{ + PyObject *res; + if (PyErr_CheckSignals()) + return NULL; +#ifdef USE_STACKCHECK + if (PyOS_CheckStack()) { + PyErr_SetString(PyExc_MemoryError, "stack overflow"); + return NULL; + } +#endif + if (v == NULL) + return PyUnicode_FromString("<NULL>"); + if (Py_TYPE(v)->tp_repr == NULL) + return PyUnicode_FromFormat("<%s object at %p>", Py_TYPE(v)->tp_name, v); - + PyThreadState *tstate = _PyThreadState_GET(); -#ifdef Py_DEBUG - /* PyObject_Repr() must not be called with an exception set, - because it can clear it (directly or indirectly) and so the - caller loses its exception */ +#ifdef Py_DEBUG + /* PyObject_Repr() must not be called with an exception set, + because it can clear it (directly or indirectly) and so the + caller loses its exception */ assert(!_PyErr_Occurred(tstate)); -#endif - - /* It is possible for a type to have a tp_repr representation that loops - infinitely. */ +#endif + + /* It is possible for a type to have a tp_repr representation that loops + infinitely. */ if (_Py_EnterRecursiveCall(tstate, " while getting the repr of an object")) { - return NULL; + return NULL; } res = (*Py_TYPE(v)->tp_repr)(v); _Py_LeaveRecursiveCall(tstate); if (res == NULL) { - return NULL; + return NULL; } - if (!PyUnicode_Check(res)) { + if (!PyUnicode_Check(res)) { _PyErr_Format(tstate, PyExc_TypeError, "__repr__ returned non-string (type %.200s)", Py_TYPE(res)->tp_name); - Py_DECREF(res); - return NULL; - } -#ifndef Py_DEBUG + Py_DECREF(res); + return NULL; + } +#ifndef Py_DEBUG if (PyUnicode_READY(res) < 0) { - return NULL; - } -#endif - return res; -} - -PyObject * -PyObject_Str(PyObject *v) -{ - PyObject *res; - if (PyErr_CheckSignals()) - return NULL; -#ifdef USE_STACKCHECK - if (PyOS_CheckStack()) { - PyErr_SetString(PyExc_MemoryError, "stack overflow"); - return NULL; - } -#endif - if (v == NULL) - return PyUnicode_FromString("<NULL>"); - if (PyUnicode_CheckExact(v)) { -#ifndef Py_DEBUG - if (PyUnicode_READY(v) < 0) - return NULL; -#endif - Py_INCREF(v); - return v; - } - if (Py_TYPE(v)->tp_str == NULL) - return PyObject_Repr(v); - + return NULL; + } +#endif + return res; +} + +PyObject * +PyObject_Str(PyObject *v) +{ + PyObject *res; + if (PyErr_CheckSignals()) + return NULL; +#ifdef USE_STACKCHECK + if (PyOS_CheckStack()) { + PyErr_SetString(PyExc_MemoryError, "stack overflow"); + return NULL; + } +#endif + if (v == NULL) + return PyUnicode_FromString("<NULL>"); + if (PyUnicode_CheckExact(v)) { +#ifndef Py_DEBUG + if (PyUnicode_READY(v) < 0) + return NULL; +#endif + Py_INCREF(v); + return v; + } + if (Py_TYPE(v)->tp_str == NULL) + return PyObject_Repr(v); + PyThreadState *tstate = _PyThreadState_GET(); -#ifdef Py_DEBUG - /* PyObject_Str() must not be called with an exception set, - because it can clear it (directly or indirectly) and so the - caller loses its exception */ +#ifdef Py_DEBUG + /* PyObject_Str() must not be called with an exception set, + because it can clear it (directly or indirectly) and so the + caller loses its exception */ assert(!_PyErr_Occurred(tstate)); -#endif - - /* It is possible for a type to have a tp_str representation that loops - infinitely. */ +#endif + + /* It is possible for a type to have a tp_str representation that loops + infinitely. */ if (_Py_EnterRecursiveCall(tstate, " while getting the str of an object")) { - return NULL; + return NULL; } - res = (*Py_TYPE(v)->tp_str)(v); + res = (*Py_TYPE(v)->tp_str)(v); _Py_LeaveRecursiveCall(tstate); if (res == NULL) { - return NULL; + return NULL; } - if (!PyUnicode_Check(res)) { + if (!PyUnicode_Check(res)) { _PyErr_Format(tstate, PyExc_TypeError, "__str__ returned non-string (type %.200s)", Py_TYPE(res)->tp_name); - Py_DECREF(res); - return NULL; - } -#ifndef Py_DEBUG + Py_DECREF(res); + return NULL; + } +#ifndef Py_DEBUG if (PyUnicode_READY(res) < 0) { - return NULL; - } -#endif - assert(_PyUnicode_CheckConsistency(res, 1)); - return res; -} - -PyObject * -PyObject_ASCII(PyObject *v) -{ - PyObject *repr, *ascii, *res; - - repr = PyObject_Repr(v); - if (repr == NULL) - return NULL; - - if (PyUnicode_IS_ASCII(repr)) - return repr; - - /* repr is guaranteed to be a PyUnicode object by PyObject_Repr */ - ascii = _PyUnicode_AsASCIIString(repr, "backslashreplace"); - Py_DECREF(repr); - if (ascii == NULL) - return NULL; - - res = PyUnicode_DecodeASCII( - PyBytes_AS_STRING(ascii), - PyBytes_GET_SIZE(ascii), - NULL); - - Py_DECREF(ascii); - return res; -} - -PyObject * -PyObject_Bytes(PyObject *v) -{ - PyObject *result, *func; - - if (v == NULL) - return PyBytes_FromString("<NULL>"); - - if (PyBytes_CheckExact(v)) { - Py_INCREF(v); - return v; - } - - func = _PyObject_LookupSpecial(v, &PyId___bytes__); - if (func != NULL) { - result = _PyObject_CallNoArg(func); - Py_DECREF(func); - if (result == NULL) - return NULL; - if (!PyBytes_Check(result)) { - PyErr_Format(PyExc_TypeError, - "__bytes__ returned non-bytes (type %.200s)", - Py_TYPE(result)->tp_name); - Py_DECREF(result); - return NULL; - } - return result; - } - else if (PyErr_Occurred()) - return NULL; - return PyBytes_FromObject(v); -} - + return NULL; + } +#endif + assert(_PyUnicode_CheckConsistency(res, 1)); + return res; +} + +PyObject * +PyObject_ASCII(PyObject *v) +{ + PyObject *repr, *ascii, *res; + + repr = PyObject_Repr(v); + if (repr == NULL) + return NULL; + + if (PyUnicode_IS_ASCII(repr)) + return repr; + + /* repr is guaranteed to be a PyUnicode object by PyObject_Repr */ + ascii = _PyUnicode_AsASCIIString(repr, "backslashreplace"); + Py_DECREF(repr); + if (ascii == NULL) + return NULL; + + res = PyUnicode_DecodeASCII( + PyBytes_AS_STRING(ascii), + PyBytes_GET_SIZE(ascii), + NULL); + + Py_DECREF(ascii); + return res; +} + +PyObject * +PyObject_Bytes(PyObject *v) +{ + PyObject *result, *func; + + if (v == NULL) + return PyBytes_FromString("<NULL>"); + + if (PyBytes_CheckExact(v)) { + Py_INCREF(v); + return v; + } + + func = _PyObject_LookupSpecial(v, &PyId___bytes__); + if (func != NULL) { + result = _PyObject_CallNoArg(func); + Py_DECREF(func); + if (result == NULL) + return NULL; + if (!PyBytes_Check(result)) { + PyErr_Format(PyExc_TypeError, + "__bytes__ returned non-bytes (type %.200s)", + Py_TYPE(result)->tp_name); + Py_DECREF(result); + return NULL; + } + return result; + } + else if (PyErr_Occurred()) + return NULL; + return PyBytes_FromObject(v); +} + /* def _PyObject_FunctionStr(x): @@ -616,518 +616,518 @@ done: return result; } -/* For Python 3.0.1 and later, the old three-way comparison has been - completely removed in favour of rich comparisons. PyObject_Compare() and - PyObject_Cmp() are gone, and the builtin cmp function no longer exists. +/* For Python 3.0.1 and later, the old three-way comparison has been + completely removed in favour of rich comparisons. PyObject_Compare() and + PyObject_Cmp() are gone, and the builtin cmp function no longer exists. The old tp_compare slot has been renamed to tp_as_async, and should no - longer be used. Use tp_richcompare instead. - - See (*) below for practical amendments. - - tp_richcompare gets called with a first argument of the appropriate type - and a second object of an arbitrary type. We never do any kind of - coercion. - - The tp_richcompare slot should return an object, as follows: - - NULL if an exception occurred - NotImplemented if the requested comparison is not implemented - any other false value if the requested comparison is false - any other true value if the requested comparison is true - - The PyObject_RichCompare[Bool]() wrappers raise TypeError when they get - NotImplemented. - - (*) Practical amendments: - - - If rich comparison returns NotImplemented, == and != are decided by - comparing the object pointer (i.e. falling back to the base object - implementation). - -*/ - -/* Map rich comparison operators to their swapped version, e.g. LT <--> GT */ -int _Py_SwappedOp[] = {Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE}; - -static const char * const opstrings[] = {"<", "<=", "==", "!=", ">", ">="}; - -/* Perform a rich comparison, raising TypeError when the requested comparison - operator is not supported. */ -static PyObject * + longer be used. Use tp_richcompare instead. + + See (*) below for practical amendments. + + tp_richcompare gets called with a first argument of the appropriate type + and a second object of an arbitrary type. We never do any kind of + coercion. + + The tp_richcompare slot should return an object, as follows: + + NULL if an exception occurred + NotImplemented if the requested comparison is not implemented + any other false value if the requested comparison is false + any other true value if the requested comparison is true + + The PyObject_RichCompare[Bool]() wrappers raise TypeError when they get + NotImplemented. + + (*) Practical amendments: + + - If rich comparison returns NotImplemented, == and != are decided by + comparing the object pointer (i.e. falling back to the base object + implementation). + +*/ + +/* Map rich comparison operators to their swapped version, e.g. LT <--> GT */ +int _Py_SwappedOp[] = {Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE}; + +static const char * const opstrings[] = {"<", "<=", "==", "!=", ">", ">="}; + +/* Perform a rich comparison, raising TypeError when the requested comparison + operator is not supported. */ +static PyObject * do_richcompare(PyThreadState *tstate, PyObject *v, PyObject *w, int op) -{ - richcmpfunc f; - PyObject *res; - int checked_reverse_op = 0; - +{ + richcmpfunc f; + PyObject *res; + int checked_reverse_op = 0; + if (!Py_IS_TYPE(v, Py_TYPE(w)) && PyType_IsSubtype(Py_TYPE(w), Py_TYPE(v)) && (f = Py_TYPE(w)->tp_richcompare) != NULL) { - checked_reverse_op = 1; - res = (*f)(w, v, _Py_SwappedOp[op]); - if (res != Py_NotImplemented) - return res; - Py_DECREF(res); - } + checked_reverse_op = 1; + res = (*f)(w, v, _Py_SwappedOp[op]); + if (res != Py_NotImplemented) + return res; + Py_DECREF(res); + } if ((f = Py_TYPE(v)->tp_richcompare) != NULL) { - res = (*f)(v, w, op); - if (res != Py_NotImplemented) - return res; - Py_DECREF(res); - } + res = (*f)(v, w, op); + if (res != Py_NotImplemented) + return res; + Py_DECREF(res); + } if (!checked_reverse_op && (f = Py_TYPE(w)->tp_richcompare) != NULL) { - res = (*f)(w, v, _Py_SwappedOp[op]); - if (res != Py_NotImplemented) - return res; - Py_DECREF(res); - } - /* If neither object implements it, provide a sensible default - for == and !=, but raise an exception for ordering. */ - switch (op) { - case Py_EQ: - res = (v == w) ? Py_True : Py_False; - break; - case Py_NE: - res = (v != w) ? Py_True : Py_False; - break; - default: + res = (*f)(w, v, _Py_SwappedOp[op]); + if (res != Py_NotImplemented) + return res; + Py_DECREF(res); + } + /* If neither object implements it, provide a sensible default + for == and !=, but raise an exception for ordering. */ + switch (op) { + case Py_EQ: + res = (v == w) ? Py_True : Py_False; + break; + case Py_NE: + res = (v != w) ? Py_True : Py_False; + break; + default: _PyErr_Format(tstate, PyExc_TypeError, "'%s' not supported between instances of '%.100s' and '%.100s'", opstrings[op], Py_TYPE(v)->tp_name, Py_TYPE(w)->tp_name); - return NULL; - } - Py_INCREF(res); - return res; -} - -/* Perform a rich comparison with object result. This wraps do_richcompare() - with a check for NULL arguments and a recursion check. */ - -PyObject * -PyObject_RichCompare(PyObject *v, PyObject *w, int op) -{ + return NULL; + } + Py_INCREF(res); + return res; +} + +/* Perform a rich comparison with object result. This wraps do_richcompare() + with a check for NULL arguments and a recursion check. */ + +PyObject * +PyObject_RichCompare(PyObject *v, PyObject *w, int op) +{ PyThreadState *tstate = _PyThreadState_GET(); - - assert(Py_LT <= op && op <= Py_GE); - if (v == NULL || w == NULL) { + + assert(Py_LT <= op && op <= Py_GE); + if (v == NULL || w == NULL) { if (!_PyErr_Occurred(tstate)) { - PyErr_BadInternalCall(); + PyErr_BadInternalCall(); } - return NULL; - } + return NULL; + } if (_Py_EnterRecursiveCall(tstate, " in comparison")) { - return NULL; + return NULL; } PyObject *res = do_richcompare(tstate, v, w, op); _Py_LeaveRecursiveCall(tstate); - return res; -} - -/* Perform a rich comparison with integer result. This wraps - PyObject_RichCompare(), returning -1 for error, 0 for false, 1 for true. */ -int -PyObject_RichCompareBool(PyObject *v, PyObject *w, int op) -{ - PyObject *res; - int ok; - - /* Quick result when objects are the same. - Guarantees that identity implies equality. */ - if (v == w) { - if (op == Py_EQ) - return 1; - else if (op == Py_NE) - return 0; - } - - res = PyObject_RichCompare(v, w, op); - if (res == NULL) - return -1; - if (PyBool_Check(res)) - ok = (res == Py_True); - else - ok = PyObject_IsTrue(res); - Py_DECREF(res); - return ok; -} - -Py_hash_t -PyObject_HashNotImplemented(PyObject *v) -{ - PyErr_Format(PyExc_TypeError, "unhashable type: '%.200s'", - Py_TYPE(v)->tp_name); - return -1; -} - -Py_hash_t -PyObject_Hash(PyObject *v) -{ - PyTypeObject *tp = Py_TYPE(v); - if (tp->tp_hash != NULL) - return (*tp->tp_hash)(v); - /* To keep to the general practice that inheriting - * solely from object in C code should work without - * an explicit call to PyType_Ready, we implicitly call - * PyType_Ready here and then check the tp_hash slot again - */ - if (tp->tp_dict == NULL) { - if (PyType_Ready(tp) < 0) - return -1; - if (tp->tp_hash != NULL) - return (*tp->tp_hash)(v); - } - /* Otherwise, the object can't be hashed */ - return PyObject_HashNotImplemented(v); -} - -PyObject * -PyObject_GetAttrString(PyObject *v, const char *name) -{ - PyObject *w, *res; - - if (Py_TYPE(v)->tp_getattr != NULL) - return (*Py_TYPE(v)->tp_getattr)(v, (char*)name); - w = PyUnicode_FromString(name); - if (w == NULL) - return NULL; - res = PyObject_GetAttr(v, w); - Py_DECREF(w); - return res; -} - -int -PyObject_HasAttrString(PyObject *v, const char *name) -{ - PyObject *res = PyObject_GetAttrString(v, name); - if (res != NULL) { - Py_DECREF(res); - return 1; - } - PyErr_Clear(); - return 0; -} - -int -PyObject_SetAttrString(PyObject *v, const char *name, PyObject *w) -{ - PyObject *s; - int res; - - if (Py_TYPE(v)->tp_setattr != NULL) - return (*Py_TYPE(v)->tp_setattr)(v, (char*)name, w); - s = PyUnicode_InternFromString(name); - if (s == NULL) - return -1; - res = PyObject_SetAttr(v, s, w); - Py_XDECREF(s); - return res; -} - -int -_PyObject_IsAbstract(PyObject *obj) -{ - int res; - PyObject* isabstract; - - if (obj == NULL) - return 0; - - res = _PyObject_LookupAttrId(obj, &PyId___isabstractmethod__, &isabstract); - if (res > 0) { - res = PyObject_IsTrue(isabstract); - Py_DECREF(isabstract); - } - return res; -} - -PyObject * -_PyObject_GetAttrId(PyObject *v, _Py_Identifier *name) -{ - PyObject *result; - PyObject *oname = _PyUnicode_FromId(name); /* borrowed */ - if (!oname) - return NULL; - result = PyObject_GetAttr(v, oname); - return result; -} - -int -_PyObject_HasAttrId(PyObject *v, _Py_Identifier *name) -{ - int result; - PyObject *oname = _PyUnicode_FromId(name); /* borrowed */ - if (!oname) - return -1; - result = PyObject_HasAttr(v, oname); - return result; -} - -int -_PyObject_SetAttrId(PyObject *v, _Py_Identifier *name, PyObject *w) -{ - int result; - PyObject *oname = _PyUnicode_FromId(name); /* borrowed */ - if (!oname) - return -1; - result = PyObject_SetAttr(v, oname, w); - return result; -} - -PyObject * -PyObject_GetAttr(PyObject *v, PyObject *name) -{ - PyTypeObject *tp = Py_TYPE(v); - - if (!PyUnicode_Check(name)) { - PyErr_Format(PyExc_TypeError, - "attribute name must be string, not '%.200s'", + return res; +} + +/* Perform a rich comparison with integer result. This wraps + PyObject_RichCompare(), returning -1 for error, 0 for false, 1 for true. */ +int +PyObject_RichCompareBool(PyObject *v, PyObject *w, int op) +{ + PyObject *res; + int ok; + + /* Quick result when objects are the same. + Guarantees that identity implies equality. */ + if (v == w) { + if (op == Py_EQ) + return 1; + else if (op == Py_NE) + return 0; + } + + res = PyObject_RichCompare(v, w, op); + if (res == NULL) + return -1; + if (PyBool_Check(res)) + ok = (res == Py_True); + else + ok = PyObject_IsTrue(res); + Py_DECREF(res); + return ok; +} + +Py_hash_t +PyObject_HashNotImplemented(PyObject *v) +{ + PyErr_Format(PyExc_TypeError, "unhashable type: '%.200s'", + Py_TYPE(v)->tp_name); + return -1; +} + +Py_hash_t +PyObject_Hash(PyObject *v) +{ + PyTypeObject *tp = Py_TYPE(v); + if (tp->tp_hash != NULL) + return (*tp->tp_hash)(v); + /* To keep to the general practice that inheriting + * solely from object in C code should work without + * an explicit call to PyType_Ready, we implicitly call + * PyType_Ready here and then check the tp_hash slot again + */ + if (tp->tp_dict == NULL) { + if (PyType_Ready(tp) < 0) + return -1; + if (tp->tp_hash != NULL) + return (*tp->tp_hash)(v); + } + /* Otherwise, the object can't be hashed */ + return PyObject_HashNotImplemented(v); +} + +PyObject * +PyObject_GetAttrString(PyObject *v, const char *name) +{ + PyObject *w, *res; + + if (Py_TYPE(v)->tp_getattr != NULL) + return (*Py_TYPE(v)->tp_getattr)(v, (char*)name); + w = PyUnicode_FromString(name); + if (w == NULL) + return NULL; + res = PyObject_GetAttr(v, w); + Py_DECREF(w); + return res; +} + +int +PyObject_HasAttrString(PyObject *v, const char *name) +{ + PyObject *res = PyObject_GetAttrString(v, name); + if (res != NULL) { + Py_DECREF(res); + return 1; + } + PyErr_Clear(); + return 0; +} + +int +PyObject_SetAttrString(PyObject *v, const char *name, PyObject *w) +{ + PyObject *s; + int res; + + if (Py_TYPE(v)->tp_setattr != NULL) + return (*Py_TYPE(v)->tp_setattr)(v, (char*)name, w); + s = PyUnicode_InternFromString(name); + if (s == NULL) + return -1; + res = PyObject_SetAttr(v, s, w); + Py_XDECREF(s); + return res; +} + +int +_PyObject_IsAbstract(PyObject *obj) +{ + int res; + PyObject* isabstract; + + if (obj == NULL) + return 0; + + res = _PyObject_LookupAttrId(obj, &PyId___isabstractmethod__, &isabstract); + if (res > 0) { + res = PyObject_IsTrue(isabstract); + Py_DECREF(isabstract); + } + return res; +} + +PyObject * +_PyObject_GetAttrId(PyObject *v, _Py_Identifier *name) +{ + PyObject *result; + PyObject *oname = _PyUnicode_FromId(name); /* borrowed */ + if (!oname) + return NULL; + result = PyObject_GetAttr(v, oname); + return result; +} + +int +_PyObject_HasAttrId(PyObject *v, _Py_Identifier *name) +{ + int result; + PyObject *oname = _PyUnicode_FromId(name); /* borrowed */ + if (!oname) + return -1; + result = PyObject_HasAttr(v, oname); + return result; +} + +int +_PyObject_SetAttrId(PyObject *v, _Py_Identifier *name, PyObject *w) +{ + int result; + PyObject *oname = _PyUnicode_FromId(name); /* borrowed */ + if (!oname) + return -1; + result = PyObject_SetAttr(v, oname, w); + return result; +} + +PyObject * +PyObject_GetAttr(PyObject *v, PyObject *name) +{ + PyTypeObject *tp = Py_TYPE(v); + + if (!PyUnicode_Check(name)) { + PyErr_Format(PyExc_TypeError, + "attribute name must be string, not '%.200s'", Py_TYPE(name)->tp_name); - return NULL; - } - if (tp->tp_getattro != NULL) - return (*tp->tp_getattro)(v, name); - if (tp->tp_getattr != NULL) { - const char *name_str = PyUnicode_AsUTF8(name); - if (name_str == NULL) - return NULL; - return (*tp->tp_getattr)(v, (char *)name_str); - } - PyErr_Format(PyExc_AttributeError, - "'%.50s' object has no attribute '%U'", - tp->tp_name, name); - return NULL; -} - -int -_PyObject_LookupAttr(PyObject *v, PyObject *name, PyObject **result) -{ - PyTypeObject *tp = Py_TYPE(v); - - if (!PyUnicode_Check(name)) { - PyErr_Format(PyExc_TypeError, - "attribute name must be string, not '%.200s'", + return NULL; + } + if (tp->tp_getattro != NULL) + return (*tp->tp_getattro)(v, name); + if (tp->tp_getattr != NULL) { + const char *name_str = PyUnicode_AsUTF8(name); + if (name_str == NULL) + return NULL; + return (*tp->tp_getattr)(v, (char *)name_str); + } + PyErr_Format(PyExc_AttributeError, + "'%.50s' object has no attribute '%U'", + tp->tp_name, name); + return NULL; +} + +int +_PyObject_LookupAttr(PyObject *v, PyObject *name, PyObject **result) +{ + PyTypeObject *tp = Py_TYPE(v); + + if (!PyUnicode_Check(name)) { + PyErr_Format(PyExc_TypeError, + "attribute name must be string, not '%.200s'", Py_TYPE(name)->tp_name); - *result = NULL; - return -1; - } - - if (tp->tp_getattro == PyObject_GenericGetAttr) { - *result = _PyObject_GenericGetAttrWithDict(v, name, NULL, 1); - if (*result != NULL) { - return 1; - } - if (PyErr_Occurred()) { - return -1; - } - return 0; - } - if (tp->tp_getattro != NULL) { - *result = (*tp->tp_getattro)(v, name); - } - else if (tp->tp_getattr != NULL) { - const char *name_str = PyUnicode_AsUTF8(name); - if (name_str == NULL) { - *result = NULL; - return -1; - } - *result = (*tp->tp_getattr)(v, (char *)name_str); - } - else { - *result = NULL; - return 0; - } - - if (*result != NULL) { - return 1; - } - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { - return -1; - } - PyErr_Clear(); - return 0; -} - -int -_PyObject_LookupAttrId(PyObject *v, _Py_Identifier *name, PyObject **result) -{ - PyObject *oname = _PyUnicode_FromId(name); /* borrowed */ - if (!oname) { - *result = NULL; - return -1; - } - return _PyObject_LookupAttr(v, oname, result); -} - -int -PyObject_HasAttr(PyObject *v, PyObject *name) -{ - PyObject *res; - if (_PyObject_LookupAttr(v, name, &res) < 0) { - PyErr_Clear(); - return 0; - } - if (res == NULL) { - return 0; - } - Py_DECREF(res); - return 1; -} - -int -PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value) -{ - PyTypeObject *tp = Py_TYPE(v); - int err; - - if (!PyUnicode_Check(name)) { - PyErr_Format(PyExc_TypeError, - "attribute name must be string, not '%.200s'", + *result = NULL; + return -1; + } + + if (tp->tp_getattro == PyObject_GenericGetAttr) { + *result = _PyObject_GenericGetAttrWithDict(v, name, NULL, 1); + if (*result != NULL) { + return 1; + } + if (PyErr_Occurred()) { + return -1; + } + return 0; + } + if (tp->tp_getattro != NULL) { + *result = (*tp->tp_getattro)(v, name); + } + else if (tp->tp_getattr != NULL) { + const char *name_str = PyUnicode_AsUTF8(name); + if (name_str == NULL) { + *result = NULL; + return -1; + } + *result = (*tp->tp_getattr)(v, (char *)name_str); + } + else { + *result = NULL; + return 0; + } + + if (*result != NULL) { + return 1; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + return -1; + } + PyErr_Clear(); + return 0; +} + +int +_PyObject_LookupAttrId(PyObject *v, _Py_Identifier *name, PyObject **result) +{ + PyObject *oname = _PyUnicode_FromId(name); /* borrowed */ + if (!oname) { + *result = NULL; + return -1; + } + return _PyObject_LookupAttr(v, oname, result); +} + +int +PyObject_HasAttr(PyObject *v, PyObject *name) +{ + PyObject *res; + if (_PyObject_LookupAttr(v, name, &res) < 0) { + PyErr_Clear(); + return 0; + } + if (res == NULL) { + return 0; + } + Py_DECREF(res); + return 1; +} + +int +PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value) +{ + PyTypeObject *tp = Py_TYPE(v); + int err; + + if (!PyUnicode_Check(name)) { + PyErr_Format(PyExc_TypeError, + "attribute name must be string, not '%.200s'", Py_TYPE(name)->tp_name); - return -1; - } - Py_INCREF(name); - - PyUnicode_InternInPlace(&name); - if (tp->tp_setattro != NULL) { - err = (*tp->tp_setattro)(v, name, value); - Py_DECREF(name); - return err; - } - if (tp->tp_setattr != NULL) { - const char *name_str = PyUnicode_AsUTF8(name); + return -1; + } + Py_INCREF(name); + + PyUnicode_InternInPlace(&name); + if (tp->tp_setattro != NULL) { + err = (*tp->tp_setattro)(v, name, value); + Py_DECREF(name); + return err; + } + if (tp->tp_setattr != NULL) { + const char *name_str = PyUnicode_AsUTF8(name); if (name_str == NULL) { Py_DECREF(name); - return -1; + return -1; } - err = (*tp->tp_setattr)(v, (char *)name_str, value); - Py_DECREF(name); - return err; - } - Py_DECREF(name); + err = (*tp->tp_setattr)(v, (char *)name_str, value); + Py_DECREF(name); + return err; + } + Py_DECREF(name); _PyObject_ASSERT(name, Py_REFCNT(name) >= 1); - if (tp->tp_getattr == NULL && tp->tp_getattro == NULL) - PyErr_Format(PyExc_TypeError, - "'%.100s' object has no attributes " - "(%s .%U)", - tp->tp_name, - value==NULL ? "del" : "assign to", - name); - else - PyErr_Format(PyExc_TypeError, - "'%.100s' object has only read-only attributes " - "(%s .%U)", - tp->tp_name, - value==NULL ? "del" : "assign to", - name); - return -1; -} - -/* Helper to get a pointer to an object's __dict__ slot, if any */ - -PyObject ** -_PyObject_GetDictPtr(PyObject *obj) -{ - Py_ssize_t dictoffset; - PyTypeObject *tp = Py_TYPE(obj); - - dictoffset = tp->tp_dictoffset; - if (dictoffset == 0) - return NULL; - if (dictoffset < 0) { + if (tp->tp_getattr == NULL && tp->tp_getattro == NULL) + PyErr_Format(PyExc_TypeError, + "'%.100s' object has no attributes " + "(%s .%U)", + tp->tp_name, + value==NULL ? "del" : "assign to", + name); + else + PyErr_Format(PyExc_TypeError, + "'%.100s' object has only read-only attributes " + "(%s .%U)", + tp->tp_name, + value==NULL ? "del" : "assign to", + name); + return -1; +} + +/* Helper to get a pointer to an object's __dict__ slot, if any */ + +PyObject ** +_PyObject_GetDictPtr(PyObject *obj) +{ + Py_ssize_t dictoffset; + PyTypeObject *tp = Py_TYPE(obj); + + dictoffset = tp->tp_dictoffset; + if (dictoffset == 0) + return NULL; + if (dictoffset < 0) { Py_ssize_t tsize = Py_SIZE(obj); if (tsize < 0) { - tsize = -tsize; + tsize = -tsize; } size_t size = _PyObject_VAR_SIZE(tp, tsize); - - dictoffset += (long)size; + + dictoffset += (long)size; _PyObject_ASSERT(obj, dictoffset > 0); _PyObject_ASSERT(obj, dictoffset % SIZEOF_VOID_P == 0); - } - return (PyObject **) ((char *)obj + dictoffset); -} - -PyObject * -PyObject_SelfIter(PyObject *obj) -{ - Py_INCREF(obj); - return obj; -} - -/* Helper used when the __next__ method is removed from a type: - tp_iternext is never NULL and can be safely called without checking - on every iteration. - */ - -PyObject * -_PyObject_NextNotImplemented(PyObject *self) -{ - PyErr_Format(PyExc_TypeError, - "'%.200s' object is not iterable", - Py_TYPE(self)->tp_name); - return NULL; -} - - -/* Specialized version of _PyObject_GenericGetAttrWithDict - specifically for the LOAD_METHOD opcode. - - Return 1 if a method is found, 0 if it's a regular attribute - from __dict__ or something returned by using a descriptor - protocol. - - `method` will point to the resolved attribute or NULL. In the - latter case, an error will be set. -*/ -int -_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) -{ - PyTypeObject *tp = Py_TYPE(obj); - PyObject *descr; - descrgetfunc f = NULL; - PyObject **dictptr, *dict; - PyObject *attr; - int meth_found = 0; - - assert(*method == NULL); - - if (Py_TYPE(obj)->tp_getattro != PyObject_GenericGetAttr - || !PyUnicode_Check(name)) { - *method = PyObject_GetAttr(obj, name); - return 0; - } - - if (tp->tp_dict == NULL && PyType_Ready(tp) < 0) - return 0; - - descr = _PyType_Lookup(tp, name); - if (descr != NULL) { - Py_INCREF(descr); + } + return (PyObject **) ((char *)obj + dictoffset); +} + +PyObject * +PyObject_SelfIter(PyObject *obj) +{ + Py_INCREF(obj); + return obj; +} + +/* Helper used when the __next__ method is removed from a type: + tp_iternext is never NULL and can be safely called without checking + on every iteration. + */ + +PyObject * +_PyObject_NextNotImplemented(PyObject *self) +{ + PyErr_Format(PyExc_TypeError, + "'%.200s' object is not iterable", + Py_TYPE(self)->tp_name); + return NULL; +} + + +/* Specialized version of _PyObject_GenericGetAttrWithDict + specifically for the LOAD_METHOD opcode. + + Return 1 if a method is found, 0 if it's a regular attribute + from __dict__ or something returned by using a descriptor + protocol. + + `method` will point to the resolved attribute or NULL. In the + latter case, an error will be set. +*/ +int +_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) +{ + PyTypeObject *tp = Py_TYPE(obj); + PyObject *descr; + descrgetfunc f = NULL; + PyObject **dictptr, *dict; + PyObject *attr; + int meth_found = 0; + + assert(*method == NULL); + + if (Py_TYPE(obj)->tp_getattro != PyObject_GenericGetAttr + || !PyUnicode_Check(name)) { + *method = PyObject_GetAttr(obj, name); + return 0; + } + + if (tp->tp_dict == NULL && PyType_Ready(tp) < 0) + return 0; + + descr = _PyType_Lookup(tp, name); + if (descr != NULL) { + Py_INCREF(descr); if (_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)) { - meth_found = 1; - } else { + meth_found = 1; + } else { f = Py_TYPE(descr)->tp_descr_get; - if (f != NULL && PyDescr_IsData(descr)) { + if (f != NULL && PyDescr_IsData(descr)) { *method = f(descr, obj, (PyObject *)Py_TYPE(obj)); - Py_DECREF(descr); - return 0; - } - } - } - - dictptr = _PyObject_GetDictPtr(obj); - if (dictptr != NULL && (dict = *dictptr) != NULL) { - Py_INCREF(dict); + Py_DECREF(descr); + return 0; + } + } + } + + dictptr = _PyObject_GetDictPtr(obj); + if (dictptr != NULL && (dict = *dictptr) != NULL) { + Py_INCREF(dict); attr = PyDict_GetItemWithError(dict, name); - if (attr != NULL) { - Py_INCREF(attr); - *method = attr; - Py_DECREF(dict); - Py_XDECREF(descr); - return 0; - } + if (attr != NULL) { + Py_INCREF(attr); + *method = attr; + Py_DECREF(dict); + Py_XDECREF(descr); + return 0; + } else { Py_DECREF(dict); if (PyErr_Occurred()) { @@ -1135,106 +1135,106 @@ _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) return 0; } } - } - - if (meth_found) { - *method = descr; - return 1; - } - - if (f != NULL) { - *method = f(descr, obj, (PyObject *)Py_TYPE(obj)); - Py_DECREF(descr); - return 0; - } - - if (descr != NULL) { - *method = descr; - return 0; - } - - PyErr_Format(PyExc_AttributeError, - "'%.50s' object has no attribute '%U'", - tp->tp_name, name); - return 0; -} - -/* Generic GetAttr functions - put these in your tp_[gs]etattro slot. */ - -PyObject * -_PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, - PyObject *dict, int suppress) -{ - /* Make sure the logic of _PyObject_GetMethod is in sync with - this method. - - When suppress=1, this function suppress AttributeError. - */ - - PyTypeObject *tp = Py_TYPE(obj); - PyObject *descr = NULL; - PyObject *res = NULL; - descrgetfunc f; - Py_ssize_t dictoffset; - PyObject **dictptr; - - if (!PyUnicode_Check(name)){ - PyErr_Format(PyExc_TypeError, - "attribute name must be string, not '%.200s'", + } + + if (meth_found) { + *method = descr; + return 1; + } + + if (f != NULL) { + *method = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + return 0; + } + + if (descr != NULL) { + *method = descr; + return 0; + } + + PyErr_Format(PyExc_AttributeError, + "'%.50s' object has no attribute '%U'", + tp->tp_name, name); + return 0; +} + +/* Generic GetAttr functions - put these in your tp_[gs]etattro slot. */ + +PyObject * +_PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, + PyObject *dict, int suppress) +{ + /* Make sure the logic of _PyObject_GetMethod is in sync with + this method. + + When suppress=1, this function suppress AttributeError. + */ + + PyTypeObject *tp = Py_TYPE(obj); + PyObject *descr = NULL; + PyObject *res = NULL; + descrgetfunc f; + Py_ssize_t dictoffset; + PyObject **dictptr; + + if (!PyUnicode_Check(name)){ + PyErr_Format(PyExc_TypeError, + "attribute name must be string, not '%.200s'", Py_TYPE(name)->tp_name); - return NULL; - } - Py_INCREF(name); - - if (tp->tp_dict == NULL) { - if (PyType_Ready(tp) < 0) - goto done; - } - - descr = _PyType_Lookup(tp, name); - - f = NULL; - if (descr != NULL) { - Py_INCREF(descr); + return NULL; + } + Py_INCREF(name); + + if (tp->tp_dict == NULL) { + if (PyType_Ready(tp) < 0) + goto done; + } + + descr = _PyType_Lookup(tp, name); + + f = NULL; + if (descr != NULL) { + Py_INCREF(descr); f = Py_TYPE(descr)->tp_descr_get; - if (f != NULL && PyDescr_IsData(descr)) { + if (f != NULL && PyDescr_IsData(descr)) { res = f(descr, obj, (PyObject *)Py_TYPE(obj)); - if (res == NULL && suppress && - PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Clear(); - } - goto done; - } - } - - if (dict == NULL) { - /* Inline _PyObject_GetDictPtr */ - dictoffset = tp->tp_dictoffset; - if (dictoffset != 0) { - if (dictoffset < 0) { + if (res == NULL && suppress && + PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } + goto done; + } + } + + if (dict == NULL) { + /* Inline _PyObject_GetDictPtr */ + dictoffset = tp->tp_dictoffset; + if (dictoffset != 0) { + if (dictoffset < 0) { Py_ssize_t tsize = Py_SIZE(obj); if (tsize < 0) { - tsize = -tsize; + tsize = -tsize; } size_t size = _PyObject_VAR_SIZE(tp, tsize); _PyObject_ASSERT(obj, size <= PY_SSIZE_T_MAX); - - dictoffset += (Py_ssize_t)size; + + dictoffset += (Py_ssize_t)size; _PyObject_ASSERT(obj, dictoffset > 0); _PyObject_ASSERT(obj, dictoffset % SIZEOF_VOID_P == 0); - } - dictptr = (PyObject **) ((char *)obj + dictoffset); - dict = *dictptr; - } - } - if (dict != NULL) { - Py_INCREF(dict); + } + dictptr = (PyObject **) ((char *)obj + dictoffset); + dict = *dictptr; + } + } + if (dict != NULL) { + Py_INCREF(dict); res = PyDict_GetItemWithError(dict, name); - if (res != NULL) { - Py_INCREF(res); - Py_DECREF(dict); - goto done; - } + if (res != NULL) { + Py_INCREF(res); + Py_DECREF(dict); + goto done; + } else { Py_DECREF(dict); if (PyErr_Occurred()) { @@ -1246,73 +1246,73 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, } } } - } - - if (f != NULL) { - res = f(descr, obj, (PyObject *)Py_TYPE(obj)); - if (res == NULL && suppress && - PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Clear(); - } - goto done; - } - - if (descr != NULL) { - res = descr; - descr = NULL; - goto done; - } - - if (!suppress) { - PyErr_Format(PyExc_AttributeError, - "'%.50s' object has no attribute '%U'", - tp->tp_name, name); - } - done: - Py_XDECREF(descr); - Py_DECREF(name); - return res; -} - -PyObject * -PyObject_GenericGetAttr(PyObject *obj, PyObject *name) -{ - return _PyObject_GenericGetAttrWithDict(obj, name, NULL, 0); -} - -int -_PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name, - PyObject *value, PyObject *dict) -{ - PyTypeObject *tp = Py_TYPE(obj); - PyObject *descr; - descrsetfunc f; - PyObject **dictptr; - int res = -1; - - if (!PyUnicode_Check(name)){ - PyErr_Format(PyExc_TypeError, - "attribute name must be string, not '%.200s'", + } + + if (f != NULL) { + res = f(descr, obj, (PyObject *)Py_TYPE(obj)); + if (res == NULL && suppress && + PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } + goto done; + } + + if (descr != NULL) { + res = descr; + descr = NULL; + goto done; + } + + if (!suppress) { + PyErr_Format(PyExc_AttributeError, + "'%.50s' object has no attribute '%U'", + tp->tp_name, name); + } + done: + Py_XDECREF(descr); + Py_DECREF(name); + return res; +} + +PyObject * +PyObject_GenericGetAttr(PyObject *obj, PyObject *name) +{ + return _PyObject_GenericGetAttrWithDict(obj, name, NULL, 0); +} + +int +_PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name, + PyObject *value, PyObject *dict) +{ + PyTypeObject *tp = Py_TYPE(obj); + PyObject *descr; + descrsetfunc f; + PyObject **dictptr; + int res = -1; + + if (!PyUnicode_Check(name)){ + PyErr_Format(PyExc_TypeError, + "attribute name must be string, not '%.200s'", Py_TYPE(name)->tp_name); - return -1; - } - - if (tp->tp_dict == NULL && PyType_Ready(tp) < 0) - return -1; - - Py_INCREF(name); - - descr = _PyType_Lookup(tp, name); - - if (descr != NULL) { - Py_INCREF(descr); + return -1; + } + + if (tp->tp_dict == NULL && PyType_Ready(tp) < 0) + return -1; + + Py_INCREF(name); + + descr = _PyType_Lookup(tp, name); + + if (descr != NULL) { + Py_INCREF(descr); f = Py_TYPE(descr)->tp_descr_set; - if (f != NULL) { - res = f(descr, obj, value); - goto done; - } - } - + if (f != NULL) { + res = f(descr, obj, value); + goto done; + } + } + /* XXX [Steve Dower] These are really noisy - worth it? */ /*if (PyType_Check(obj) || PyModule_Check(obj)) { if (value && PySys_Audit("object.__setattr__", "OOO", obj, name, value) < 0) @@ -1321,84 +1321,84 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name, return -1; }*/ - if (dict == NULL) { - dictptr = _PyObject_GetDictPtr(obj); - if (dictptr == NULL) { - if (descr == NULL) { - PyErr_Format(PyExc_AttributeError, - "'%.100s' object has no attribute '%U'", - tp->tp_name, name); - } - else { - PyErr_Format(PyExc_AttributeError, - "'%.50s' object attribute '%U' is read-only", - tp->tp_name, name); - } - goto done; - } - res = _PyObjectDict_SetItem(tp, dictptr, name, value); - } - else { - Py_INCREF(dict); - if (value == NULL) - res = PyDict_DelItem(dict, name); - else - res = PyDict_SetItem(dict, name, value); - Py_DECREF(dict); - } - if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) - PyErr_SetObject(PyExc_AttributeError, name); - - done: - Py_XDECREF(descr); - Py_DECREF(name); - return res; -} - -int -PyObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value) -{ - return _PyObject_GenericSetAttrWithDict(obj, name, value, NULL); -} - -int -PyObject_GenericSetDict(PyObject *obj, PyObject *value, void *context) -{ - PyObject **dictptr = _PyObject_GetDictPtr(obj); - if (dictptr == NULL) { - PyErr_SetString(PyExc_AttributeError, - "This object has no __dict__"); - return -1; - } - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "cannot delete __dict__"); - return -1; - } - if (!PyDict_Check(value)) { - PyErr_Format(PyExc_TypeError, - "__dict__ must be set to a dictionary, " - "not a '%.200s'", Py_TYPE(value)->tp_name); - return -1; - } - Py_INCREF(value); - Py_XSETREF(*dictptr, value); - return 0; -} - - -/* Test a value used as condition, e.g., in a for or if statement. - Return -1 if an error occurred */ - -int -PyObject_IsTrue(PyObject *v) -{ - Py_ssize_t res; - if (v == Py_True) - return 1; - if (v == Py_False) - return 0; - if (v == Py_None) - return 0; + if (dict == NULL) { + dictptr = _PyObject_GetDictPtr(obj); + if (dictptr == NULL) { + if (descr == NULL) { + PyErr_Format(PyExc_AttributeError, + "'%.100s' object has no attribute '%U'", + tp->tp_name, name); + } + else { + PyErr_Format(PyExc_AttributeError, + "'%.50s' object attribute '%U' is read-only", + tp->tp_name, name); + } + goto done; + } + res = _PyObjectDict_SetItem(tp, dictptr, name, value); + } + else { + Py_INCREF(dict); + if (value == NULL) + res = PyDict_DelItem(dict, name); + else + res = PyDict_SetItem(dict, name, value); + Py_DECREF(dict); + } + if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) + PyErr_SetObject(PyExc_AttributeError, name); + + done: + Py_XDECREF(descr); + Py_DECREF(name); + return res; +} + +int +PyObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value) +{ + return _PyObject_GenericSetAttrWithDict(obj, name, value, NULL); +} + +int +PyObject_GenericSetDict(PyObject *obj, PyObject *value, void *context) +{ + PyObject **dictptr = _PyObject_GetDictPtr(obj); + if (dictptr == NULL) { + PyErr_SetString(PyExc_AttributeError, + "This object has no __dict__"); + return -1; + } + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "cannot delete __dict__"); + return -1; + } + if (!PyDict_Check(value)) { + PyErr_Format(PyExc_TypeError, + "__dict__ must be set to a dictionary, " + "not a '%.200s'", Py_TYPE(value)->tp_name); + return -1; + } + Py_INCREF(value); + Py_XSETREF(*dictptr, value); + return 0; +} + + +/* Test a value used as condition, e.g., in a for or if statement. + Return -1 if an error occurred */ + +int +PyObject_IsTrue(PyObject *v) +{ + Py_ssize_t res; + if (v == Py_True) + return 1; + if (v == Py_False) + return 0; + if (v == Py_None) + return 0; else if (Py_TYPE(v)->tp_as_number != NULL && Py_TYPE(v)->tp_as_number->nb_bool != NULL) res = (*Py_TYPE(v)->tp_as_number->nb_bool)(v); @@ -1408,266 +1408,266 @@ PyObject_IsTrue(PyObject *v) else if (Py_TYPE(v)->tp_as_sequence != NULL && Py_TYPE(v)->tp_as_sequence->sq_length != NULL) res = (*Py_TYPE(v)->tp_as_sequence->sq_length)(v); - else - return 1; - /* if it is negative, it should be either -1 or -2 */ - return (res > 0) ? 1 : Py_SAFE_DOWNCAST(res, Py_ssize_t, int); -} - -/* equivalent of 'not v' - Return -1 if an error occurred */ - -int -PyObject_Not(PyObject *v) -{ - int res; - res = PyObject_IsTrue(v); - if (res < 0) - return res; - return res == 0; -} - -/* Test whether an object can be called */ - -int -PyCallable_Check(PyObject *x) -{ - if (x == NULL) - return 0; + else + return 1; + /* if it is negative, it should be either -1 or -2 */ + return (res > 0) ? 1 : Py_SAFE_DOWNCAST(res, Py_ssize_t, int); +} + +/* equivalent of 'not v' + Return -1 if an error occurred */ + +int +PyObject_Not(PyObject *v) +{ + int res; + res = PyObject_IsTrue(v); + if (res < 0) + return res; + return res == 0; +} + +/* Test whether an object can be called */ + +int +PyCallable_Check(PyObject *x) +{ + if (x == NULL) + return 0; return Py_TYPE(x)->tp_call != NULL; -} - - -/* Helper for PyObject_Dir without arguments: returns the local scope. */ -static PyObject * -_dir_locals(void) -{ - PyObject *names; - PyObject *locals; - - locals = PyEval_GetLocals(); - if (locals == NULL) - return NULL; - - names = PyMapping_Keys(locals); - if (!names) - return NULL; - if (!PyList_Check(names)) { - PyErr_Format(PyExc_TypeError, - "dir(): expected keys() of locals to be a list, " - "not '%.200s'", Py_TYPE(names)->tp_name); - Py_DECREF(names); - return NULL; - } - if (PyList_Sort(names)) { - Py_DECREF(names); - return NULL; - } - /* the locals don't need to be DECREF'd */ - return names; -} - -/* Helper for PyObject_Dir: object introspection. */ -static PyObject * -_dir_object(PyObject *obj) -{ - PyObject *result, *sorted; - PyObject *dirfunc = _PyObject_LookupSpecial(obj, &PyId___dir__); - +} + + +/* Helper for PyObject_Dir without arguments: returns the local scope. */ +static PyObject * +_dir_locals(void) +{ + PyObject *names; + PyObject *locals; + + locals = PyEval_GetLocals(); + if (locals == NULL) + return NULL; + + names = PyMapping_Keys(locals); + if (!names) + return NULL; + if (!PyList_Check(names)) { + PyErr_Format(PyExc_TypeError, + "dir(): expected keys() of locals to be a list, " + "not '%.200s'", Py_TYPE(names)->tp_name); + Py_DECREF(names); + return NULL; + } + if (PyList_Sort(names)) { + Py_DECREF(names); + return NULL; + } + /* the locals don't need to be DECREF'd */ + return names; +} + +/* Helper for PyObject_Dir: object introspection. */ +static PyObject * +_dir_object(PyObject *obj) +{ + PyObject *result, *sorted; + PyObject *dirfunc = _PyObject_LookupSpecial(obj, &PyId___dir__); + assert(obj != NULL); - if (dirfunc == NULL) { - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_TypeError, "object does not provide __dir__"); - return NULL; - } - /* use __dir__ */ - result = _PyObject_CallNoArg(dirfunc); - Py_DECREF(dirfunc); - if (result == NULL) - return NULL; - /* return sorted(result) */ - sorted = PySequence_List(result); - Py_DECREF(result); - if (sorted == NULL) - return NULL; - if (PyList_Sort(sorted)) { - Py_DECREF(sorted); - return NULL; - } - return sorted; -} - -/* Implementation of dir() -- if obj is NULL, returns the names in the current - (local) scope. Otherwise, performs introspection of the object: returns a - sorted list of attribute names (supposedly) accessible from the object -*/ -PyObject * -PyObject_Dir(PyObject *obj) -{ - return (obj == NULL) ? _dir_locals() : _dir_object(obj); -} - -/* -None is a non-NULL undefined value. -There is (and should be!) no way to create other objects of this type, -so there is exactly one (which is indestructible, by the way). -*/ - -/* ARGSUSED */ -static PyObject * -none_repr(PyObject *op) -{ - return PyUnicode_FromString("None"); -} - -/* ARGUSED */ + if (dirfunc == NULL) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_TypeError, "object does not provide __dir__"); + return NULL; + } + /* use __dir__ */ + result = _PyObject_CallNoArg(dirfunc); + Py_DECREF(dirfunc); + if (result == NULL) + return NULL; + /* return sorted(result) */ + sorted = PySequence_List(result); + Py_DECREF(result); + if (sorted == NULL) + return NULL; + if (PyList_Sort(sorted)) { + Py_DECREF(sorted); + return NULL; + } + return sorted; +} + +/* Implementation of dir() -- if obj is NULL, returns the names in the current + (local) scope. Otherwise, performs introspection of the object: returns a + sorted list of attribute names (supposedly) accessible from the object +*/ +PyObject * +PyObject_Dir(PyObject *obj) +{ + return (obj == NULL) ? _dir_locals() : _dir_object(obj); +} + +/* +None is a non-NULL undefined value. +There is (and should be!) no way to create other objects of this type, +so there is exactly one (which is indestructible, by the way). +*/ + +/* ARGSUSED */ +static PyObject * +none_repr(PyObject *op) +{ + return PyUnicode_FromString("None"); +} + +/* ARGUSED */ static void _Py_NO_RETURN -none_dealloc(PyObject* ignore) -{ - /* This should never get called, but we also don't want to SEGV if - * we accidentally decref None out of existence. - */ - Py_FatalError("deallocating None"); -} - -static PyObject * -none_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_GET_SIZE(kwargs))) { - PyErr_SetString(PyExc_TypeError, "NoneType takes no arguments"); - return NULL; - } - Py_RETURN_NONE; -} - -static int -none_bool(PyObject *v) -{ - return 0; -} - -static PyNumberMethods none_as_number = { - 0, /* nb_add */ - 0, /* nb_subtract */ - 0, /* nb_multiply */ - 0, /* nb_remainder */ - 0, /* nb_divmod */ - 0, /* nb_power */ - 0, /* nb_negative */ - 0, /* nb_positive */ - 0, /* nb_absolute */ - (inquiry)none_bool, /* nb_bool */ - 0, /* nb_invert */ - 0, /* nb_lshift */ - 0, /* nb_rshift */ - 0, /* nb_and */ - 0, /* nb_xor */ - 0, /* nb_or */ - 0, /* nb_int */ - 0, /* nb_reserved */ - 0, /* nb_float */ - 0, /* nb_inplace_add */ - 0, /* nb_inplace_subtract */ - 0, /* nb_inplace_multiply */ - 0, /* nb_inplace_remainder */ - 0, /* nb_inplace_power */ - 0, /* nb_inplace_lshift */ - 0, /* nb_inplace_rshift */ - 0, /* nb_inplace_and */ - 0, /* nb_inplace_xor */ - 0, /* nb_inplace_or */ - 0, /* nb_floor_divide */ - 0, /* nb_true_divide */ - 0, /* nb_inplace_floor_divide */ - 0, /* nb_inplace_true_divide */ - 0, /* nb_index */ -}; - -PyTypeObject _PyNone_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "NoneType", - 0, - 0, - none_dealloc, /*tp_dealloc*/ /*never called*/ +none_dealloc(PyObject* ignore) +{ + /* This should never get called, but we also don't want to SEGV if + * we accidentally decref None out of existence. + */ + Py_FatalError("deallocating None"); +} + +static PyObject * +none_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_GET_SIZE(kwargs))) { + PyErr_SetString(PyExc_TypeError, "NoneType takes no arguments"); + return NULL; + } + Py_RETURN_NONE; +} + +static int +none_bool(PyObject *v) +{ + return 0; +} + +static PyNumberMethods none_as_number = { + 0, /* nb_add */ + 0, /* nb_subtract */ + 0, /* nb_multiply */ + 0, /* nb_remainder */ + 0, /* nb_divmod */ + 0, /* nb_power */ + 0, /* nb_negative */ + 0, /* nb_positive */ + 0, /* nb_absolute */ + (inquiry)none_bool, /* nb_bool */ + 0, /* nb_invert */ + 0, /* nb_lshift */ + 0, /* nb_rshift */ + 0, /* nb_and */ + 0, /* nb_xor */ + 0, /* nb_or */ + 0, /* nb_int */ + 0, /* nb_reserved */ + 0, /* nb_float */ + 0, /* nb_inplace_add */ + 0, /* nb_inplace_subtract */ + 0, /* nb_inplace_multiply */ + 0, /* nb_inplace_remainder */ + 0, /* nb_inplace_power */ + 0, /* nb_inplace_lshift */ + 0, /* nb_inplace_rshift */ + 0, /* nb_inplace_and */ + 0, /* nb_inplace_xor */ + 0, /* nb_inplace_or */ + 0, /* nb_floor_divide */ + 0, /* nb_true_divide */ + 0, /* nb_inplace_floor_divide */ + 0, /* nb_inplace_true_divide */ + 0, /* nb_index */ +}; + +PyTypeObject _PyNone_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "NoneType", + 0, + 0, + none_dealloc, /*tp_dealloc*/ /*never called*/ 0, /*tp_vectorcall_offset*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ 0, /*tp_as_async*/ - none_repr, /*tp_repr*/ - &none_as_number, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call */ - 0, /*tp_str */ - 0, /*tp_getattro */ - 0, /*tp_setattro */ - 0, /*tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /*tp_flags */ - 0, /*tp_doc */ - 0, /*tp_traverse */ - 0, /*tp_clear */ - 0, /*tp_richcompare */ - 0, /*tp_weaklistoffset */ - 0, /*tp_iter */ - 0, /*tp_iternext */ - 0, /*tp_methods */ - 0, /*tp_members */ - 0, /*tp_getset */ - 0, /*tp_base */ - 0, /*tp_dict */ - 0, /*tp_descr_get */ - 0, /*tp_descr_set */ - 0, /*tp_dictoffset */ - 0, /*tp_init */ - 0, /*tp_alloc */ - none_new, /*tp_new */ -}; - -PyObject _Py_NoneStruct = { - _PyObject_EXTRA_INIT - 1, &_PyNone_Type -}; - -/* NotImplemented is an object that can be used to signal that an - operation is not implemented for the given type combination. */ - -static PyObject * -NotImplemented_repr(PyObject *op) -{ - return PyUnicode_FromString("NotImplemented"); -} - -static PyObject * + none_repr, /*tp_repr*/ + &none_as_number, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call */ + 0, /*tp_str */ + 0, /*tp_getattro */ + 0, /*tp_setattro */ + 0, /*tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /*tp_flags */ + 0, /*tp_doc */ + 0, /*tp_traverse */ + 0, /*tp_clear */ + 0, /*tp_richcompare */ + 0, /*tp_weaklistoffset */ + 0, /*tp_iter */ + 0, /*tp_iternext */ + 0, /*tp_methods */ + 0, /*tp_members */ + 0, /*tp_getset */ + 0, /*tp_base */ + 0, /*tp_dict */ + 0, /*tp_descr_get */ + 0, /*tp_descr_set */ + 0, /*tp_dictoffset */ + 0, /*tp_init */ + 0, /*tp_alloc */ + none_new, /*tp_new */ +}; + +PyObject _Py_NoneStruct = { + _PyObject_EXTRA_INIT + 1, &_PyNone_Type +}; + +/* NotImplemented is an object that can be used to signal that an + operation is not implemented for the given type combination. */ + +static PyObject * +NotImplemented_repr(PyObject *op) +{ + return PyUnicode_FromString("NotImplemented"); +} + +static PyObject * NotImplemented_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) -{ - return PyUnicode_FromString("NotImplemented"); -} - -static PyMethodDef notimplemented_methods[] = { +{ + return PyUnicode_FromString("NotImplemented"); +} + +static PyMethodDef notimplemented_methods[] = { {"__reduce__", NotImplemented_reduce, METH_NOARGS, NULL}, - {NULL, NULL} -}; - -static PyObject * -notimplemented_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_GET_SIZE(kwargs))) { - PyErr_SetString(PyExc_TypeError, "NotImplementedType takes no arguments"); - return NULL; - } - Py_RETURN_NOTIMPLEMENTED; -} - + {NULL, NULL} +}; + +static PyObject * +notimplemented_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_GET_SIZE(kwargs))) { + PyErr_SetString(PyExc_TypeError, "NotImplementedType takes no arguments"); + return NULL; + } + Py_RETURN_NOTIMPLEMENTED; +} + static void _Py_NO_RETURN -notimplemented_dealloc(PyObject* ignore) -{ - /* This should never get called, but we also don't want to SEGV if - * we accidentally decref NotImplemented out of existence. - */ - Py_FatalError("deallocating NotImplemented"); -} - +notimplemented_dealloc(PyObject* ignore) +{ + /* This should never get called, but we also don't want to SEGV if + * we accidentally decref NotImplemented out of existence. + */ + Py_FatalError("deallocating NotImplemented"); +} + static int notimplemented_bool(PyObject *v) { @@ -1684,55 +1684,55 @@ static PyNumberMethods notimplemented_as_number = { .nb_bool = notimplemented_bool, }; -PyTypeObject _PyNotImplemented_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "NotImplementedType", - 0, - 0, - notimplemented_dealloc, /*tp_dealloc*/ /*never called*/ +PyTypeObject _PyNotImplemented_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "NotImplementedType", + 0, + 0, + notimplemented_dealloc, /*tp_dealloc*/ /*never called*/ 0, /*tp_vectorcall_offset*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ 0, /*tp_as_async*/ NotImplemented_repr, /*tp_repr*/ ¬implemented_as_number, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call */ - 0, /*tp_str */ - 0, /*tp_getattro */ - 0, /*tp_setattro */ - 0, /*tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /*tp_flags */ - 0, /*tp_doc */ - 0, /*tp_traverse */ - 0, /*tp_clear */ - 0, /*tp_richcompare */ - 0, /*tp_weaklistoffset */ - 0, /*tp_iter */ - 0, /*tp_iternext */ - notimplemented_methods, /*tp_methods */ - 0, /*tp_members */ - 0, /*tp_getset */ - 0, /*tp_base */ - 0, /*tp_dict */ - 0, /*tp_descr_get */ - 0, /*tp_descr_set */ - 0, /*tp_dictoffset */ - 0, /*tp_init */ - 0, /*tp_alloc */ - notimplemented_new, /*tp_new */ -}; - -PyObject _Py_NotImplementedStruct = { - _PyObject_EXTRA_INIT - 1, &_PyNotImplemented_Type -}; - + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call */ + 0, /*tp_str */ + 0, /*tp_getattro */ + 0, /*tp_setattro */ + 0, /*tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /*tp_flags */ + 0, /*tp_doc */ + 0, /*tp_traverse */ + 0, /*tp_clear */ + 0, /*tp_richcompare */ + 0, /*tp_weaklistoffset */ + 0, /*tp_iter */ + 0, /*tp_iternext */ + notimplemented_methods, /*tp_methods */ + 0, /*tp_members */ + 0, /*tp_getset */ + 0, /*tp_base */ + 0, /*tp_dict */ + 0, /*tp_descr_get */ + 0, /*tp_descr_set */ + 0, /*tp_dictoffset */ + 0, /*tp_init */ + 0, /*tp_alloc */ + notimplemented_new, /*tp_new */ +}; + +PyObject _Py_NotImplementedStruct = { + _PyObject_EXTRA_INIT + 1, &_PyNotImplemented_Type +}; + PyStatus _PyTypes_Init(void) -{ +{ PyStatus status = _PyTypes_InitSlotDefs(); if (_PyStatus_EXCEPTION(status)) { return status; @@ -1744,7 +1744,7 @@ _PyTypes_Init(void) return _PyStatus_ERR("Can't initialize " NAME " type"); \ } \ } while (0) - + INIT_TYPE(&PyBaseObject_Type, "object"); INIT_TYPE(&PyType_Type, "type"); INIT_TYPE(&_PyWeakref_RefType, "weakref"); @@ -1813,14 +1813,14 @@ _PyTypes_Init(void) INIT_TYPE(&_PyCoroWrapper_Type, "coroutine wrapper"); INIT_TYPE(&_PyInterpreterID_Type, "interpreter ID"); return _PyStatus_OK(); - + #undef INIT_TYPE -} - - -void -_Py_NewReference(PyObject *op) -{ +} + + +void +_Py_NewReference(PyObject *op) +{ if (_Py_tracemalloc_config.tracing) { _PyTraceMalloc_NewReference(op); } @@ -1829,206 +1829,206 @@ _Py_NewReference(PyObject *op) #endif Py_SET_REFCNT(op, 1); #ifdef Py_TRACE_REFS - _Py_AddToAllObjects(op, 1); + _Py_AddToAllObjects(op, 1); #endif -} - +} + #ifdef Py_TRACE_REFS -void -_Py_ForgetReference(PyObject *op) -{ +void +_Py_ForgetReference(PyObject *op) +{ if (Py_REFCNT(op) < 0) { _PyObject_ASSERT_FAILED_MSG(op, "negative refcnt"); } - if (op == &refchain || + if (op == &refchain || op->_ob_prev->_ob_next != op || op->_ob_next->_ob_prev != op) { _PyObject_ASSERT_FAILED_MSG(op, "invalid object chain"); - } + } -#ifdef SLOW_UNREF_CHECK +#ifdef SLOW_UNREF_CHECK PyObject *p; - for (p = refchain._ob_next; p != &refchain; p = p->_ob_next) { + for (p = refchain._ob_next; p != &refchain; p = p->_ob_next) { if (p == op) { - break; + break; } - } + } if (p == &refchain) { /* Not found */ _PyObject_ASSERT_FAILED_MSG(op, "object not found in the objects list"); } -#endif - - op->_ob_next->_ob_prev = op->_ob_prev; - op->_ob_prev->_ob_next = op->_ob_next; - op->_ob_next = op->_ob_prev = NULL; -} - -/* Print all live objects. Because PyObject_Print is called, the - * interpreter must be in a healthy state. - */ -void -_Py_PrintReferences(FILE *fp) -{ - PyObject *op; - fprintf(fp, "Remaining objects:\n"); - for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) { +#endif + + op->_ob_next->_ob_prev = op->_ob_prev; + op->_ob_prev->_ob_next = op->_ob_next; + op->_ob_next = op->_ob_prev = NULL; +} + +/* Print all live objects. Because PyObject_Print is called, the + * interpreter must be in a healthy state. + */ +void +_Py_PrintReferences(FILE *fp) +{ + PyObject *op; + fprintf(fp, "Remaining objects:\n"); + for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) { fprintf(fp, "%p [%" PY_FORMAT_SIZE_T "d] ", (void *)op, Py_REFCNT(op)); - if (PyObject_Print(op, fp, 0) != 0) - PyErr_Clear(); - putc('\n', fp); - } -} - -/* Print the addresses of all live objects. Unlike _Py_PrintReferences, this - * doesn't make any calls to the Python C API, so is always safe to call. - */ -void -_Py_PrintReferenceAddresses(FILE *fp) -{ - PyObject *op; - fprintf(fp, "Remaining object addresses:\n"); - for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) + if (PyObject_Print(op, fp, 0) != 0) + PyErr_Clear(); + putc('\n', fp); + } +} + +/* Print the addresses of all live objects. Unlike _Py_PrintReferences, this + * doesn't make any calls to the Python C API, so is always safe to call. + */ +void +_Py_PrintReferenceAddresses(FILE *fp) +{ + PyObject *op; + fprintf(fp, "Remaining object addresses:\n"); + for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) fprintf(fp, "%p [%" PY_FORMAT_SIZE_T "d] %s\n", (void *)op, Py_REFCNT(op), Py_TYPE(op)->tp_name); -} - -PyObject * -_Py_GetObjects(PyObject *self, PyObject *args) -{ - int i, n; - PyObject *t = NULL; - PyObject *res, *op; - - if (!PyArg_ParseTuple(args, "i|O", &n, &t)) - return NULL; - op = refchain._ob_next; - res = PyList_New(0); - if (res == NULL) - return NULL; - for (i = 0; (n == 0 || i < n) && op != &refchain; i++) { - while (op == self || op == args || op == res || op == t || +} + +PyObject * +_Py_GetObjects(PyObject *self, PyObject *args) +{ + int i, n; + PyObject *t = NULL; + PyObject *res, *op; + + if (!PyArg_ParseTuple(args, "i|O", &n, &t)) + return NULL; + op = refchain._ob_next; + res = PyList_New(0); + if (res == NULL) + return NULL; + for (i = 0; (n == 0 || i < n) && op != &refchain; i++) { + while (op == self || op == args || op == res || op == t || (t != NULL && !Py_IS_TYPE(op, (PyTypeObject *) t))) { - op = op->_ob_next; - if (op == &refchain) - return res; - } - if (PyList_Append(res, op) < 0) { - Py_DECREF(res); - return NULL; - } - op = op->_ob_next; - } - return res; -} - -#endif - - -/* Hack to force loading of abstract.o */ -Py_ssize_t (*_Py_abstract_hack)(PyObject *) = PyObject_Size; - - -void -_PyObject_DebugTypeStats(FILE *out) -{ - _PyDict_DebugMallocStats(out); - _PyFloat_DebugMallocStats(out); - _PyFrame_DebugMallocStats(out); - _PyList_DebugMallocStats(out); - _PyTuple_DebugMallocStats(out); -} - -/* These methods are used to control infinite recursion in repr, str, print, - etc. Container objects that may recursively contain themselves, - e.g. builtin dictionaries and lists, should use Py_ReprEnter() and - Py_ReprLeave() to avoid infinite recursion. - - Py_ReprEnter() returns 0 the first time it is called for a particular - object and 1 every time thereafter. It returns -1 if an exception - occurred. Py_ReprLeave() has no return value. - - See dictobject.c and listobject.c for examples of use. -*/ - -int -Py_ReprEnter(PyObject *obj) -{ - PyObject *dict; - PyObject *list; - Py_ssize_t i; - - dict = PyThreadState_GetDict(); - /* Ignore a missing thread-state, so that this function can be called - early on startup. */ - if (dict == NULL) - return 0; + op = op->_ob_next; + if (op == &refchain) + return res; + } + if (PyList_Append(res, op) < 0) { + Py_DECREF(res); + return NULL; + } + op = op->_ob_next; + } + return res; +} + +#endif + + +/* Hack to force loading of abstract.o */ +Py_ssize_t (*_Py_abstract_hack)(PyObject *) = PyObject_Size; + + +void +_PyObject_DebugTypeStats(FILE *out) +{ + _PyDict_DebugMallocStats(out); + _PyFloat_DebugMallocStats(out); + _PyFrame_DebugMallocStats(out); + _PyList_DebugMallocStats(out); + _PyTuple_DebugMallocStats(out); +} + +/* These methods are used to control infinite recursion in repr, str, print, + etc. Container objects that may recursively contain themselves, + e.g. builtin dictionaries and lists, should use Py_ReprEnter() and + Py_ReprLeave() to avoid infinite recursion. + + Py_ReprEnter() returns 0 the first time it is called for a particular + object and 1 every time thereafter. It returns -1 if an exception + occurred. Py_ReprLeave() has no return value. + + See dictobject.c and listobject.c for examples of use. +*/ + +int +Py_ReprEnter(PyObject *obj) +{ + PyObject *dict; + PyObject *list; + Py_ssize_t i; + + dict = PyThreadState_GetDict(); + /* Ignore a missing thread-state, so that this function can be called + early on startup. */ + if (dict == NULL) + return 0; list = _PyDict_GetItemIdWithError(dict, &PyId_Py_Repr); - if (list == NULL) { + if (list == NULL) { if (PyErr_Occurred()) { return -1; } - list = PyList_New(0); - if (list == NULL) - return -1; - if (_PyDict_SetItemId(dict, &PyId_Py_Repr, list) < 0) - return -1; - Py_DECREF(list); - } - i = PyList_GET_SIZE(list); - while (--i >= 0) { - if (PyList_GET_ITEM(list, i) == obj) - return 1; - } - if (PyList_Append(list, obj) < 0) - return -1; - return 0; -} - -void -Py_ReprLeave(PyObject *obj) -{ - PyObject *dict; - PyObject *list; - Py_ssize_t i; - PyObject *error_type, *error_value, *error_traceback; - - PyErr_Fetch(&error_type, &error_value, &error_traceback); - - dict = PyThreadState_GetDict(); - if (dict == NULL) - goto finally; - + list = PyList_New(0); + if (list == NULL) + return -1; + if (_PyDict_SetItemId(dict, &PyId_Py_Repr, list) < 0) + return -1; + Py_DECREF(list); + } + i = PyList_GET_SIZE(list); + while (--i >= 0) { + if (PyList_GET_ITEM(list, i) == obj) + return 1; + } + if (PyList_Append(list, obj) < 0) + return -1; + return 0; +} + +void +Py_ReprLeave(PyObject *obj) +{ + PyObject *dict; + PyObject *list; + Py_ssize_t i; + PyObject *error_type, *error_value, *error_traceback; + + PyErr_Fetch(&error_type, &error_value, &error_traceback); + + dict = PyThreadState_GetDict(); + if (dict == NULL) + goto finally; + list = _PyDict_GetItemIdWithError(dict, &PyId_Py_Repr); - if (list == NULL || !PyList_Check(list)) - goto finally; - - i = PyList_GET_SIZE(list); - /* Count backwards because we always expect obj to be list[-1] */ - while (--i >= 0) { - if (PyList_GET_ITEM(list, i) == obj) { - PyList_SetSlice(list, i, i + 1, NULL); - break; - } - } - -finally: - /* ignore exceptions because there is no way to report them. */ - PyErr_Restore(error_type, error_value, error_traceback); -} - -/* Trashcan support. */ - -/* Add op to the _PyTrash_delete_later list. Called when the current - * call-stack depth gets large. op must be a currently untracked gc'ed - * object, with refcount 0. Py_DECREF must already have been called on it. - */ -void -_PyTrash_deposit_object(PyObject *op) -{ + if (list == NULL || !PyList_Check(list)) + goto finally; + + i = PyList_GET_SIZE(list); + /* Count backwards because we always expect obj to be list[-1] */ + while (--i >= 0) { + if (PyList_GET_ITEM(list, i) == obj) { + PyList_SetSlice(list, i, i + 1, NULL); + break; + } + } + +finally: + /* ignore exceptions because there is no way to report them. */ + PyErr_Restore(error_type, error_value, error_traceback); +} + +/* Trashcan support. */ + +/* Add op to the _PyTrash_delete_later list. Called when the current + * call-stack depth gets large. op must be a currently untracked gc'ed + * object, with refcount 0. Py_DECREF must already have been called on it. + */ +void +_PyTrash_deposit_object(PyObject *op) +{ PyThreadState *tstate = _PyThreadState_GET(); struct _gc_runtime_state *gcstate = &tstate->interp->gc; @@ -2037,87 +2037,87 @@ _PyTrash_deposit_object(PyObject *op) _PyObject_ASSERT(op, Py_REFCNT(op) == 0); _PyGCHead_SET_PREV(_Py_AS_GC(op), gcstate->trash_delete_later); gcstate->trash_delete_later = op; -} - -/* The equivalent API, using per-thread state recursion info */ -void -_PyTrash_thread_deposit_object(PyObject *op) -{ +} + +/* The equivalent API, using per-thread state recursion info */ +void +_PyTrash_thread_deposit_object(PyObject *op) +{ PyThreadState *tstate = _PyThreadState_GET(); _PyObject_ASSERT(op, _PyObject_IS_GC(op)); _PyObject_ASSERT(op, !_PyObject_GC_IS_TRACKED(op)); _PyObject_ASSERT(op, Py_REFCNT(op) == 0); _PyGCHead_SET_PREV(_Py_AS_GC(op), tstate->trash_delete_later); - tstate->trash_delete_later = op; -} - + tstate->trash_delete_later = op; +} + /* Deallocate all the objects in the _PyTrash_delete_later list. Called when - * the call-stack unwinds again. - */ -void -_PyTrash_destroy_chain(void) -{ + * the call-stack unwinds again. + */ +void +_PyTrash_destroy_chain(void) +{ PyThreadState *tstate = _PyThreadState_GET(); struct _gc_runtime_state *gcstate = &tstate->interp->gc; while (gcstate->trash_delete_later) { PyObject *op = gcstate->trash_delete_later; - destructor dealloc = Py_TYPE(op)->tp_dealloc; - + destructor dealloc = Py_TYPE(op)->tp_dealloc; + gcstate->trash_delete_later = (PyObject*) _PyGCHead_PREV(_Py_AS_GC(op)); - - /* Call the deallocator directly. This used to try to - * fool Py_DECREF into calling it indirectly, but - * Py_DECREF was already called on this object, and in - * assorted non-release builds calling Py_DECREF again ends - * up distorting allocation statistics. - */ + + /* Call the deallocator directly. This used to try to + * fool Py_DECREF into calling it indirectly, but + * Py_DECREF was already called on this object, and in + * assorted non-release builds calling Py_DECREF again ends + * up distorting allocation statistics. + */ _PyObject_ASSERT(op, Py_REFCNT(op) == 0); ++gcstate->trash_delete_nesting; - (*dealloc)(op); + (*dealloc)(op); --gcstate->trash_delete_nesting; - } -} - -/* The equivalent API, using per-thread state recursion info */ -void -_PyTrash_thread_destroy_chain(void) -{ + } +} + +/* The equivalent API, using per-thread state recursion info */ +void +_PyTrash_thread_destroy_chain(void) +{ PyThreadState *tstate = _PyThreadState_GET(); - /* We need to increase trash_delete_nesting here, otherwise, - _PyTrash_thread_destroy_chain will be called recursively - and then possibly crash. An example that may crash without - increase: - N = 500000 # need to be large enough - ob = object() - tups = [(ob,) for i in range(N)] - for i in range(49): - tups = [(tup,) for tup in tups] - del tups - */ - assert(tstate->trash_delete_nesting == 0); - ++tstate->trash_delete_nesting; - while (tstate->trash_delete_later) { - PyObject *op = tstate->trash_delete_later; - destructor dealloc = Py_TYPE(op)->tp_dealloc; - - tstate->trash_delete_later = + /* We need to increase trash_delete_nesting here, otherwise, + _PyTrash_thread_destroy_chain will be called recursively + and then possibly crash. An example that may crash without + increase: + N = 500000 # need to be large enough + ob = object() + tups = [(ob,) for i in range(N)] + for i in range(49): + tups = [(tup,) for tup in tups] + del tups + */ + assert(tstate->trash_delete_nesting == 0); + ++tstate->trash_delete_nesting; + while (tstate->trash_delete_later) { + PyObject *op = tstate->trash_delete_later; + destructor dealloc = Py_TYPE(op)->tp_dealloc; + + tstate->trash_delete_later = (PyObject*) _PyGCHead_PREV(_Py_AS_GC(op)); - - /* Call the deallocator directly. This used to try to - * fool Py_DECREF into calling it indirectly, but - * Py_DECREF was already called on this object, and in - * assorted non-release builds calling Py_DECREF again ends - * up distorting allocation statistics. - */ + + /* Call the deallocator directly. This used to try to + * fool Py_DECREF into calling it indirectly, but + * Py_DECREF was already called on this object, and in + * assorted non-release builds calling Py_DECREF again ends + * up distorting allocation statistics. + */ _PyObject_ASSERT(op, Py_REFCNT(op) == 0); - (*dealloc)(op); - assert(tstate->trash_delete_nesting == 1); - } - --tstate->trash_delete_nesting; -} - + (*dealloc)(op); + assert(tstate->trash_delete_nesting == 1); + } + --tstate->trash_delete_nesting; +} + int _PyTrash_begin(PyThreadState *tstate, PyObject *op) @@ -2199,16 +2199,16 @@ _PyObject_AssertFailed(PyObject *obj, const char *expr, const char *msg, } -void -_Py_Dealloc(PyObject *op) -{ +void +_Py_Dealloc(PyObject *op) +{ destructor dealloc = Py_TYPE(op)->tp_dealloc; #ifdef Py_TRACE_REFS _Py_ForgetReference(op); #endif (*dealloc)(op); -} - +} + PyObject ** PyObject_GET_WEAKREFS_LISTPTR(PyObject *op) @@ -2217,6 +2217,6 @@ PyObject_GET_WEAKREFS_LISTPTR(PyObject *op) } -#ifdef __cplusplus -} -#endif +#ifdef __cplusplus +} +#endif |