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