1 #include "Python.h"
2 #include "pycore_object.h" // _PyObject_GET_WEAKREFS_LISTPTR()
3 #include "structmember.h" // PyMemberDef
4
5
6 #define GET_WEAKREFS_LISTPTR(o) \
7 ((PyWeakReference **) _PyObject_GET_WEAKREFS_LISTPTR(o))
8
9
10 Py_ssize_t
11 _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
22 static PyObject *weakref_vectorcall(PyWeakReference *self, PyObject *const *args, size_t nargsf, PyObject *kwnames);
23
24 static void
25 init_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
35 static PyWeakReference *
36 new_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 */
54 static void
55 clear_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 */
92 void
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
106 static void
107 weakref_dealloc(PyObject *self)
108 {
109 PyObject_GC_UnTrack(self);
110 clear_weakref((PyWeakReference *) self);
111 Py_TYPE(self)->tp_free(self);
112 }
113
114
115 static int
116 gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
117 {
118 Py_VISIT(self->wr_callback);
119 return 0;
120 }
121
122
123 static int
124 gc_clear(PyWeakReference *self)
125 {
126 clear_weakref(self);
127 return 0;
128 }
129
130
131 static PyObject *
132 weakref_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
145 static Py_hash_t
146 weakref_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
162 static PyObject *
163 weakref_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
198 static PyObject *
199 weakref_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 */
231 static void
232 get_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. */
256 static void
257 insert_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 */
269 static void
270 insert_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
281 static int
282 parse_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
288 static PyObject *
289 weakref___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 return Py_NewRef(ref);
312 }
313 }
314 /* We have to create a new reference. */
315 /* Note: the tp_alloc() can trigger cyclic GC, so the weakref
316 list on ob can be mutated. This means that the ref and
317 proxy pointers we got back earlier may have been collected,
318 so we need to compute these values again before we use
319 them. */
320 self = (PyWeakReference *) (type->tp_alloc(type, 0));
321 if (self != NULL) {
322 init_weakref(self, ob, callback);
323 if (callback == NULL && type == &_PyWeakref_RefType) {
324 insert_head(self, list);
325 }
326 else {
327 PyWeakReference *prev;
328
329 get_basic_refs(*list, &ref, &proxy);
330 prev = (proxy == NULL) ? ref : proxy;
331 if (prev == NULL)
332 insert_head(self, list);
333 else
334 insert_after(self, prev);
335 }
336 }
337 }
338 return (PyObject *)self;
339 }
340
341 static int
342 weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)
343 {
344 PyObject *tmp;
345
346 if (!_PyArg_NoKeywords("ref", kwargs))
347 return -1;
348
349 if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp))
350 return 0;
351 else
352 return -1;
353 }
354
355
356 static PyMemberDef weakref_members[] = {
357 {"__callback__", T_OBJECT, offsetof(PyWeakReference, wr_callback), READONLY},
358 {NULL} /* Sentinel */
359 };
360
361 static PyMethodDef weakref_methods[] = {
362 {"__class_getitem__", Py_GenericAlias,
363 METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
364 {NULL} /* Sentinel */
365 };
366
367 PyTypeObject
368 _PyWeakref_RefType = {
369 PyVarObject_HEAD_INIT(&PyType_Type, 0)
370 .tp_name = "weakref.ReferenceType",
371 .tp_basicsize = sizeof(PyWeakReference),
372 .tp_dealloc = weakref_dealloc,
373 .tp_vectorcall_offset = offsetof(PyWeakReference, vectorcall),
374 .tp_call = PyVectorcall_Call,
375 .tp_repr = (reprfunc)weakref_repr,
376 .tp_hash = (hashfunc)weakref_hash,
377 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
378 Py_TPFLAGS_HAVE_VECTORCALL | Py_TPFLAGS_BASETYPE,
379 .tp_traverse = (traverseproc)gc_traverse,
380 .tp_clear = (inquiry)gc_clear,
381 .tp_richcompare = (richcmpfunc)weakref_richcompare,
382 .tp_methods = weakref_methods,
383 .tp_members = weakref_members,
384 .tp_init = weakref___init__,
385 .tp_alloc = PyType_GenericAlloc,
386 .tp_new = weakref___new__,
387 .tp_free = PyObject_GC_Del,
388 };
389
390
391 static int
392 proxy_checkref(PyWeakReference *proxy)
393 {
394 if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
395 PyErr_SetString(PyExc_ReferenceError,
396 "weakly-referenced object no longer exists");
397 return 0;
398 }
399 return 1;
400 }
401
402
403 /* If a parameter is a proxy, check that it is still "live" and wrap it,
404 * replacing the original value with the raw object. Raises ReferenceError
405 * if the param is a dead proxy.
406 */
407 #define UNWRAP(o) \
408 if (PyWeakref_CheckProxy(o)) { \
409 if (!proxy_checkref((PyWeakReference *)o)) \
410 return NULL; \
411 o = PyWeakref_GET_OBJECT(o); \
412 }
413
414 #define WRAP_UNARY(method, generic) \
415 static PyObject * \
416 method(PyObject *proxy) { \
417 UNWRAP(proxy); \
418 Py_INCREF(proxy); \
419 PyObject* res = generic(proxy); \
420 Py_DECREF(proxy); \
421 return res; \
422 }
423
424 #define WRAP_BINARY(method, generic) \
425 static PyObject * \
426 method(PyObject *x, PyObject *y) { \
427 UNWRAP(x); \
428 UNWRAP(y); \
429 Py_INCREF(x); \
430 Py_INCREF(y); \
431 PyObject* res = generic(x, y); \
432 Py_DECREF(x); \
433 Py_DECREF(y); \
434 return res; \
435 }
436
437 /* Note that the third arg needs to be checked for NULL since the tp_call
438 * slot can receive NULL for this arg.
439 */
440 #define WRAP_TERNARY(method, generic) \
441 static PyObject * \
442 method(PyObject *proxy, PyObject *v, PyObject *w) { \
443 UNWRAP(proxy); \
444 UNWRAP(v); \
445 if (w != NULL) \
446 UNWRAP(w); \
447 Py_INCREF(proxy); \
448 Py_INCREF(v); \
449 Py_XINCREF(w); \
450 PyObject* res = generic(proxy, v, w); \
451 Py_DECREF(proxy); \
452 Py_DECREF(v); \
453 Py_XDECREF(w); \
454 return res; \
455 }
456
457 #define WRAP_METHOD(method, SPECIAL) \
458 static PyObject * \
459 method(PyObject *proxy, PyObject *Py_UNUSED(ignored)) { \
460 UNWRAP(proxy); \
461 Py_INCREF(proxy); \
462 PyObject* res = PyObject_CallMethodNoArgs(proxy, &_Py_ID(SPECIAL)); \
463 Py_DECREF(proxy); \
464 return res; \
465 }
466
467
468 /* direct slots */
469
470 WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
471 WRAP_UNARY(proxy_str, PyObject_Str)
472 WRAP_TERNARY(proxy_call, PyObject_Call)
473
474 static PyObject *
475 proxy_repr(PyWeakReference *proxy)
476 {
477 return PyUnicode_FromFormat(
478 "<weakproxy at %p to %s at %p>",
479 proxy,
480 Py_TYPE(PyWeakref_GET_OBJECT(proxy))->tp_name,
481 PyWeakref_GET_OBJECT(proxy));
482 }
483
484
485 static int
486 proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
487 {
488 if (!proxy_checkref(proxy))
489 return -1;
490 PyObject *obj = PyWeakref_GET_OBJECT(proxy);
491 Py_INCREF(obj);
492 int res = PyObject_SetAttr(obj, name, value);
493 Py_DECREF(obj);
494 return res;
495 }
496
497 static PyObject *
498 proxy_richcompare(PyObject *proxy, PyObject *v, int op)
499 {
500 UNWRAP(proxy);
501 UNWRAP(v);
502 return PyObject_RichCompare(proxy, v, op);
503 }
504
505 /* number slots */
506 WRAP_BINARY(proxy_add, PyNumber_Add)
507 WRAP_BINARY(proxy_sub, PyNumber_Subtract)
508 WRAP_BINARY(proxy_mul, PyNumber_Multiply)
509 WRAP_BINARY(proxy_floor_div, PyNumber_FloorDivide)
510 WRAP_BINARY(proxy_true_div, PyNumber_TrueDivide)
511 WRAP_BINARY(proxy_mod, PyNumber_Remainder)
512 WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
513 WRAP_TERNARY(proxy_pow, PyNumber_Power)
514 WRAP_UNARY(proxy_neg, PyNumber_Negative)
515 WRAP_UNARY(proxy_pos, PyNumber_Positive)
516 WRAP_UNARY(proxy_abs, PyNumber_Absolute)
517 WRAP_UNARY(proxy_invert, PyNumber_Invert)
518 WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
519 WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
520 WRAP_BINARY(proxy_and, PyNumber_And)
521 WRAP_BINARY(proxy_xor, PyNumber_Xor)
522 WRAP_BINARY(proxy_or, PyNumber_Or)
523 WRAP_UNARY(proxy_int, PyNumber_Long)
524 WRAP_UNARY(proxy_float, PyNumber_Float)
525 WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
526 WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
527 WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
528 WRAP_BINARY(proxy_ifloor_div, PyNumber_InPlaceFloorDivide)
529 WRAP_BINARY(proxy_itrue_div, PyNumber_InPlaceTrueDivide)
530 WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
531 WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
532 WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
533 WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
534 WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
535 WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
536 WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
537 WRAP_UNARY(proxy_index, PyNumber_Index)
538 WRAP_BINARY(proxy_matmul, PyNumber_MatrixMultiply)
539 WRAP_BINARY(proxy_imatmul, PyNumber_InPlaceMatrixMultiply)
540
541 static int
542 proxy_bool(PyWeakReference *proxy)
543 {
544 PyObject *o = PyWeakref_GET_OBJECT(proxy);
545 if (!proxy_checkref(proxy)) {
546 return -1;
547 }
548 Py_INCREF(o);
549 int res = PyObject_IsTrue(o);
550 Py_DECREF(o);
551 return res;
552 }
553
554 static void
555 proxy_dealloc(PyWeakReference *self)
556 {
557 PyObject_GC_UnTrack(self);
558 if (self->wr_callback != NULL)
559 PyObject_GC_UnTrack((PyObject *)self);
560 clear_weakref(self);
561 PyObject_GC_Del(self);
562 }
563
564 /* sequence slots */
565
566 static int
567 proxy_contains(PyWeakReference *proxy, PyObject *value)
568 {
569 if (!proxy_checkref(proxy))
570 return -1;
571
572 PyObject *obj = PyWeakref_GET_OBJECT(proxy);
573 Py_INCREF(obj);
574 int res = PySequence_Contains(obj, value);
575 Py_DECREF(obj);
576 return res;
577 }
578
579 /* mapping slots */
580
581 static Py_ssize_t
582 proxy_length(PyWeakReference *proxy)
583 {
584 if (!proxy_checkref(proxy))
585 return -1;
586
587 PyObject *obj = PyWeakref_GET_OBJECT(proxy);
588 Py_INCREF(obj);
589 Py_ssize_t res = PyObject_Length(obj);
590 Py_DECREF(obj);
591 return res;
592 }
593
594 WRAP_BINARY(proxy_getitem, PyObject_GetItem)
595
596 static int
597 proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
598 {
599 if (!proxy_checkref(proxy))
600 return -1;
601
602 PyObject *obj = PyWeakref_GET_OBJECT(proxy);
603 Py_INCREF(obj);
604 int res;
605 if (value == NULL) {
606 res = PyObject_DelItem(obj, key);
607 } else {
608 res = PyObject_SetItem(obj, key, value);
609 }
610 Py_DECREF(obj);
611 return res;
612 }
613
614 /* iterator slots */
615
616 static PyObject *
617 proxy_iter(PyWeakReference *proxy)
618 {
619 if (!proxy_checkref(proxy))
620 return NULL;
621 PyObject *obj = PyWeakref_GET_OBJECT(proxy);
622 Py_INCREF(obj);
623 PyObject* res = PyObject_GetIter(obj);
624 Py_DECREF(obj);
625 return res;
626 }
627
628 static PyObject *
629 proxy_iternext(PyWeakReference *proxy)
630 {
631 if (!proxy_checkref(proxy))
632 return NULL;
633
634 PyObject *obj = PyWeakref_GET_OBJECT(proxy);
635 if (!PyIter_Check(obj)) {
636 PyErr_Format(PyExc_TypeError,
637 "Weakref proxy referenced a non-iterator '%.200s' object",
638 Py_TYPE(obj)->tp_name);
639 return NULL;
640 }
641 Py_INCREF(obj);
642 PyObject* res = PyIter_Next(obj);
643 Py_DECREF(obj);
644 return res;
645 }
646
647
648 WRAP_METHOD(proxy_bytes, __bytes__)
649 WRAP_METHOD(proxy_reversed, __reversed__)
650
651
652 static PyMethodDef proxy_methods[] = {
653 {"__bytes__", proxy_bytes, METH_NOARGS},
654 {"__reversed__", proxy_reversed, METH_NOARGS},
655 {NULL, NULL}
656 };
657
658
659 static PyNumberMethods proxy_as_number = {
660 proxy_add, /*nb_add*/
661 proxy_sub, /*nb_subtract*/
662 proxy_mul, /*nb_multiply*/
663 proxy_mod, /*nb_remainder*/
664 proxy_divmod, /*nb_divmod*/
665 proxy_pow, /*nb_power*/
666 proxy_neg, /*nb_negative*/
667 proxy_pos, /*nb_positive*/
668 proxy_abs, /*nb_absolute*/
669 (inquiry)proxy_bool, /*nb_bool*/
670 proxy_invert, /*nb_invert*/
671 proxy_lshift, /*nb_lshift*/
672 proxy_rshift, /*nb_rshift*/
673 proxy_and, /*nb_and*/
674 proxy_xor, /*nb_xor*/
675 proxy_or, /*nb_or*/
676 proxy_int, /*nb_int*/
677 0, /*nb_reserved*/
678 proxy_float, /*nb_float*/
679 proxy_iadd, /*nb_inplace_add*/
680 proxy_isub, /*nb_inplace_subtract*/
681 proxy_imul, /*nb_inplace_multiply*/
682 proxy_imod, /*nb_inplace_remainder*/
683 proxy_ipow, /*nb_inplace_power*/
684 proxy_ilshift, /*nb_inplace_lshift*/
685 proxy_irshift, /*nb_inplace_rshift*/
686 proxy_iand, /*nb_inplace_and*/
687 proxy_ixor, /*nb_inplace_xor*/
688 proxy_ior, /*nb_inplace_or*/
689 proxy_floor_div, /*nb_floor_divide*/
690 proxy_true_div, /*nb_true_divide*/
691 proxy_ifloor_div, /*nb_inplace_floor_divide*/
692 proxy_itrue_div, /*nb_inplace_true_divide*/
693 proxy_index, /*nb_index*/
694 proxy_matmul, /*nb_matrix_multiply*/
695 proxy_imatmul, /*nb_inplace_matrix_multiply*/
696 };
697
698 static PySequenceMethods proxy_as_sequence = {
699 (lenfunc)proxy_length, /*sq_length*/
700 0, /*sq_concat*/
701 0, /*sq_repeat*/
702 0, /*sq_item*/
703 0, /*sq_slice*/
704 0, /*sq_ass_item*/
705 0, /*sq_ass_slice*/
706 (objobjproc)proxy_contains, /* sq_contains */
707 };
708
709 static PyMappingMethods proxy_as_mapping = {
710 (lenfunc)proxy_length, /*mp_length*/
711 proxy_getitem, /*mp_subscript*/
712 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
713 };
714
715
716 PyTypeObject
717 _PyWeakref_ProxyType = {
718 PyVarObject_HEAD_INIT(&PyType_Type, 0)
719 "weakref.ProxyType",
720 sizeof(PyWeakReference),
721 0,
722 /* methods */
723 (destructor)proxy_dealloc, /* tp_dealloc */
724 0, /* tp_vectorcall_offset */
725 0, /* tp_getattr */
726 0, /* tp_setattr */
727 0, /* tp_as_async */
728 (reprfunc)proxy_repr, /* tp_repr */
729 &proxy_as_number, /* tp_as_number */
730 &proxy_as_sequence, /* tp_as_sequence */
731 &proxy_as_mapping, /* tp_as_mapping */
732 // Notice that tp_hash is intentionally omitted as proxies are "mutable" (when the reference dies).
733 0, /* tp_hash */
734 0, /* tp_call */
735 proxy_str, /* tp_str */
736 proxy_getattr, /* tp_getattro */
737 (setattrofunc)proxy_setattr, /* tp_setattro */
738 0, /* tp_as_buffer */
739 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
740 0, /* tp_doc */
741 (traverseproc)gc_traverse, /* tp_traverse */
742 (inquiry)gc_clear, /* tp_clear */
743 proxy_richcompare, /* tp_richcompare */
744 0, /* tp_weaklistoffset */
745 (getiterfunc)proxy_iter, /* tp_iter */
746 (iternextfunc)proxy_iternext, /* tp_iternext */
747 proxy_methods, /* tp_methods */
748 };
749
750
751 PyTypeObject
752 _PyWeakref_CallableProxyType = {
753 PyVarObject_HEAD_INIT(&PyType_Type, 0)
754 "weakref.CallableProxyType",
755 sizeof(PyWeakReference),
756 0,
757 /* methods */
758 (destructor)proxy_dealloc, /* tp_dealloc */
759 0, /* tp_vectorcall_offset */
760 0, /* tp_getattr */
761 0, /* tp_setattr */
762 0, /* tp_as_async */
763 (unaryfunc)proxy_repr, /* tp_repr */
764 &proxy_as_number, /* tp_as_number */
765 &proxy_as_sequence, /* tp_as_sequence */
766 &proxy_as_mapping, /* tp_as_mapping */
767 0, /* tp_hash */
768 proxy_call, /* tp_call */
769 proxy_str, /* tp_str */
770 proxy_getattr, /* tp_getattro */
771 (setattrofunc)proxy_setattr, /* tp_setattro */
772 0, /* tp_as_buffer */
773 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
774 0, /* tp_doc */
775 (traverseproc)gc_traverse, /* tp_traverse */
776 (inquiry)gc_clear, /* tp_clear */
777 proxy_richcompare, /* tp_richcompare */
778 0, /* tp_weaklistoffset */
779 (getiterfunc)proxy_iter, /* tp_iter */
780 (iternextfunc)proxy_iternext, /* tp_iternext */
781 };
782
783
784
785 PyObject *
786 PyWeakref_NewRef(PyObject *ob, PyObject *callback)
787 {
788 PyWeakReference *result = NULL;
789 PyWeakReference **list;
790 PyWeakReference *ref, *proxy;
791
792 if (!_PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
793 PyErr_Format(PyExc_TypeError,
794 "cannot create weak reference to '%s' object",
795 Py_TYPE(ob)->tp_name);
796 return NULL;
797 }
798 list = GET_WEAKREFS_LISTPTR(ob);
799 get_basic_refs(*list, &ref, &proxy);
800 if (callback == Py_None)
801 callback = NULL;
802 if (callback == NULL)
803 /* return existing weak reference if it exists */
804 result = ref;
805 if (result != NULL)
806 Py_INCREF(result);
807 else {
808 /* Note: new_weakref() can trigger cyclic GC, so the weakref
809 list on ob can be mutated. This means that the ref and
810 proxy pointers we got back earlier may have been collected,
811 so we need to compute these values again before we use
812 them. */
813 result = new_weakref(ob, callback);
814 if (result != NULL) {
815 get_basic_refs(*list, &ref, &proxy);
816 if (callback == NULL) {
817 if (ref == NULL)
818 insert_head(result, list);
819 else {
820 /* Someone else added a ref without a callback
821 during GC. Return that one instead of this one
822 to avoid violating the invariants of the list
823 of weakrefs for ob. */
824 Py_SETREF(result, (PyWeakReference*)Py_NewRef(ref));
825 }
826 }
827 else {
828 PyWeakReference *prev;
829
830 prev = (proxy == NULL) ? ref : proxy;
831 if (prev == NULL)
832 insert_head(result, list);
833 else
834 insert_after(result, prev);
835 }
836 }
837 }
838 return (PyObject *) result;
839 }
840
841
842 PyObject *
843 PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
844 {
845 PyWeakReference *result = NULL;
846 PyWeakReference **list;
847 PyWeakReference *ref, *proxy;
848
849 if (!_PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
850 PyErr_Format(PyExc_TypeError,
851 "cannot create weak reference to '%s' object",
852 Py_TYPE(ob)->tp_name);
853 return NULL;
854 }
855 list = GET_WEAKREFS_LISTPTR(ob);
856 get_basic_refs(*list, &ref, &proxy);
857 if (callback == Py_None)
858 callback = NULL;
859 if (callback == NULL)
860 /* attempt to return an existing weak reference if it exists */
861 result = proxy;
862 if (result != NULL)
863 Py_INCREF(result);
864 else {
865 /* Note: new_weakref() can trigger cyclic GC, so the weakref
866 list on ob can be mutated. This means that the ref and
867 proxy pointers we got back earlier may have been collected,
868 so we need to compute these values again before we use
869 them. */
870 result = new_weakref(ob, callback);
871 if (result != NULL) {
872 PyWeakReference *prev;
873
874 if (PyCallable_Check(ob)) {
875 Py_SET_TYPE(result, &_PyWeakref_CallableProxyType);
876 }
877 else {
878 Py_SET_TYPE(result, &_PyWeakref_ProxyType);
879 }
880 get_basic_refs(*list, &ref, &proxy);
881 if (callback == NULL) {
882 if (proxy != NULL) {
883 /* Someone else added a proxy without a callback
884 during GC. Return that one instead of this one
885 to avoid violating the invariants of the list
886 of weakrefs for ob. */
887 Py_SETREF(result, (PyWeakReference*)Py_NewRef(proxy));
888 goto skip_insert;
889 }
890 prev = ref;
891 }
892 else
893 prev = (proxy == NULL) ? ref : proxy;
894
895 if (prev == NULL)
896 insert_head(result, list);
897 else
898 insert_after(result, prev);
899 skip_insert:
900 ;
901 }
902 }
903 return (PyObject *) result;
904 }
905
906
907 PyObject *
908 PyWeakref_GetObject(PyObject *ref)
909 {
910 if (ref == NULL || !PyWeakref_Check(ref)) {
911 PyErr_BadInternalCall();
912 return NULL;
913 }
914 return PyWeakref_GET_OBJECT(ref);
915 }
916
917 /* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
918 * handle_weakrefs().
919 */
920 static void
921 handle_callback(PyWeakReference *ref, PyObject *callback)
922 {
923 PyObject *cbresult = PyObject_CallOneArg(callback, (PyObject *)ref);
924
925 if (cbresult == NULL)
926 PyErr_WriteUnraisable(callback);
927 else
928 Py_DECREF(cbresult);
929 }
930
931 /* This function is called by the tp_dealloc handler to clear weak references.
932 *
933 * This iterates through the weak references for 'object' and calls callbacks
934 * for those references which have one. It returns when all callbacks have
935 * been attempted.
936 */
937 void
938 PyObject_ClearWeakRefs(PyObject *object)
939 {
940 PyWeakReference **list;
941
942 if (object == NULL
943 || !_PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))
944 || Py_REFCNT(object) != 0)
945 {
946 PyErr_BadInternalCall();
947 return;
948 }
949 list = GET_WEAKREFS_LISTPTR(object);
950 /* Remove the callback-less basic and proxy references */
951 if (*list != NULL && (*list)->wr_callback == NULL) {
952 clear_weakref(*list);
953 if (*list != NULL && (*list)->wr_callback == NULL)
954 clear_weakref(*list);
955 }
956 if (*list != NULL) {
957 PyWeakReference *current = *list;
958 Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
959 PyObject *exc = PyErr_GetRaisedException();
960
961 if (count == 1) {
962 PyObject *callback = current->wr_callback;
963
964 current->wr_callback = NULL;
965 clear_weakref(current);
966 if (callback != NULL) {
967 if (Py_REFCNT((PyObject *)current) > 0) {
968 handle_callback(current, callback);
969 }
970 Py_DECREF(callback);
971 }
972 }
973 else {
974 PyObject *tuple;
975 Py_ssize_t i = 0;
976
977 tuple = PyTuple_New(count * 2);
978 if (tuple == NULL) {
979 _PyErr_ChainExceptions1(exc);
980 return;
981 }
982
983 for (i = 0; i < count; ++i) {
984 PyWeakReference *next = current->wr_next;
985
986 if (Py_REFCNT((PyObject *)current) > 0) {
987 PyTuple_SET_ITEM(tuple, i * 2, Py_NewRef(current));
988 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
989 }
990 else {
991 Py_DECREF(current->wr_callback);
992 }
993 current->wr_callback = NULL;
994 clear_weakref(current);
995 current = next;
996 }
997 for (i = 0; i < count; ++i) {
998 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
999
1000 /* The tuple may have slots left to NULL */
1001 if (callback != NULL) {
1002 PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
1003 handle_callback((PyWeakReference *)item, callback);
1004 }
1005 }
1006 Py_DECREF(tuple);
1007 }
1008 assert(!PyErr_Occurred());
1009 PyErr_SetRaisedException(exc);
1010 }
1011 }
1012
1013 /* This function is called by _PyStaticType_Dealloc() to clear weak references.
1014 *
1015 * This is called at the end of runtime finalization, so we can just
1016 * wipe out the type's weaklist. We don't bother with callbacks
1017 * or anything else.
1018 */
1019 void
1020 _PyStaticType_ClearWeakRefs(PyInterpreterState *interp, PyTypeObject *type)
1021 {
1022 static_builtin_state *state = _PyStaticType_GetState(interp, type);
1023 PyObject **list = _PyStaticType_GET_WEAKREFS_LISTPTR(state);
1024 while (*list != NULL) {
1025 /* Note that clear_weakref() pops the first ref off the type's
1026 weaklist before clearing its wr_object and wr_callback.
1027 That is how we're able to loop over the list. */
1028 clear_weakref((PyWeakReference *)*list);
1029 }
1030 }