LCOV - code coverage report
Current view: top level - Objects - weakrefobject.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit acb105a7c1f] Lines: 346 408 84.8 %
Date: 2022-07-20 13:12:14 Functions: 45 74 60.8 %
Branches: 228 668 34.1 %

           Branch data     Line data    Source code
       1                 :            : #include "Python.h"
       2                 :            : #include "pycore_object.h"        // _PyObject_GET_WEAKREFS_LISTPTR()
       3                 :            : #include "structmember.h"         // PyMemberDef
       4                 :            : 
       5                 :            : 
       6                 :            : #define GET_WEAKREFS_LISTPTR(o) \
       7                 :            :         ((PyWeakReference **) _PyObject_GET_WEAKREFS_LISTPTR(o))
       8                 :            : 
       9                 :            : 
      10                 :            : Py_ssize_t
      11                 :     624885 : _PyWeakref_GetWeakrefCount(PyWeakReference *head)
      12                 :            : {
      13                 :     624885 :     Py_ssize_t count = 0;
      14                 :            : 
      15         [ +  + ]:    1298166 :     while (head != NULL) {
      16                 :     673281 :         ++count;
      17                 :     673281 :         head = head->wr_next;
      18                 :            :     }
      19                 :     624885 :     return count;
      20                 :            : }
      21                 :            : 
      22                 :            : static PyObject *weakref_vectorcall(PyWeakReference *self, PyObject *const *args, size_t nargsf, PyObject *kwnames);
      23                 :            : 
      24                 :            : static void
      25                 :    3919212 : init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback)
      26                 :            : {
      27                 :    3919212 :     self->hash = -1;
      28                 :    3919212 :     self->wr_object = ob;
      29                 :    3919212 :     self->wr_prev = NULL;
      30                 :    3919212 :     self->wr_next = NULL;
      31                 :    3919212 :     self->wr_callback = Py_XNewRef(callback);
      32                 :    3919212 :     self->vectorcall = (vectorcallfunc)weakref_vectorcall;
      33                 :    3919212 : }
      34                 :            : 
      35                 :            : static PyWeakReference *
      36                 :    2701481 : new_weakref(PyObject *ob, PyObject *callback)
      37                 :            : {
      38                 :            :     PyWeakReference *result;
      39                 :            : 
      40                 :    2701481 :     result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);
      41         [ +  - ]:    2701481 :     if (result) {
      42                 :    2701481 :         init_weakref(result, ob, callback);
      43                 :    2701481 :         PyObject_GC_Track(result);
      44                 :            :     }
      45                 :    2701481 :     return result;
      46                 :            : }
      47                 :            : 
      48                 :            : 
      49                 :            : /* This function clears the passed-in reference and removes it from the
      50                 :            :  * list of weak references for the referent.  This is the only code that
      51                 :            :  * removes an item from the doubly-linked list of weak references for an
      52                 :            :  * object; it is also responsible for clearing the callback slot.
      53                 :            :  */
      54                 :            : static void
      55                 :    6478004 : clear_weakref(PyWeakReference *self)
      56                 :            : {
      57                 :    6478004 :     PyObject *callback = self->wr_callback;
      58                 :            : 
      59         [ +  + ]:    6478004 :     if (self->wr_object != Py_None) {
      60                 :    3793364 :         PyWeakReference **list = GET_WEAKREFS_LISTPTR(self->wr_object);
      61                 :            : 
      62         [ +  + ]:    3793364 :         if (*list == self)
      63                 :            :             /* If 'self' is the end of the list (and thus self->wr_next == NULL)
      64                 :            :                then the weakref list itself (and thus the value of *list) will
      65                 :            :                end up being set to NULL. */
      66                 :    3580077 :             *list = self->wr_next;
      67                 :    3793364 :         self->wr_object = Py_None;
      68         [ +  + ]:    3793364 :         if (self->wr_prev != NULL)
      69                 :     213287 :             self->wr_prev->wr_next = self->wr_next;
      70         [ +  + ]:    3793364 :         if (self->wr_next != NULL)
      71                 :     229815 :             self->wr_next->wr_prev = self->wr_prev;
      72                 :    3793364 :         self->wr_prev = NULL;
      73                 :    3793364 :         self->wr_next = NULL;
      74                 :            :     }
      75         [ +  + ]:    6478004 :     if (callback != NULL) {
      76                 :     742369 :         Py_DECREF(callback);
      77                 :     742369 :         self->wr_callback = NULL;
      78                 :            :     }
      79                 :    6478004 : }
      80                 :            : 
      81                 :            : /* Cyclic gc uses this to *just* clear the passed-in reference, leaving
      82                 :            :  * the callback intact and uncalled.  It must be possible to call self's
      83                 :            :  * tp_dealloc() after calling this, so self has to be left in a sane enough
      84                 :            :  * state for that to work.  We expect tp_dealloc to decref the callback
      85                 :            :  * then.  The reason for not letting clear_weakref() decref the callback
      86                 :            :  * right now is that if the callback goes away, that may in turn trigger
      87                 :            :  * another callback (if a weak reference to the callback exists) -- running
      88                 :            :  * arbitrary Python code in the middle of gc is a disaster.  The convolution
      89                 :            :  * here allows gc to delay triggering such callbacks until the world is in
      90                 :            :  * a sane state again.
      91                 :            :  */
      92                 :            : void
      93                 :    1904535 : _PyWeakref_ClearRef(PyWeakReference *self)
      94                 :            : {
      95                 :            :     PyObject *callback;
      96                 :            : 
      97                 :            :     assert(self != NULL);
      98                 :            :     assert(PyWeakref_Check(self));
      99                 :            :     /* Preserve and restore the callback around clear_weakref. */
     100                 :    1904535 :     callback = self->wr_callback;
     101                 :    1904535 :     self->wr_callback = NULL;
     102                 :    1904535 :     clear_weakref(self);
     103                 :    1904535 :     self->wr_callback = callback;
     104                 :    1904535 : }
     105                 :            : 
     106                 :            : static void
     107                 :    3785985 : weakref_dealloc(PyObject *self)
     108                 :            : {
     109                 :    3785985 :     PyObject_GC_UnTrack(self);
     110                 :    3785985 :     clear_weakref((PyWeakReference *) self);
     111                 :    3785985 :     Py_TYPE(self)->tp_free(self);
     112                 :    3785985 : }
     113                 :            : 
     114                 :            : 
     115                 :            : static int
     116                 :   63255812 : gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
     117                 :            : {
     118   [ +  +  -  + ]:   63255812 :     Py_VISIT(self->wr_callback);
     119                 :   63255812 :     return 0;
     120                 :            : }
     121                 :            : 
     122                 :            : 
     123                 :            : static int
     124                 :         25 : gc_clear(PyWeakReference *self)
     125                 :            : {
     126                 :         25 :     clear_weakref(self);
     127                 :         25 :     return 0;
     128                 :            : }
     129                 :            : 
     130                 :            : 
     131                 :            : static PyObject *
     132                 :     965121 : weakref_vectorcall(PyWeakReference *self, PyObject *const *args,
     133                 :            :                    size_t nargsf, PyObject *kwnames)
     134                 :            : {
     135   [ -  +  -  - ]:     965121 :     if (!_PyArg_NoKwnames("weakref", kwnames)) {
     136                 :          0 :         return NULL;
     137                 :            :     }
     138                 :     965121 :     Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
     139   [ +  -  -  +  :     965121 :     if (!_PyArg_CheckPositional("weakref", nargs, 0, 0)) {
                   -  - ]
     140                 :          0 :         return NULL;
     141                 :            :     }
     142                 :     965121 :     return Py_NewRef(PyWeakref_GET_OBJECT(self));
     143                 :            : }
     144                 :            : 
     145                 :            : static Py_hash_t
     146                 :    1565931 : weakref_hash(PyWeakReference *self)
     147                 :            : {
     148         [ +  + ]:    1565931 :     if (self->hash != -1)
     149                 :    1011563 :         return self->hash;
     150                 :     554368 :     PyObject* obj = PyWeakref_GET_OBJECT(self);
     151         [ +  + ]:     554368 :     if (obj == Py_None) {
     152                 :          2 :         PyErr_SetString(PyExc_TypeError, "weak object has gone away");
     153                 :          2 :         return -1;
     154                 :            :     }
     155                 :     554366 :     Py_INCREF(obj);
     156                 :     554366 :     self->hash = PyObject_Hash(obj);
     157                 :     554366 :     Py_DECREF(obj);
     158                 :     554366 :     return self->hash;
     159                 :            : }
     160                 :            : 
     161                 :            : 
     162                 :            : static PyObject *
     163                 :          9 : weakref_repr(PyWeakReference *self)
     164                 :            : {
     165                 :            :     PyObject *name, *repr;
     166                 :          9 :     PyObject* obj = PyWeakref_GET_OBJECT(self);
     167                 :            : 
     168         [ +  + ]:          9 :     if (obj == Py_None) {
     169                 :          2 :         return PyUnicode_FromFormat("<weakref at %p; dead>", self);
     170                 :            :     }
     171                 :            : 
     172                 :          7 :     Py_INCREF(obj);
     173         [ -  + ]:          7 :     if (_PyObject_LookupAttr(obj, &_Py_ID(__name__), &name) < 0) {
     174                 :          0 :         Py_DECREF(obj);
     175                 :          0 :         return NULL;
     176                 :            :     }
     177   [ -  +  -  - ]:          7 :     if (name == NULL || !PyUnicode_Check(name)) {
     178                 :          7 :         repr = PyUnicode_FromFormat(
     179                 :            :             "<weakref at %p; to '%s' at %p>",
     180                 :            :             self,
     181                 :          7 :             Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name,
     182                 :            :             obj);
     183                 :            :     }
     184                 :            :     else {
     185                 :          0 :         repr = PyUnicode_FromFormat(
     186                 :            :             "<weakref at %p; to '%s' at %p (%U)>",
     187                 :            :             self,
     188                 :          0 :             Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name,
     189                 :            :             obj,
     190                 :            :             name);
     191                 :            :     }
     192                 :          7 :     Py_DECREF(obj);
     193                 :          7 :     Py_XDECREF(name);
     194                 :          7 :     return repr;
     195                 :            : }
     196                 :            : 
     197                 :            : /* Weak references only support equality, not ordering. Two weak references
     198                 :            :    are equal if the underlying objects are equal. If the underlying object has
     199                 :            :    gone away, they are equal if they are identical. */
     200                 :            : 
     201                 :            : static PyObject *
     202                 :     548886 : weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
     203                 :            : {
     204   [ +  +  +  +  :    1097756 :     if ((op != Py_EQ && op != Py_NE) ||
                   -  + ]
     205   [ -  -  -  -  :    1097740 :         !PyWeakref_Check(self) ||
                   +  + ]
     206   [ +  -  +  - ]:     548874 :         !PyWeakref_Check(other)) {
     207                 :         20 :         Py_RETURN_NOTIMPLEMENTED;
     208                 :            :     }
     209         [ +  + ]:     548866 :     if (PyWeakref_GET_OBJECT(self) == Py_None
     210         [ +  + ]:     548855 :         || PyWeakref_GET_OBJECT(other) == Py_None) {
     211                 :        345 :         int res = (self == other);
     212         [ +  + ]:        345 :         if (op == Py_NE)
     213                 :          3 :             res = !res;
     214         [ +  + ]:        345 :         if (res)
     215                 :          3 :             Py_RETURN_TRUE;
     216                 :            :         else
     217                 :        342 :             Py_RETURN_FALSE;
     218                 :            :     }
     219                 :     548521 :     PyObject* obj = PyWeakref_GET_OBJECT(self);
     220                 :     548521 :     PyObject* other_obj = PyWeakref_GET_OBJECT(other);
     221                 :     548521 :     Py_INCREF(obj);
     222                 :     548521 :     Py_INCREF(other_obj);
     223                 :     548521 :     PyObject* res = PyObject_RichCompare(obj, other_obj, op);
     224                 :     548521 :     Py_DECREF(obj);
     225                 :     548521 :     Py_DECREF(other_obj);
     226                 :     548521 :     return res;
     227                 :            : }
     228                 :            : 
     229                 :            : /* Given the head of an object's list of weak references, extract the
     230                 :            :  * two callback-less refs (ref and proxy).  Used to determine if the
     231                 :            :  * shared references exist and to determine the back link for newly
     232                 :            :  * inserted references.
     233                 :            :  */
     234                 :            : static void
     235                 :    8954061 : get_basic_refs(PyWeakReference *head,
     236                 :            :                PyWeakReference **refp, PyWeakReference **proxyp)
     237                 :            : {
     238                 :    8954061 :     *refp = NULL;
     239                 :    8954061 :     *proxyp = NULL;
     240                 :            : 
     241   [ +  +  +  + ]:    8954061 :     if (head != NULL && head->wr_callback == NULL) {
     242                 :            :         /* We need to be careful that the "basic refs" aren't
     243                 :            :            subclasses of the main types.  That complicates this a
     244                 :            :            little. */
     245         [ +  + ]:    1598799 :         if (PyWeakref_CheckRefExact(head)) {
     246                 :    1598792 :             *refp = head;
     247                 :    1598792 :             head = head->wr_next;
     248                 :            :         }
     249         [ +  + ]:    1598799 :         if (head != NULL
     250         [ +  + ]:    1037852 :             && head->wr_callback == NULL
     251   [ +  +  -  + ]:         14 :             && PyWeakref_CheckProxy(head)) {
     252                 :         11 :             *proxyp = head;
     253                 :            :             /* head = head->wr_next; */
     254                 :            :         }
     255                 :            :     }
     256                 :    8954061 : }
     257                 :            : 
     258                 :            : /* Insert 'newref' in the list after 'prev'.  Both must be non-NULL. */
     259                 :            : static void
     260                 :     227473 : insert_after(PyWeakReference *newref, PyWeakReference *prev)
     261                 :            : {
     262                 :     227473 :     newref->wr_prev = prev;
     263                 :     227473 :     newref->wr_next = prev->wr_next;
     264         [ +  + ]:     227473 :     if (prev->wr_next != NULL)
     265                 :     108376 :         prev->wr_next->wr_prev = newref;
     266                 :     227473 :     prev->wr_next = newref;
     267                 :     227473 : }
     268                 :            : 
     269                 :            : /* Insert 'newref' at the head of the list; 'list' points to the variable
     270                 :            :  * that stores the head.
     271                 :            :  */
     272                 :            : static void
     273                 :    3691739 : insert_head(PyWeakReference *newref, PyWeakReference **list)
     274                 :            : {
     275                 :    3691739 :     PyWeakReference *next = *list;
     276                 :            : 
     277                 :    3691739 :     newref->wr_prev = NULL;
     278                 :    3691739 :     newref->wr_next = next;
     279         [ +  + ]:    3691739 :     if (next != NULL)
     280                 :     161771 :         next->wr_prev = newref;
     281                 :    3691739 :     *list = newref;
     282                 :    3691739 : }
     283                 :            : 
     284                 :            : static int
     285                 :    2460639 : parse_weakref_init_args(const char *funcname, PyObject *args, PyObject *kwargs,
     286                 :            :                         PyObject **obp, PyObject **callbackp)
     287                 :            : {
     288                 :    2460639 :     return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp);
     289                 :            : }
     290                 :            : 
     291                 :            : static PyObject *
     292                 :    1230329 : weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs)
     293                 :            : {
     294                 :    1230329 :     PyWeakReference *self = NULL;
     295                 :    1230329 :     PyObject *ob, *callback = NULL;
     296                 :            : 
     297         [ +  - ]:    1230329 :     if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) {
     298                 :            :         PyWeakReference *ref, *proxy;
     299                 :            :         PyWeakReference **list;
     300                 :            : 
     301         [ +  + ]:    1230329 :         if (!_PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
     302                 :         18 :             PyErr_Format(PyExc_TypeError,
     303                 :            :                          "cannot create weak reference to '%s' object",
     304                 :         18 :                          Py_TYPE(ob)->tp_name);
     305                 :      12598 :             return NULL;
     306                 :            :         }
     307         [ +  + ]:    1230311 :         if (callback == Py_None)
     308                 :          5 :             callback = NULL;
     309                 :    1230311 :         list = GET_WEAKREFS_LISTPTR(ob);
     310                 :    1230311 :         get_basic_refs(*list, &ref, &proxy);
     311   [ +  +  +  + ]:    1230311 :         if (callback == NULL && type == &_PyWeakref_RefType) {
     312         [ +  + ]:      40793 :             if (ref != NULL) {
     313                 :            :                 /* We can re-use an existing reference. */
     314                 :      12580 :                 Py_INCREF(ref);
     315                 :      12580 :                 return (PyObject *)ref;
     316                 :            :             }
     317                 :            :         }
     318                 :            :         /* We have to create a new reference. */
     319                 :            :         /* Note: the tp_alloc() can trigger cyclic GC, so the weakref
     320                 :            :            list on ob can be mutated.  This means that the ref and
     321                 :            :            proxy pointers we got back earlier may have been collected,
     322                 :            :            so we need to compute these values again before we use
     323                 :            :            them. */
     324                 :    1217731 :         self = (PyWeakReference *) (type->tp_alloc(type, 0));
     325         [ +  - ]:    1217731 :         if (self != NULL) {
     326                 :    1217731 :             init_weakref(self, ob, callback);
     327   [ +  +  +  + ]:    1217731 :             if (callback == NULL && type == &_PyWeakref_RefType) {
     328                 :      28213 :                 insert_head(self, list);
     329                 :            :             }
     330                 :            :             else {
     331                 :            :                 PyWeakReference *prev;
     332                 :            : 
     333                 :    1189518 :                 get_basic_refs(*list, &ref, &proxy);
     334         [ +  - ]:    1189518 :                 prev = (proxy == NULL) ? ref : proxy;
     335         [ +  + ]:    1189518 :                 if (prev == NULL)
     336                 :    1188560 :                     insert_head(self, list);
     337                 :            :                 else
     338                 :        958 :                     insert_after(self, prev);
     339                 :            :             }
     340                 :            :         }
     341                 :            :     }
     342                 :    1217731 :     return (PyObject *)self;
     343                 :            : }
     344                 :            : 
     345                 :            : static int
     346                 :    1230311 : weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)
     347                 :            : {
     348                 :            :     PyObject *tmp;
     349                 :            : 
     350   [ +  +  +  + ]:    1230311 :     if (!_PyArg_NoKeywords("ref", kwargs))
     351                 :          1 :         return -1;
     352                 :            : 
     353         [ +  + ]:    1230310 :     if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp))
     354                 :    1230309 :         return 0;
     355                 :            :     else
     356                 :          1 :         return -1;
     357                 :            : }
     358                 :            : 
     359                 :            : 
     360                 :            : static PyMemberDef weakref_members[] = {
     361                 :            :     {"__callback__", T_OBJECT, offsetof(PyWeakReference, wr_callback), READONLY},
     362                 :            :     {NULL} /* Sentinel */
     363                 :            : };
     364                 :            : 
     365                 :            : static PyMethodDef weakref_methods[] = {
     366                 :            :     {"__class_getitem__",    Py_GenericAlias,
     367                 :            :     METH_O|METH_CLASS,       PyDoc_STR("See PEP 585")},
     368                 :            :     {NULL} /* Sentinel */
     369                 :            : };
     370                 :            : 
     371                 :            : PyTypeObject
     372                 :            : _PyWeakref_RefType = {
     373                 :            :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
     374                 :            :     .tp_name = "weakref.ReferenceType",
     375                 :            :     .tp_basicsize = sizeof(PyWeakReference),
     376                 :            :     .tp_dealloc = weakref_dealloc,
     377                 :            :     .tp_vectorcall_offset = offsetof(PyWeakReference, vectorcall),
     378                 :            :     .tp_call = PyVectorcall_Call,
     379                 :            :     .tp_repr = (reprfunc)weakref_repr,
     380                 :            :     .tp_hash = (hashfunc)weakref_hash,
     381                 :            :     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
     382                 :            :                 Py_TPFLAGS_HAVE_VECTORCALL | Py_TPFLAGS_BASETYPE,
     383                 :            :     .tp_traverse = (traverseproc)gc_traverse,
     384                 :            :     .tp_clear = (inquiry)gc_clear,
     385                 :            :     .tp_richcompare = (richcmpfunc)weakref_richcompare,
     386                 :            :     .tp_methods = weakref_methods,
     387                 :            :     .tp_members = weakref_members,
     388                 :            :     .tp_init = weakref___init__,
     389                 :            :     .tp_alloc = PyType_GenericAlloc,
     390                 :            :     .tp_new = weakref___new__,
     391                 :            :     .tp_free = PyObject_GC_Del,
     392                 :            : };
     393                 :            : 
     394                 :            : 
     395                 :            : static int
     396                 :      19341 : proxy_checkref(PyWeakReference *proxy)
     397                 :            : {
     398         [ +  + ]:      19341 :     if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
     399                 :         29 :         PyErr_SetString(PyExc_ReferenceError,
     400                 :            :                         "weakly-referenced object no longer exists");
     401                 :         29 :         return 0;
     402                 :            :     }
     403                 :      19312 :     return 1;
     404                 :            : }
     405                 :            : 
     406                 :            : 
     407                 :            : /* If a parameter is a proxy, check that it is still "live" and wrap it,
     408                 :            :  * replacing the original value with the raw object.  Raises ReferenceError
     409                 :            :  * if the param is a dead proxy.
     410                 :            :  */
     411                 :            : #define UNWRAP(o) \
     412                 :            :         if (PyWeakref_CheckProxy(o)) { \
     413                 :            :             if (!proxy_checkref((PyWeakReference *)o)) \
     414                 :            :                 return NULL; \
     415                 :            :             o = PyWeakref_GET_OBJECT(o); \
     416                 :            :         }
     417                 :            : 
     418                 :            : #define WRAP_UNARY(method, generic) \
     419                 :            :     static PyObject * \
     420                 :            :     method(PyObject *proxy) { \
     421                 :            :         UNWRAP(proxy); \
     422                 :            :         Py_INCREF(proxy); \
     423                 :            :         PyObject* res = generic(proxy); \
     424                 :            :         Py_DECREF(proxy); \
     425                 :            :         return res; \
     426                 :            :     }
     427                 :            : 
     428                 :            : #define WRAP_BINARY(method, generic) \
     429                 :            :     static PyObject * \
     430                 :            :     method(PyObject *x, PyObject *y) { \
     431                 :            :         UNWRAP(x); \
     432                 :            :         UNWRAP(y); \
     433                 :            :         Py_INCREF(x); \
     434                 :            :         Py_INCREF(y); \
     435                 :            :         PyObject* res = generic(x, y); \
     436                 :            :         Py_DECREF(x); \
     437                 :            :         Py_DECREF(y); \
     438                 :            :         return res; \
     439                 :            :     }
     440                 :            : 
     441                 :            : /* Note that the third arg needs to be checked for NULL since the tp_call
     442                 :            :  * slot can receive NULL for this arg.
     443                 :            :  */
     444                 :            : #define WRAP_TERNARY(method, generic) \
     445                 :            :     static PyObject * \
     446                 :            :     method(PyObject *proxy, PyObject *v, PyObject *w) { \
     447                 :            :         UNWRAP(proxy); \
     448                 :            :         UNWRAP(v); \
     449                 :            :         if (w != NULL) \
     450                 :            :             UNWRAP(w); \
     451                 :            :         Py_INCREF(proxy); \
     452                 :            :         Py_INCREF(v); \
     453                 :            :         Py_XINCREF(w); \
     454                 :            :         PyObject* res = generic(proxy, v, w); \
     455                 :            :         Py_DECREF(proxy); \
     456                 :            :         Py_DECREF(v); \
     457                 :            :         Py_XDECREF(w); \
     458                 :            :         return res; \
     459                 :            :     }
     460                 :            : 
     461                 :            : #define WRAP_METHOD(method, SPECIAL) \
     462                 :            :     static PyObject * \
     463                 :            :     method(PyObject *proxy, PyObject *Py_UNUSED(ignored)) { \
     464                 :            :             UNWRAP(proxy); \
     465                 :            :             Py_INCREF(proxy); \
     466                 :            :             PyObject* res = PyObject_CallMethodNoArgs(proxy, &_Py_ID(SPECIAL)); \
     467                 :            :             Py_DECREF(proxy); \
     468                 :            :             return res; \
     469                 :            :         }
     470                 :            : 
     471                 :            : 
     472                 :            : /* direct slots */
     473                 :            : 
     474   [ +  +  +  -  :       5736 : WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
          +  +  +  -  -  
                +  -  - ]
     475   [ +  +  +  -  :          8 : WRAP_UNARY(proxy_str, PyObject_Str)
                   +  + ]
     476   [ +  -  +  -  :          4 : WRAP_TERNARY(proxy_call, PyObject_Call)
          -  +  +  -  -  
          +  -  -  +  +  
          +  -  -  +  -  
                      - ]
     477                 :            : 
     478                 :            : static PyObject *
     479                 :          0 : proxy_repr(PyWeakReference *proxy)
     480                 :            : {
     481                 :          0 :     return PyUnicode_FromFormat(
     482                 :            :         "<weakproxy at %p to %s at %p>",
     483                 :            :         proxy,
     484                 :          0 :         Py_TYPE(PyWeakref_GET_OBJECT(proxy))->tp_name,
     485                 :            :         PyWeakref_GET_OBJECT(proxy));
     486                 :            : }
     487                 :            : 
     488                 :            : 
     489                 :            : static int
     490                 :      13544 : proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
     491                 :            : {
     492         [ -  + ]:      13544 :     if (!proxy_checkref(proxy))
     493                 :          0 :         return -1;
     494                 :      13544 :     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
     495                 :      13544 :     Py_INCREF(obj);
     496                 :      13544 :     int res = PyObject_SetAttr(obj, name, value);
     497                 :      13544 :     Py_DECREF(obj);
     498                 :      13544 :     return res;
     499                 :            : }
     500                 :            : 
     501                 :            : static PyObject *
     502                 :          1 : proxy_richcompare(PyObject *proxy, PyObject *v, int op)
     503                 :            : {
     504   [ -  +  -  -  :          1 :     UNWRAP(proxy);
                   -  + ]
     505   [ -  +  -  -  :          1 :     UNWRAP(v);
                   -  + ]
     506                 :          1 :     return PyObject_RichCompare(proxy, v, op);
     507                 :            : }
     508                 :            : 
     509                 :            : /* number slots */
     510   [ +  +  -  +  :          2 : WRAP_BINARY(proxy_add, PyNumber_Add)
          -  +  +  +  -  
                +  -  + ]
     511   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_sub, PyNumber_Subtract)
          #  #  #  #  #  
                #  #  # ]
     512   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_mul, PyNumber_Multiply)
          #  #  #  #  #  
                #  #  # ]
     513   [ -  +  -  -  :          1 : WRAP_BINARY(proxy_floor_div, PyNumber_FloorDivide)
          -  +  +  -  -  
                +  -  - ]
     514   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_true_div, PyNumber_TrueDivide)
          #  #  #  #  #  
                #  #  # ]
     515   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_mod, PyNumber_Remainder)
          #  #  #  #  #  
                #  #  # ]
     516   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
          #  #  #  #  #  
                #  #  # ]
     517   [ #  #  #  #  :          0 : WRAP_TERNARY(proxy_pow, PyNumber_Power)
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     518   [ #  #  #  #  :          0 : WRAP_UNARY(proxy_neg, PyNumber_Negative)
                   #  # ]
     519   [ #  #  #  #  :          0 : WRAP_UNARY(proxy_pos, PyNumber_Positive)
                   #  # ]
     520   [ #  #  #  #  :          0 : WRAP_UNARY(proxy_abs, PyNumber_Absolute)
                   #  # ]
     521   [ #  #  #  #  :          0 : WRAP_UNARY(proxy_invert, PyNumber_Invert)
                   #  # ]
     522   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
          #  #  #  #  #  
                #  #  # ]
     523   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
          #  #  #  #  #  
                #  #  # ]
     524   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_and, PyNumber_And)
          #  #  #  #  #  
                #  #  # ]
     525   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_xor, PyNumber_Xor)
          #  #  #  #  #  
                #  #  # ]
     526   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_or, PyNumber_Or)
          #  #  #  #  #  
                #  #  # ]
     527   [ #  #  #  #  :          0 : WRAP_UNARY(proxy_int, PyNumber_Long)
                   #  # ]
     528   [ #  #  #  #  :          0 : WRAP_UNARY(proxy_float, PyNumber_Float)
                   #  # ]
     529   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
          #  #  #  #  #  
                #  #  # ]
     530   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
          #  #  #  #  #  
                #  #  # ]
     531   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
          #  #  #  #  #  
                #  #  # ]
     532   [ -  +  -  -  :          1 : WRAP_BINARY(proxy_ifloor_div, PyNumber_InPlaceFloorDivide)
          -  +  +  -  -  
                +  -  - ]
     533   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_itrue_div, PyNumber_InPlaceTrueDivide)
          #  #  #  #  #  
                #  #  # ]
     534   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
          #  #  #  #  #  
                #  #  # ]
     535   [ #  #  #  #  :          0 : WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     536   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
          #  #  #  #  #  
                #  #  # ]
     537   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
          #  #  #  #  #  
                #  #  # ]
     538   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
          #  #  #  #  #  
                #  #  # ]
     539   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
          #  #  #  #  #  
                #  #  # ]
     540   [ #  #  #  #  :          0 : WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
          #  #  #  #  #  
                #  #  # ]
     541   [ -  +  -  -  :          1 : WRAP_UNARY(proxy_index, PyNumber_Index)
                   -  + ]
     542   [ +  +  -  +  :          2 : WRAP_BINARY(proxy_matmul, PyNumber_MatrixMultiply)
          -  +  +  +  -  
                +  -  + ]
     543   [ -  +  -  -  :          1 : WRAP_BINARY(proxy_imatmul, PyNumber_InPlaceMatrixMultiply)
          -  +  +  -  -  
                +  -  - ]
     544                 :            : 
     545                 :            : static int
     546                 :          4 : proxy_bool(PyWeakReference *proxy)
     547                 :            : {
     548                 :          4 :     PyObject *o = PyWeakref_GET_OBJECT(proxy);
     549         [ +  + ]:          4 :     if (!proxy_checkref(proxy)) {
     550                 :          1 :         return -1;
     551                 :            :     }
     552                 :          3 :     Py_INCREF(o);
     553                 :          3 :     int res = PyObject_IsTrue(o);
     554                 :          3 :     Py_DECREF(o);
     555                 :          3 :     return res;
     556                 :            : }
     557                 :            : 
     558                 :            : static void
     559                 :       6979 : proxy_dealloc(PyWeakReference *self)
     560                 :            : {
     561         [ +  + ]:       6979 :     if (self->wr_callback != NULL)
     562                 :        121 :         PyObject_GC_UnTrack((PyObject *)self);
     563                 :       6979 :     clear_weakref(self);
     564                 :       6979 :     PyObject_GC_Del(self);
     565                 :       6979 : }
     566                 :            : 
     567                 :            : /* sequence slots */
     568                 :            : 
     569                 :            : static int
     570                 :          2 : proxy_contains(PyWeakReference *proxy, PyObject *value)
     571                 :            : {
     572         [ -  + ]:          2 :     if (!proxy_checkref(proxy))
     573                 :          0 :         return -1;
     574                 :            : 
     575                 :          2 :     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
     576                 :          2 :     Py_INCREF(obj);
     577                 :          2 :     int res = PySequence_Contains(obj, value);
     578                 :          2 :     Py_DECREF(obj);
     579                 :          2 :     return res;
     580                 :            : }
     581                 :            : 
     582                 :            : /* mapping slots */
     583                 :            : 
     584                 :            : static Py_ssize_t
     585                 :         16 : proxy_length(PyWeakReference *proxy)
     586                 :            : {
     587         [ +  + ]:         16 :     if (!proxy_checkref(proxy))
     588                 :         13 :         return -1;
     589                 :            : 
     590                 :          3 :     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
     591                 :          3 :     Py_INCREF(obj);
     592                 :          3 :     Py_ssize_t res = PyObject_Length(obj);
     593                 :          3 :     Py_DECREF(obj);
     594                 :          3 :     return res;
     595                 :            : }
     596                 :            : 
     597   [ -  +  -  -  :          5 : WRAP_BINARY(proxy_getitem, PyObject_GetItem)
          -  +  +  -  -  
                +  -  - ]
     598                 :            : 
     599                 :            : static int
     600                 :          3 : proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
     601                 :            : {
     602         [ -  + ]:          3 :     if (!proxy_checkref(proxy))
     603                 :          0 :         return -1;
     604                 :            : 
     605                 :          3 :     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
     606                 :          3 :     Py_INCREF(obj);
     607                 :            :     int res;
     608         [ +  + ]:          3 :     if (value == NULL) {
     609                 :          1 :         res = PyObject_DelItem(obj, key);
     610                 :            :     } else {
     611                 :          2 :         res = PyObject_SetItem(obj, key, value);
     612                 :            :     }
     613                 :          3 :     Py_DECREF(obj);
     614                 :          3 :     return res;
     615                 :            : }
     616                 :            : 
     617                 :            : /* iterator slots */
     618                 :            : 
     619                 :            : static PyObject *
     620                 :          2 : proxy_iter(PyWeakReference *proxy)
     621                 :            : {
     622         [ -  + ]:          2 :     if (!proxy_checkref(proxy))
     623                 :          0 :         return NULL;
     624                 :          2 :     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
     625                 :          2 :     Py_INCREF(obj);
     626                 :          2 :     PyObject* res = PyObject_GetIter(obj);
     627                 :          2 :     Py_DECREF(obj);
     628                 :          2 :     return res;
     629                 :            : }
     630                 :            : 
     631                 :            : static PyObject *
     632                 :          5 : proxy_iternext(PyWeakReference *proxy)
     633                 :            : {
     634         [ -  + ]:          5 :     if (!proxy_checkref(proxy))
     635                 :          0 :         return NULL;
     636                 :            : 
     637                 :          5 :     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
     638         [ +  + ]:          5 :     if (!PyIter_Check(obj)) {
     639                 :          1 :         PyErr_Format(PyExc_TypeError,
     640                 :            :             "Weakref proxy referenced a non-iterator '%.200s' object",
     641                 :          1 :             Py_TYPE(obj)->tp_name);
     642                 :          1 :         return NULL;
     643                 :            :     }
     644                 :          4 :     Py_INCREF(obj);
     645                 :          4 :     PyObject* res = PyIter_Next(obj);
     646                 :          4 :     Py_DECREF(obj);
     647                 :          4 :     return res;
     648                 :            : }
     649                 :            : 
     650                 :            : 
     651   [ -  +  -  -  :          1 : WRAP_METHOD(proxy_bytes, __bytes__)
                   -  + ]
     652   [ -  +  -  -  :          1 : WRAP_METHOD(proxy_reversed, __reversed__)
                   -  + ]
     653                 :            : 
     654                 :            : 
     655                 :            : static PyMethodDef proxy_methods[] = {
     656                 :            :         {"__bytes__", proxy_bytes, METH_NOARGS},
     657                 :            :         {"__reversed__", proxy_reversed, METH_NOARGS},
     658                 :            :         {NULL, NULL}
     659                 :            : };
     660                 :            : 
     661                 :            : 
     662                 :            : static PyNumberMethods proxy_as_number = {
     663                 :            :     proxy_add,              /*nb_add*/
     664                 :            :     proxy_sub,              /*nb_subtract*/
     665                 :            :     proxy_mul,              /*nb_multiply*/
     666                 :            :     proxy_mod,              /*nb_remainder*/
     667                 :            :     proxy_divmod,           /*nb_divmod*/
     668                 :            :     proxy_pow,              /*nb_power*/
     669                 :            :     proxy_neg,              /*nb_negative*/
     670                 :            :     proxy_pos,              /*nb_positive*/
     671                 :            :     proxy_abs,              /*nb_absolute*/
     672                 :            :     (inquiry)proxy_bool,    /*nb_bool*/
     673                 :            :     proxy_invert,           /*nb_invert*/
     674                 :            :     proxy_lshift,           /*nb_lshift*/
     675                 :            :     proxy_rshift,           /*nb_rshift*/
     676                 :            :     proxy_and,              /*nb_and*/
     677                 :            :     proxy_xor,              /*nb_xor*/
     678                 :            :     proxy_or,               /*nb_or*/
     679                 :            :     proxy_int,              /*nb_int*/
     680                 :            :     0,                      /*nb_reserved*/
     681                 :            :     proxy_float,            /*nb_float*/
     682                 :            :     proxy_iadd,             /*nb_inplace_add*/
     683                 :            :     proxy_isub,             /*nb_inplace_subtract*/
     684                 :            :     proxy_imul,             /*nb_inplace_multiply*/
     685                 :            :     proxy_imod,             /*nb_inplace_remainder*/
     686                 :            :     proxy_ipow,             /*nb_inplace_power*/
     687                 :            :     proxy_ilshift,          /*nb_inplace_lshift*/
     688                 :            :     proxy_irshift,          /*nb_inplace_rshift*/
     689                 :            :     proxy_iand,             /*nb_inplace_and*/
     690                 :            :     proxy_ixor,             /*nb_inplace_xor*/
     691                 :            :     proxy_ior,              /*nb_inplace_or*/
     692                 :            :     proxy_floor_div,        /*nb_floor_divide*/
     693                 :            :     proxy_true_div,         /*nb_true_divide*/
     694                 :            :     proxy_ifloor_div,       /*nb_inplace_floor_divide*/
     695                 :            :     proxy_itrue_div,        /*nb_inplace_true_divide*/
     696                 :            :     proxy_index,            /*nb_index*/
     697                 :            :     proxy_matmul,           /*nb_matrix_multiply*/
     698                 :            :     proxy_imatmul,          /*nb_inplace_matrix_multiply*/
     699                 :            : };
     700                 :            : 
     701                 :            : static PySequenceMethods proxy_as_sequence = {
     702                 :            :     (lenfunc)proxy_length,      /*sq_length*/
     703                 :            :     0,                          /*sq_concat*/
     704                 :            :     0,                          /*sq_repeat*/
     705                 :            :     0,                          /*sq_item*/
     706                 :            :     0,                          /*sq_slice*/
     707                 :            :     0,                          /*sq_ass_item*/
     708                 :            :     0,                           /*sq_ass_slice*/
     709                 :            :     (objobjproc)proxy_contains, /* sq_contains */
     710                 :            : };
     711                 :            : 
     712                 :            : static PyMappingMethods proxy_as_mapping = {
     713                 :            :     (lenfunc)proxy_length,        /*mp_length*/
     714                 :            :     proxy_getitem,                /*mp_subscript*/
     715                 :            :     (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
     716                 :            : };
     717                 :            : 
     718                 :            : 
     719                 :            : PyTypeObject
     720                 :            : _PyWeakref_ProxyType = {
     721                 :            :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
     722                 :            :     "weakref.ProxyType",
     723                 :            :     sizeof(PyWeakReference),
     724                 :            :     0,
     725                 :            :     /* methods */
     726                 :            :     (destructor)proxy_dealloc,          /* tp_dealloc */
     727                 :            :     0,                                  /* tp_vectorcall_offset */
     728                 :            :     0,                                  /* tp_getattr */
     729                 :            :     0,                                  /* tp_setattr */
     730                 :            :     0,                                  /* tp_as_async */
     731                 :            :     (reprfunc)proxy_repr,               /* tp_repr */
     732                 :            :     &proxy_as_number,                   /* tp_as_number */
     733                 :            :     &proxy_as_sequence,                 /* tp_as_sequence */
     734                 :            :     &proxy_as_mapping,                  /* tp_as_mapping */
     735                 :            : // Notice that tp_hash is intentionally omitted as proxies are "mutable" (when the reference dies).
     736                 :            :     0,                                  /* tp_hash */
     737                 :            :     0,                                  /* tp_call */
     738                 :            :     proxy_str,                          /* tp_str */
     739                 :            :     proxy_getattr,                      /* tp_getattro */
     740                 :            :     (setattrofunc)proxy_setattr,        /* tp_setattro */
     741                 :            :     0,                                  /* tp_as_buffer */
     742                 :            :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
     743                 :            :     0,                                  /* tp_doc */
     744                 :            :     (traverseproc)gc_traverse,          /* tp_traverse */
     745                 :            :     (inquiry)gc_clear,                  /* tp_clear */
     746                 :            :     proxy_richcompare,                  /* tp_richcompare */
     747                 :            :     0,                                  /* tp_weaklistoffset */
     748                 :            :     (getiterfunc)proxy_iter,            /* tp_iter */
     749                 :            :     (iternextfunc)proxy_iternext,       /* tp_iternext */
     750                 :            :         proxy_methods,                      /* tp_methods */
     751                 :            : };
     752                 :            : 
     753                 :            : 
     754                 :            : PyTypeObject
     755                 :            : _PyWeakref_CallableProxyType = {
     756                 :            :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
     757                 :            :     "weakref.CallableProxyType",
     758                 :            :     sizeof(PyWeakReference),
     759                 :            :     0,
     760                 :            :     /* methods */
     761                 :            :     (destructor)proxy_dealloc,          /* tp_dealloc */
     762                 :            :     0,                                  /* tp_vectorcall_offset */
     763                 :            :     0,                                  /* tp_getattr */
     764                 :            :     0,                                  /* tp_setattr */
     765                 :            :     0,                                  /* tp_as_async */
     766                 :            :     (unaryfunc)proxy_repr,              /* tp_repr */
     767                 :            :     &proxy_as_number,                   /* tp_as_number */
     768                 :            :     &proxy_as_sequence,                 /* tp_as_sequence */
     769                 :            :     &proxy_as_mapping,                  /* tp_as_mapping */
     770                 :            :     0,                                  /* tp_hash */
     771                 :            :     proxy_call,                         /* tp_call */
     772                 :            :     proxy_str,                          /* tp_str */
     773                 :            :     proxy_getattr,                      /* tp_getattro */
     774                 :            :     (setattrofunc)proxy_setattr,        /* tp_setattro */
     775                 :            :     0,                                  /* tp_as_buffer */
     776                 :            :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
     777                 :            :     0,                                  /* tp_doc */
     778                 :            :     (traverseproc)gc_traverse,          /* tp_traverse */
     779                 :            :     (inquiry)gc_clear,                  /* tp_clear */
     780                 :            :     proxy_richcompare,                  /* tp_richcompare */
     781                 :            :     0,                                  /* tp_weaklistoffset */
     782                 :            :     (getiterfunc)proxy_iter,            /* tp_iter */
     783                 :            :     (iternextfunc)proxy_iternext,       /* tp_iternext */
     784                 :            : };
     785                 :            : 
     786                 :            : 
     787                 :            : 
     788                 :            : PyObject *
     789                 :    3825761 : PyWeakref_NewRef(PyObject *ob, PyObject *callback)
     790                 :            : {
     791                 :    3825761 :     PyWeakReference *result = NULL;
     792                 :            :     PyWeakReference **list;
     793                 :            :     PyWeakReference *ref, *proxy;
     794                 :            : 
     795         [ -  + ]:    3825761 :     if (!_PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
     796                 :          0 :         PyErr_Format(PyExc_TypeError,
     797                 :            :                      "cannot create weak reference to '%s' object",
     798                 :          0 :                      Py_TYPE(ob)->tp_name);
     799                 :          0 :         return NULL;
     800                 :            :     }
     801                 :    3825761 :     list = GET_WEAKREFS_LISTPTR(ob);
     802                 :    3825761 :     get_basic_refs(*list, &ref, &proxy);
     803         [ -  + ]:    3825761 :     if (callback == Py_None)
     804                 :          0 :         callback = NULL;
     805         [ +  + ]:    3825761 :     if (callback == NULL)
     806                 :            :         /* return existing weak reference if it exists */
     807                 :    3597386 :         result = ref;
     808         [ +  + ]:    3825761 :     if (result != NULL)
     809                 :    1131265 :         Py_INCREF(result);
     810                 :            :     else {
     811                 :            :         /* Note: new_weakref() can trigger cyclic GC, so the weakref
     812                 :            :            list on ob can be mutated.  This means that the ref and
     813                 :            :            proxy pointers we got back earlier may have been collected,
     814                 :            :            so we need to compute these values again before we use
     815                 :            :            them. */
     816                 :    2694496 :         result = new_weakref(ob, callback);
     817         [ +  - ]:    2694496 :         if (result != NULL) {
     818                 :    2694496 :             get_basic_refs(*list, &ref, &proxy);
     819         [ +  + ]:    2694496 :             if (callback == NULL) {
     820         [ +  - ]:    2466121 :                 if (ref == NULL)
     821                 :    2466121 :                     insert_head(result, list);
     822                 :            :                 else {
     823                 :            :                     /* Someone else added a ref without a callback
     824                 :            :                        during GC.  Return that one instead of this one
     825                 :            :                        to avoid violating the invariants of the list
     826                 :            :                        of weakrefs for ob. */
     827                 :          0 :                     Py_DECREF(result);
     828                 :          0 :                     Py_INCREF(ref);
     829                 :          0 :                     result = ref;
     830                 :            :                 }
     831                 :            :             }
     832                 :            :             else {
     833                 :            :                 PyWeakReference *prev;
     834                 :            : 
     835         [ +  - ]:     228375 :                 prev = (proxy == NULL) ? ref : proxy;
     836         [ +  + ]:     228375 :                 if (prev == NULL)
     837                 :       1993 :                     insert_head(result, list);
     838                 :            :                 else
     839                 :     226382 :                     insert_after(result, prev);
     840                 :            :             }
     841                 :            :         }
     842                 :            :     }
     843                 :    3825761 :     return (PyObject *) result;
     844                 :            : }
     845                 :            : 
     846                 :            : 
     847                 :            : PyObject *
     848                 :       6990 : PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
     849                 :            : {
     850                 :       6990 :     PyWeakReference *result = NULL;
     851                 :            :     PyWeakReference **list;
     852                 :            :     PyWeakReference *ref, *proxy;
     853                 :            : 
     854         [ -  + ]:       6990 :     if (!_PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
     855                 :          0 :         PyErr_Format(PyExc_TypeError,
     856                 :            :                      "cannot create weak reference to '%s' object",
     857                 :          0 :                      Py_TYPE(ob)->tp_name);
     858                 :          0 :         return NULL;
     859                 :            :     }
     860                 :       6990 :     list = GET_WEAKREFS_LISTPTR(ob);
     861                 :       6990 :     get_basic_refs(*list, &ref, &proxy);
     862         [ +  + ]:       6990 :     if (callback == Py_None)
     863                 :          4 :         callback = NULL;
     864         [ +  + ]:       6990 :     if (callback == NULL)
     865                 :            :         /* attempt to return an existing weak reference if it exists */
     866                 :       6861 :         result = proxy;
     867         [ +  + ]:       6990 :     if (result != NULL)
     868                 :          5 :         Py_INCREF(result);
     869                 :            :     else {
     870                 :            :         /* Note: new_weakref() can trigger cyclic GC, so the weakref
     871                 :            :            list on ob can be mutated.  This means that the ref and
     872                 :            :            proxy pointers we got back earlier may have been collected,
     873                 :            :            so we need to compute these values again before we use
     874                 :            :            them. */
     875                 :       6985 :         result = new_weakref(ob, callback);
     876         [ +  - ]:       6985 :         if (result != NULL) {
     877                 :            :             PyWeakReference *prev;
     878                 :            : 
     879         [ +  + ]:       6985 :             if (PyCallable_Check(ob)) {
     880                 :        134 :                 Py_SET_TYPE(result, &_PyWeakref_CallableProxyType);
     881                 :            :             }
     882                 :            :             else {
     883                 :       6851 :                 Py_SET_TYPE(result, &_PyWeakref_ProxyType);
     884                 :            :             }
     885                 :       6985 :             get_basic_refs(*list, &ref, &proxy);
     886         [ +  + ]:       6985 :             if (callback == NULL) {
     887         [ -  + ]:       6856 :                 if (proxy != NULL) {
     888                 :            :                     /* Someone else added a proxy without a callback
     889                 :            :                        during GC.  Return that one instead of this one
     890                 :            :                        to avoid violating the invariants of the list
     891                 :            :                        of weakrefs for ob. */
     892                 :          0 :                     Py_DECREF(result);
     893                 :          0 :                     result = proxy;
     894                 :          0 :                     Py_INCREF(result);
     895                 :          0 :                     goto skip_insert;
     896                 :            :                 }
     897                 :       6856 :                 prev = ref;
     898                 :            :             }
     899                 :            :             else
     900         [ +  + ]:        129 :                 prev = (proxy == NULL) ? ref : proxy;
     901                 :            : 
     902         [ +  + ]:       6985 :             if (prev == NULL)
     903                 :       6852 :                 insert_head(result, list);
     904                 :            :             else
     905                 :        133 :                 insert_after(result, prev);
     906                 :       6985 :         skip_insert:
     907                 :            :             ;
     908                 :            :         }
     909                 :            :     }
     910                 :       6990 :     return (PyObject *) result;
     911                 :            : }
     912                 :            : 
     913                 :            : 
     914                 :            : PyObject *
     915                 :      99298 : PyWeakref_GetObject(PyObject *ref)
     916                 :            : {
     917   [ +  -  -  +  :      99298 :     if (ref == NULL || !PyWeakref_Check(ref)) {
             -  -  -  - ]
     918                 :          0 :         PyErr_BadInternalCall();
     919                 :          0 :         return NULL;
     920                 :            :     }
     921                 :      99298 :     return PyWeakref_GET_OBJECT(ref);
     922                 :            : }
     923                 :            : 
     924                 :            : /* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
     925                 :            :  * handle_weakrefs().
     926                 :            :  */
     927                 :            : static void
     928                 :     673234 : handle_callback(PyWeakReference *ref, PyObject *callback)
     929                 :            : {
     930                 :     673234 :     PyObject *cbresult = PyObject_CallOneArg(callback, (PyObject *)ref);
     931                 :            : 
     932         [ +  + ]:     673234 :     if (cbresult == NULL)
     933                 :         14 :         PyErr_WriteUnraisable(callback);
     934                 :            :     else
     935                 :     673220 :         Py_DECREF(cbresult);
     936                 :     673234 : }
     937                 :            : 
     938                 :            : /* This function is called by the tp_dealloc handler to clear weak references.
     939                 :            :  *
     940                 :            :  * This iterates through the weak references for 'object' and calls callbacks
     941                 :            :  * for those references which have one.  It returns when all callbacks have
     942                 :            :  * been attempted.
     943                 :            :  */
     944                 :            : void
     945                 :   20042669 : PyObject_ClearWeakRefs(PyObject *object)
     946                 :            : {
     947                 :            :     PyWeakReference **list;
     948                 :            : 
     949         [ +  - ]:   20042669 :     if (object == NULL
     950         [ +  - ]:   20042669 :         || !_PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))
     951         [ -  + ]:   20042669 :         || Py_REFCNT(object) != 0)
     952                 :            :     {
     953                 :          0 :         PyErr_BadInternalCall();
     954                 :          0 :         return;
     955                 :            :     }
     956                 :   20042669 :     list = GET_WEAKREFS_LISTPTR(object);
     957                 :            :     /* Remove the callback-less basic and proxy references */
     958   [ +  +  +  + ]:   20042669 :     if (*list != NULL && (*list)->wr_callback == NULL) {
     959                 :     107238 :         clear_weakref(*list);
     960   [ +  +  +  + ]:     107238 :         if (*list != NULL && (*list)->wr_callback == NULL)
     961                 :          4 :             clear_weakref(*list);
     962                 :            :     }
     963         [ +  + ]:   20042669 :     if (*list != NULL) {
     964                 :     624852 :         PyWeakReference *current = *list;
     965                 :     624852 :         Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
     966                 :            :         PyObject *err_type, *err_value, *err_tb;
     967                 :            : 
     968                 :     624852 :         PyErr_Fetch(&err_type, &err_value, &err_tb);
     969         [ +  + ]:     624852 :         if (count == 1) {
     970                 :     576528 :             PyObject *callback = current->wr_callback;
     971                 :            : 
     972                 :     576528 :             current->wr_callback = NULL;
     973                 :     576528 :             clear_weakref(current);
     974         [ +  + ]:     576528 :             if (callback != NULL) {
     975         [ +  + ]:     576527 :                 if (Py_REFCNT((PyObject *)current) > 0) {
     976                 :     576526 :                     handle_callback(current, callback);
     977                 :            :                 }
     978                 :     576527 :                 Py_DECREF(callback);
     979                 :            :             }
     980                 :            :         }
     981                 :            :         else {
     982                 :            :             PyObject *tuple;
     983                 :      48324 :             Py_ssize_t i = 0;
     984                 :            : 
     985                 :      48324 :             tuple = PyTuple_New(count * 2);
     986         [ -  + ]:      48324 :             if (tuple == NULL) {
     987                 :          0 :                 _PyErr_ChainExceptions(err_type, err_value, err_tb);
     988                 :          0 :                 return;
     989                 :            :             }
     990                 :            : 
     991         [ +  + ]:     145034 :             for (i = 0; i < count; ++i) {
     992                 :      96710 :                 PyWeakReference *next = current->wr_next;
     993                 :            : 
     994         [ +  + ]:      96710 :                 if (Py_REFCNT((PyObject *)current) > 0) {
     995                 :      96708 :                     Py_INCREF(current);
     996                 :      96708 :                     PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
     997                 :      96708 :                     PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
     998                 :            :                 }
     999                 :            :                 else {
    1000                 :          2 :                     Py_DECREF(current->wr_callback);
    1001                 :            :                 }
    1002                 :      96710 :                 current->wr_callback = NULL;
    1003                 :      96710 :                 clear_weakref(current);
    1004                 :      96710 :                 current = next;
    1005                 :            :             }
    1006         [ +  + ]:     145034 :             for (i = 0; i < count; ++i) {
    1007                 :      96710 :                 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
    1008                 :            : 
    1009                 :            :                 /* The tuple may have slots left to NULL */
    1010         [ +  + ]:      96710 :                 if (callback != NULL) {
    1011                 :      96708 :                     PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
    1012                 :      96708 :                     handle_callback((PyWeakReference *)item, callback);
    1013                 :            :                 }
    1014                 :            :             }
    1015                 :      48324 :             Py_DECREF(tuple);
    1016                 :            :         }
    1017                 :            :         assert(!PyErr_Occurred());
    1018                 :     624852 :         PyErr_Restore(err_type, err_value, err_tb);
    1019                 :            :     }
    1020                 :            : }

Generated by: LCOV version 1.14