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