Python-2.7.3/Objects/weakrefobject.c

No issues found

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