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