static PyObject * weakref_getweakrefs(PyObject *self, PyObject *object) { PyObject *result = NULL; if (PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))) { PyWeakReference **list = GET_WEAKREFS_LISTPTR(object); Py_ssize_t count = _PyWeakref_GetWeakrefCount(*list); result = PyList_New(count); if (result != NULL) { PyWeakReference *current = *list; Py_ssize_t i; for (i = 0; i < count; ++i) { PyList_SET_ITEM(result, i, (PyObject *) current); Py_INCREF(current); current = current->wr_next; } } } else { result = PyList_New(0); } return result; }
/* This function is called by the tp_dealloc handler to clear weak references. * * This iterates through the weak references for 'object' and calls callbacks * for those references which have one. It returns when all callbacks have * been attempted. */ void PyObject_ClearWeakRefs(PyObject *object) { PyWeakReference **list; if (object == NULL || !PyType_SUPPORTS_WEAKREFS(object->ob_type) || object->ob_refcnt != 0) { PyErr_BadInternalCall(); return; } list = GET_WEAKREFS_LISTPTR(object); /* Remove the callback-less basic and proxy references */ if (*list != NULL && (*list)->wr_callback == NULL) { clear_weakref(*list); if (*list != NULL && (*list)->wr_callback == NULL) clear_weakref(*list); } if (*list != NULL) { PyWeakReference *current = *list; int count = _PyWeakref_GetWeakrefCount(current); int restore_error = PyErr_Occurred() ? 1 : 0; PyObject *err_type, *err_value, *err_tb; if (restore_error) PyErr_Fetch(&err_type, &err_value, &err_tb); if (count == 1) { PyObject *callback = current->wr_callback; current->wr_callback = NULL; clear_weakref(current); handle_callback(current, callback); Py_DECREF(callback); } else { PyObject *tuple = PyTuple_New(count * 2); int i = 0; for (i = 0; i < count; ++i) { PyWeakReference *next = current->wr_next; Py_INCREF(current); PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current); PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback); current->wr_callback = NULL; clear_weakref(current); current = next; } for (i = 0; i < count; ++i) { PyObject *current = PyTuple_GET_ITEM(tuple, i * 2); PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1); handle_callback((PyWeakReference *)current, callback); } Py_DECREF(tuple); } if (restore_error) PyErr_Restore(err_type, err_value, err_tb); } }
PyObject * PyWeakref_NewRef(PyObject *ob, PyObject *callback) { PyWeakReference *result = NULL; PyWeakReference **list; PyWeakReference *ref, *proxy; if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) { PyErr_Format(PyExc_TypeError, "cannot create weak reference to '%s' object", ob->ob_type->tp_name); return NULL; } list = GET_WEAKREFS_LISTPTR(ob); get_basic_refs(*list, &ref, &proxy); if (callback == Py_None) callback = NULL; if (callback == NULL) /* return existing weak reference if it exists */ result = ref; if (result != NULL) Py_INCREF(result); else { /* Note: new_weakref() can trigger cyclic GC, so the weakref list on ob can be mutated. This means that the ref and proxy pointers we got back earlier may have been collected, so we need to compute these values again before we use them. */ result = new_weakref(ob, callback); if (result != NULL) { get_basic_refs(*list, &ref, &proxy); if (callback == NULL) { if (ref == NULL) insert_head(result, list); else { /* Someone else added a ref without a callback during GC. Return that one instead of this one to avoid violating the invariants of the list of weakrefs for ob. */ Py_DECREF(result); Py_INCREF(ref); result = ref; } } else { PyWeakReference *prev; prev = (proxy == NULL) ? ref : proxy; if (prev == NULL) insert_head(result, list); else insert_after(result, prev); } } } return (PyObject *) result; }
__attribute__((always_inline)) bool isWeaklyReferenced(Box* b) { if (PyType_SUPPORTS_WEAKREFS(b->cls)) { PyWeakReference** list = (PyWeakReference**)PyObject_GET_WEAKREFS_LISTPTR(b); if (list && *list) { return true; } } return false; }
static Py_ssize_t _weakref_getweakrefcount_impl(PyObject *module, PyObject *object) /*[clinic end generated code: output=301806d59558ff3e input=cedb69711b6a2507]*/ { PyWeakReference **list; if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))) return 0; list = GET_WEAKREFS_LISTPTR(object); return _PyWeakref_GetWeakrefCount(*list); }
static PyObject * weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PyWeakReference *self = NULL; PyObject *ob, *callback = NULL; if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) { PyWeakReference *ref, *proxy; PyWeakReference **list; if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) { PyErr_Format(PyExc_TypeError, "cannot create weak reference to '%s' object", ob->ob_type->tp_name); return NULL; } if (callback == Py_None) callback = NULL; list = GET_WEAKREFS_LISTPTR(ob); get_basic_refs(*list, &ref, &proxy); if (callback == NULL && type == &_PyWeakref_RefType) { if (ref != NULL) { /* We can re-use an existing reference. */ Py_INCREF(ref); return (PyObject *)ref; } } /* We have to create a new reference. */ /* Note: the tp_alloc() can trigger cyclic GC, so the weakref list on ob can be mutated. This means that the ref and proxy pointers we got back earlier may have been collected, so we need to compute these values again before we use them. */ self = (PyWeakReference *) (type->tp_alloc(type, 0)); if (self != NULL) { init_weakref(self, ob, callback); if (callback == NULL && type == &_PyWeakref_RefType) { insert_head(self, list); } else { PyWeakReference *prev; get_basic_refs(*list, &ref, &proxy); prev = (proxy == NULL) ? ref : proxy; if (prev == NULL) insert_head(self, list); else insert_after(self, prev); } } } return (PyObject *)self; }
static PyObject * weakref_getweakrefcount(PyObject *self, PyObject *object) { PyObject *result = NULL; if (PyType_SUPPORTS_WEAKREFS(object->ob_type)) { PyWeakReference **list = GET_WEAKREFS_LISTPTR(object); result = PyInt_FromSsize_t(_PyWeakref_GetWeakrefCount(*list)); } else result = PyInt_FromLong(0); return result; }
PyObject * PyWeakref_NewProxy(PyObject *ob, PyObject *callback) { PyWeakReference *result = NULL; PyWeakReference **list; PyWeakReference *ref, *proxy; if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) { PyErr_Format(PyExc_TypeError, "cannot create weak reference to '%s' object", ob->ob_type->tp_name); return NULL; } list = GET_WEAKREFS_LISTPTR(ob); get_basic_refs(*list, &ref, &proxy); if (callback == NULL) /* attempt to return an existing weak reference if it exists */ result = proxy; if (result != NULL) Py_XINCREF(result); else { result = new_weakref(ob, callback); if (result != NULL) { PyWeakReference *prev; if (PyCallable_Check(ob)) result->ob_type = &_PyWeakref_CallableProxyType; else result->ob_type = &_PyWeakref_ProxyType; if (callback == NULL) prev = ref; else prev = (proxy == NULL) ? ref : proxy; if (prev == NULL) insert_head(result, list); else insert_after(result, prev); } } return (PyObject *) result; }
__attribute__((always_inline)) bool _doFree(GCAllocation* al, std::vector<Box*>* weakly_referenced) { #ifndef NVALGRIND VALGRIND_DISABLE_ERROR_REPORTING; #endif GCKind alloc_kind = al->kind_id; #ifndef NVALGRIND VALGRIND_ENABLE_ERROR_REPORTING; #endif if (alloc_kind == GCKind::PYTHON || alloc_kind == GCKind::CONSERVATIVE_PYTHON) { #ifndef NVALGRIND VALGRIND_DISABLE_ERROR_REPORTING; #endif Box* b = (Box*)al->user_data; #ifndef NVALGRIND VALGRIND_ENABLE_ERROR_REPORTING; #endif if (PyType_SUPPORTS_WEAKREFS(b->cls)) { PyWeakReference** list = (PyWeakReference**)PyObject_GET_WEAKREFS_LISTPTR(b); if (list && *list) { assert(weakly_referenced && "attempting to free a weakly referenced object manually"); weakly_referenced->push_back(b); return false; } } // XXX: we are currently ignoring destructors (tp_dealloc) for extension objects, since we have // historically done that (whoops) and there are too many to be worth changing for now as long // as we can get real destructor support soon. ASSERT(b->cls->tp_dealloc == NULL || alloc_kind == GCKind::CONSERVATIVE_PYTHON, "%s", getTypeName(b)); if (b->cls->simple_destructor) b->cls->simple_destructor(b); } return true; }
bool _doFree(GCAllocation* al, std::list<Box*, StlCompatAllocator<Box*>>* weakly_referenced) { if (VERBOSITY() >= 2) printf("Freeing %p\n", al->user_data); #ifndef NVALGRIND VALGRIND_DISABLE_ERROR_REPORTING; #endif GCKind alloc_kind = al->kind_id; #ifndef NVALGRIND VALGRIND_ENABLE_ERROR_REPORTING; #endif if (alloc_kind == GCKind::PYTHON) { #ifndef NVALGRIND VALGRIND_DISABLE_ERROR_REPORTING; #endif Box* b = (Box*)al->user_data; #ifndef NVALGRIND VALGRIND_ENABLE_ERROR_REPORTING; #endif if (PyType_SUPPORTS_WEAKREFS(b->cls)) { PyWeakReference** list = (PyWeakReference**)PyObject_GET_WEAKREFS_LISTPTR(b); if (list && *list) { assert(weakly_referenced && "attempting to free a weakly referenced object manually"); weakly_referenced->push_back(b); return false; } } ASSERT(b->cls->tp_dealloc == NULL, "%s", getTypeName(b)); if (b->cls->simple_destructor) b->cls->simple_destructor(b); } return true; }
/* Clear all weakrefs to unreachable objects, and if such a weakref has a * callback, invoke it if necessary. Note that it's possible for such * weakrefs to be outside the unreachable set -- indeed, those are precisely * the weakrefs whose callbacks must be invoked. See gc_weakref.txt for * overview & some details. Some weakrefs with callbacks may be reclaimed * directly by this routine; the number reclaimed is the return value. Other * weakrefs with callbacks may be moved into the `old` generation. Objects * moved into `old` have gc_refs set to GC_REACHABLE; the objects remaining in * unreachable are left at GC_TENTATIVELY_UNREACHABLE. When this returns, * no object in `unreachable` is weakly referenced anymore. */ static int handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old) { PyGC_Head *gc; PyObject *op; /* generally FROM_GC(gc) */ PyWeakReference *wr; /* generally a cast of op */ PyGC_Head wrcb_to_call; /* weakrefs with callbacks to call */ PyGC_Head *next; int num_freed = 0; gc_list_init(&wrcb_to_call); /* Clear all weakrefs to the objects in unreachable. If such a weakref * also has a callback, move it into `wrcb_to_call` if the callback * needs to be invoked. Note that we cannot invoke any callbacks until * all weakrefs to unreachable objects are cleared, lest the callback * resurrect an unreachable object via a still-active weakref. We * make another pass over wrcb_to_call, invoking callbacks, after this * pass completes. */ for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) { PyWeakReference **wrlist; op = FROM_GC(gc); assert(IS_TENTATIVELY_UNREACHABLE(op)); next = gc->gc.gc_next; if (! PyType_SUPPORTS_WEAKREFS(op->ob_type)) continue; /* It supports weakrefs. Does it have any? */ wrlist = (PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(op); /* `op` may have some weakrefs. March over the list, clear * all the weakrefs, and move the weakrefs with callbacks * that must be called into wrcb_to_call. */ for (wr = *wrlist; wr != NULL; wr = *wrlist) { PyGC_Head *wrasgc; /* AS_GC(wr) */ /* _PyWeakref_ClearRef clears the weakref but leaves * the callback pointer intact. Obscure: it also * changes *wrlist. */ assert(wr->wr_object == op); _PyWeakref_ClearRef(wr); assert(wr->wr_object == Py_None); if (wr->wr_callback == NULL) continue; /* no callback */ /* Headache time. `op` is going away, and is weakly referenced by * `wr`, which has a callback. Should the callback be invoked? If wr * is also trash, no: * * 1. There's no need to call it. The object and the weakref are * both going away, so it's legitimate to pretend the weakref is * going away first. The user has to ensure a weakref outlives its * referent if they want a guarantee that the wr callback will get * invoked. * * 2. It may be catastrophic to call it. If the callback is also in * cyclic trash (CT), then although the CT is unreachable from * outside the current generation, CT may be reachable from the * callback. Then the callback could resurrect insane objects. * * Since the callback is never needed and may be unsafe in this case, * wr is simply left in the unreachable set. Note that because we * already called _PyWeakref_ClearRef(wr), its callback will never * trigger. * * OTOH, if wr isn't part of CT, we should invoke the callback: the * weakref outlived the trash. Note that since wr isn't CT in this * case, its callback can't be CT either -- wr acted as an external * root to this generation, and therefore its callback did too. So * nothing in CT is reachable from the callback either, so it's hard * to imagine how calling it later could create a problem for us. wr * is moved to wrcb_to_call in this case. */ if (IS_TENTATIVELY_UNREACHABLE(wr)) continue; assert(IS_REACHABLE(wr)); /* Create a new reference so that wr can't go away * before we can process it again. */ Py_INCREF(wr); /* Move wr to wrcb_to_call, for the next pass. */ wrasgc = AS_GC(wr); assert(wrasgc != next); /* wrasgc is reachable, but next isn't, so they can't be the same */ gc_list_move(wrasgc, &wrcb_to_call); } } /* Invoke the callbacks we decided to honor. It's safe to invoke them * because they can't reference unreachable objects. */ while (! gc_list_is_empty(&wrcb_to_call)) { PyObject *temp; PyObject *callback; gc = wrcb_to_call.gc.gc_next; op = FROM_GC(gc); assert(IS_REACHABLE(op)); assert(PyWeakref_Check(op)); wr = (PyWeakReference *)op; callback = wr->wr_callback; assert(callback != NULL); /* copy-paste of weakrefobject.c's handle_callback() */ temp = PyObject_CallFunction(callback, "O", wr); if (temp == NULL) PyErr_WriteUnraisable(callback); else Py_DECREF(temp); /* Give up the reference we created in the first pass. When * op's refcount hits 0 (which it may or may not do right now), * op's tp_dealloc will decref op->wr_callback too. Note * that the refcount probably will hit 0 now, and because this * weakref was reachable to begin with, gc didn't already * add it to its count of freed objects. Example: a reachable * weak value dict maps some key to this reachable weakref. * The callback removes this key->weakref mapping from the * dict, leaving no other references to the weakref (excepting * ours). */ Py_DECREF(op); if (wrcb_to_call.gc.gc_next == gc) { /* object is still alive -- move it */ gc_list_move(gc, old); } else ++num_freed; } return num_freed; }
/* This function is called by the tp_dealloc handler to clear weak references. * * This iterates through the weak references for 'object' and calls callbacks * for those references which have one. It returns when all callbacks have * been attempted. */ void PyObject_ClearWeakRefs(PyObject *object) { PyWeakReference **list; if (object == NULL || !PyType_SUPPORTS_WEAKREFS(Py_TYPE(object)) //|| object->ob_refcnt != 0 ) { PyErr_BadInternalCall(); return; } list = GET_WEAKREFS_LISTPTR(object); /* Remove the callback-less basic and proxy references */ if (*list != NULL && (*list)->wr_callback == NULL) { clear_weakref(*list); if (*list != NULL && (*list)->wr_callback == NULL) clear_weakref(*list); } if (*list != NULL) { PyWeakReference *current = *list; Py_ssize_t count = _PyWeakref_GetWeakrefCount(current); int restore_error = PyErr_Occurred() ? 1 : 0; PyObject *err_type, *err_value, *err_tb; if (restore_error) PyErr_Fetch(&err_type, &err_value, &err_tb); if (count == 1) { PyObject *callback = current->wr_callback; current->wr_callback = NULL; clear_weakref(current); if (callback != NULL) { // Pyston change: // current is a stack reference to a GC allocated object. If it wasn't null when we fetched it from *list, it won't // be collected, and we can trust that it's still valid here. if (true /*current->ob_refcnt > 0*/) handle_callback(current, callback); Py_DECREF(callback); } } else { PyObject *tuple; Py_ssize_t i = 0; tuple = PyTuple_New(count * 2); if (tuple == NULL) { if (restore_error) PyErr_Fetch(&err_type, &err_value, &err_tb); return; } for (i = 0; i < count; ++i) { PyWeakReference *next = current->wr_next; // Pyston change: // current is a stack reference to a GC allocated object. If it wasn't null when we fetched it from *list, it won't // be collected, and we can trust that it's still valid here. if (true /*current->ob_refcnt > 0*/) { Py_INCREF(current); PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current); PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback); } else { Py_DECREF(current->wr_callback); } current->wr_callback = NULL; clear_weakref(current); current = next; } for (i = 0; i < count; ++i) { PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1); /* The tuple may have slots left to NULL */ if (callback != NULL) { PyObject *item = PyTuple_GET_ITEM(tuple, i * 2); handle_callback((PyWeakReference *)item, callback); } } Py_DECREF(tuple); } if (restore_error) PyErr_Restore(err_type, err_value, err_tb); } }
/* This function is called by the tp_dealloc handler to clear weak references. * * This iterates through the weak references for 'object' and calls callbacks * for those references which have one. It returns when all callbacks have * been attempted. */ void PyObject_ClearWeakRefs(PyObject *object) { PyWeakReference **list; if (object == NULL || !PyType_SUPPORTS_WEAKREFS(Py_TYPE(object)) || object->ob_refcnt != 0) { PyErr_BadInternalCall(); return; } list = GET_WEAKREFS_LISTPTR(object); /* Remove the callback-less basic and proxy references */ if (*list != NULL && (*list)->wr_callback == NULL) { clear_weakref(*list); if (*list != NULL && (*list)->wr_callback == NULL) clear_weakref(*list); } if (*list != NULL) { PyWeakReference *current = *list; Py_ssize_t count = _PyWeakref_GetWeakrefCount(current); PyObject *err_type, *err_value, *err_tb; PyErr_Fetch(&err_type, &err_value, &err_tb); if (count == 1) { PyObject *callback = current->wr_callback; current->wr_callback = NULL; clear_weakref(current); if (callback != NULL) { if (current->ob_refcnt > 0) handle_callback(current, callback); Py_DECREF(callback); } } else { PyObject *tuple; Py_ssize_t i = 0; tuple = PyTuple_New(count * 2); if (tuple == NULL) { _PyErr_ReplaceException(err_type, err_value, err_tb); return; } for (i = 0; i < count; ++i) { PyWeakReference *next = current->wr_next; if (current->ob_refcnt > 0) { Py_INCREF(current); PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current); PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback); } else { Py_DECREF(current->wr_callback); } current->wr_callback = NULL; clear_weakref(current); current = next; } for (i = 0; i < count; ++i) { PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1); /* The tuple may have slots left to NULL */ if (callback != NULL) { PyObject *item = PyTuple_GET_ITEM(tuple, i * 2); handle_callback((PyWeakReference *)item, callback); } } Py_DECREF(tuple); } assert(!PyErr_Occurred()); PyErr_Restore(err_type, err_value, err_tb); } }
PyObject * PyWeakref_NewProxy(PyObject *ob, PyObject *callback) { PyWeakReference *result = NULL; PyWeakReference **list; PyWeakReference *ref, *proxy; if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) { PyErr_Format(PyExc_TypeError, "cannot create weak reference to '%s' object", Py_TYPE(ob)->tp_name); return NULL; } list = GET_WEAKREFS_LISTPTR(ob); get_basic_refs(*list, &ref, &proxy); if (callback == Py_None) callback = NULL; if (callback == NULL) /* attempt to return an existing weak reference if it exists */ result = proxy; if (result != NULL) Py_INCREF(result); else { /* Note: new_weakref() can trigger cyclic GC, so the weakref list on ob can be mutated. This means that the ref and proxy pointers we got back earlier may have been collected, so we need to compute these values again before we use them. */ if (PyCallable_Check(ob)) result = new_weakref(ob, callback, &_PyWeakref_CallableProxyType); else result = new_weakref(ob, callback, &_PyWeakref_ProxyType); if (result != NULL) { PyWeakReference *prev; //JyNI-note: These lines mess up JyNI-initialization. //In new_weakref _PyObject_GC_New(&_PyWeakref_RefType) is //called, which caches the tme for _PyWeakref_RefType in //jy->jy. Now the type is altered afterwards leading to //a wrong tme. Shall we fix it here, or implement a //lookup in unconsistent case? //(Better fix it here) // if (PyCallable_Check(ob)) // Py_TYPE(result) = &_PyWeakref_CallableProxyType; // else // Py_TYPE(result) = &_PyWeakref_ProxyType; get_basic_refs(*list, &ref, &proxy); if (callback == NULL) { if (proxy != NULL) { /* Someone else added a proxy without a callback during GC. Return that one instead of this one to avoid violating the invariants of the list of weakrefs for ob. */ Py_DECREF(result); Py_INCREF(result = proxy); goto skip_insert; } prev = ref; } else prev = (proxy == NULL) ? ref : proxy; if (prev == NULL) insert_head(result, list); else insert_after(result, prev); skip_insert: ; } } return (PyObject *) result; }