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