diff --git a/src/heapy/hv.c b/src/heapy/hv.c index 938a3d5..c958502 100644 --- a/src/heapy/hv.c +++ b/src/heapy/hv.c @@ -1758,6 +1758,7 @@ static PyMethodDef hv_methods[] = { {"cli_indisize", (PyCFunction)hv_cli_indisize, METH_VARARGS, hv_cli_indisize_doc}, {"cli_inrel", (PyCFunction)hv_cli_inrel, METH_VARARGS, hv_cli_inrel_doc}, {"cli_none", (PyCFunction)hv_cli_none, METH_NOARGS, hv_cli_none_doc}, + {"cli_prod", (PyCFunction)hv_cli_prod, METH_VARARGS, hv_cli_prod_doc}, {"cli_rcs", (PyCFunction)hv_cli_rcs, METH_VARARGS, hv_cli_rcs_doc}, {"cli_type", (PyCFunction)hv_cli_type, METH_NOARGS, hv_cli_type_doc}, {"cli_user_defined", (PyCFunction)hv_cli_user_defined, METH_VARARGS|METH_KEYWORDS, hv_cli_user_defined_doc}, diff --git a/src/heapy/hv_cli.c b/src/heapy/hv_cli.c index 9567584..7b24965 100644 --- a/src/heapy/hv_cli.c +++ b/src/heapy/hv_cli.c @@ -6,6 +6,7 @@ #include "hv_cli_dictof.c" #include "hv_cli_id.c" #include "hv_cli_idset.c" +#include "hv_cli_prod.c" #include "hv_cli_rcs.c" #include "hv_cli_indisize.c" #include "hv_cli_findex.c" diff --git a/src/heapy/hv_cli_prod.c b/src/heapy/hv_cli_prod.c new file mode 100644 index 0000000..c51b232 --- /dev/null +++ b/src/heapy/hv_cli_prod.c @@ -0,0 +1,159 @@ +/* Implementation of the 'prod' classifier */ + +PyDoc_STRVAR(hv_cli_prod_doc, +"HV.cli_prod(memo) -> ObjectClassifier\n" +"\n" +"Return a classifier that classifes by \"producer\".\n" +"\n" +"The classification of an object is the fine name and line number\n" +"in which the object is produced (allocated).\n" +"\n" +" memo A dict object used to\n" +" memoize the classification sets.\n" +); + +// The sizeof of PyGC_Head is not to be trusted upon even across Python minor +// released. Eg: python/cpython@8766cb7 +static Py_ssize_t sizeof_PyGC_Head; + +static void lazy_init_hv_cli_prod() +{ + if (sizeof_PyGC_Head) + return; + + if (PyLong_AsLong(PySys_GetObject("hexversion")) == PY_VERSION_HEX) { + sizeof_PyGC_Head = sizeof(PyGC_Head); + return; + } + + PyObject *_testcapimodule, *_testcapi_SIZEOF_PYGC_HEAD = NULL; + + _testcapimodule = PyImport_ImportModule("_testcapi"); + if (!_testcapimodule) + goto Err; + + _testcapi_SIZEOF_PYGC_HEAD = PyObject_GetAttrString( + _testcapimodule, "SIZEOF_PYGC_HEAD"); + if (!_testcapi_SIZEOF_PYGC_HEAD) + goto Err; + + sizeof_PyGC_Head = PyLong_AsSsize_t(_testcapi_SIZEOF_PYGC_HEAD); + if (sizeof_PyGC_Head < 0) + goto Err; + + Py_DECREF(_testcapimodule); + Py_DECREF(_testcapi_SIZEOF_PYGC_HEAD); + return; + +Err: + Py_XDECREF(_testcapimodule); + Py_XDECREF(_testcapi_SIZEOF_PYGC_HEAD); + + PyErr_Clear(); + sizeof_PyGC_Head = sizeof(PyGC_Head); + PyErr_WarnFormat(PyExc_UserWarning, 1, + "Unable to determine sizeof(PyGC_Head) from " + "_testcapi.SIZEOF_PYGC_HEAD, assuming %zd", + sizeof_PyGC_Head); +} + +typedef struct { + PyObject_VAR_HEAD + NyHeapViewObject *hv; + PyObject *memo; +} ProdObject; + +static PyObject * +hv_cli_prod_memoized_kind(ProdObject * self, PyObject *kind) +{ + PyObject *result = PyDict_GetItem(self->memo, kind); + if (!result) { + if (PyErr_Occurred()) + goto Err; + if (PyDict_SetItem(self->memo, kind, kind) == -1) + goto Err; + result = kind; + } + Py_INCREF(result); + return result; +Err: + return 0; +} + +static PyObject * +hv_cli_prod_classify(ProdObject *self, PyObject *obj) +{ + Py_uintptr_t ptr; + PyTypeObject *type; + PyObject *kind = NULL; + PyObject *tb, *result; + + // Refer to _tracemalloc.c:_tracemalloc__get_object_traceback + type = Py_TYPE(obj); + if (PyType_IS_GC(type)) { + ptr = (Py_uintptr_t)((char *)obj - sizeof_PyGC_Head); + } else { + ptr = (Py_uintptr_t)obj; + } + + tb = _PyTraceMalloc_GetTraceback(0, (Py_uintptr_t)ptr); + + if (!tb) + goto Err; + + if (PySequence_Check(tb) && PySequence_Length(tb)) { + kind = PySequence_GetItem(tb, 0); + } else { + kind = Py_None; + Py_INCREF(Py_None); + } + + result = hv_cli_prod_memoized_kind(self, kind); + Py_DECREF(tb); + Py_DECREF(kind); + return result; + +Err: + Py_XDECREF(tb); + Py_XDECREF(kind); + return 0; +} + +static int +hv_cli_prod_le(PyObject * self, PyObject *a, PyObject *b) +{ + return PyObject_RichCompareBool(a, b, Py_LE); +} + +static NyObjectClassifierDef hv_cli_prod_def = { + 0, + sizeof(NyObjectClassifierDef), + "hv_cli_prod", + "classifier returning object producer", + (binaryfunc)hv_cli_prod_classify, + (binaryfunc)hv_cli_prod_memoized_kind, + hv_cli_prod_le +}; + +static PyObject * +hv_cli_prod(NyHeapViewObject *self, PyObject *args) +{ + PyObject *r, *memo; + ProdObject *s; + if (!PyArg_ParseTuple(args, "O!:cli_prod", + &PyDict_Type, &memo)) + return NULL; + + lazy_init_hv_cli_prod(); + + s = NYTUPLELIKE_NEW(ProdObject); + if (!s) + return 0; + s->hv = self; + Py_INCREF(s->hv); + s->memo = memo; + Py_INCREF(memo); + r = NyObjectClassifier_New((PyObject *)s, &hv_cli_prod_def); + Py_DECREF(s); + return r; +} diff --git a/src/heapy/hv_cli_rcs.c b/src/heapy/hv_cli_rcs.c index ad44c00..133ae99 100644 --- a/src/heapy/hv_cli_rcs.c +++ b/src/heapy/hv_cli_rcs.c @@ -34,15 +34,15 @@ hv_cli_rcs_fast_memoized_kind(RetclasetObject * self, PyObject *kind) { PyObject *result = PyDict_GetItem(self->memo, kind); if (!result) { - if (PyErr_Occurred()) - goto Err; - if (PyDict_SetItem(self->memo, kind, kind) == -1) - goto Err; - result = kind; + if (PyErr_Occurred()) + goto Err; + if (PyDict_SetItem(self->memo, kind, kind) == -1) + goto Err; + result = kind; } Py_INCREF(result); return result; - Err: +Err: return 0; } @@ -56,10 +56,10 @@ rcs_visit_memoize_sub(PyObject *obj, MemoRcsArg *arg) { obj = arg->cli->def->memoized_kind(arg->cli->self, obj); if (!obj) - return -1; + return -1; if (NyNodeSet_setobj(arg->ns, obj) == -1) { - Py_DECREF(obj); - return -1; + Py_DECREF(obj); + return -1; } Py_DECREF(obj); return 0; @@ -69,30 +69,30 @@ static PyObject * hv_cli_rcs_memoized_kind(RetclasetObject * self, PyObject *kind) { if (!NyNodeSet_Check(kind)) { - PyErr_SetString(PyExc_TypeError, - "hv_cli_rcs_memoized_kind: nodeset object (immutable) expected."); - return 0; + PyErr_SetString(PyExc_TypeError, + "hv_cli_rcs_memoized_kind: nodeset object (immutable) expected."); + return 0; } if (!self->cli->def->memoized_kind) { - return hv_cli_rcs_fast_memoized_kind(self, kind); + return hv_cli_rcs_fast_memoized_kind(self, kind); } else { - MemoRcsArg arg; - PyObject *result; - arg.cli = self->cli; - arg.ns = hv_mutnodeset_new(self->hv); - if (!arg.ns) - return 0; - if (iterable_iterate(kind, (visitproc)rcs_visit_memoize_sub, &arg) == -1) - goto Err; - if (NyNodeSet_be_immutable(&arg.ns) == -1) - goto Err; - result = hv_cli_rcs_fast_memoized_kind(self, (PyObject *)arg.ns); - Ret: - Py_DECREF(arg.ns); - return result; - Err: - result = 0; - goto Ret; + MemoRcsArg arg; + PyObject *result; + arg.cli = self->cli; + arg.ns = hv_mutnodeset_new(self->hv); + if (!arg.ns) + return 0; + if (iterable_iterate(kind, (visitproc)rcs_visit_memoize_sub, &arg) == -1) + goto Err; + if (NyNodeSet_be_immutable(&arg.ns) == -1) + goto Err; + result = hv_cli_rcs_fast_memoized_kind(self, (PyObject *)arg.ns); +Ret: + Py_DECREF(arg.ns); + return result; +Err: + result = 0; + goto Ret; } } @@ -108,25 +108,25 @@ hv_cli_rcs_classify(RetclasetObject * self, PyObject *obj) if (!Ri) goto Err; if (NyNodeGraph_Region(self->rg, obj, &lo, &hi) == -1) { - goto Err; + goto Err; } for (cur = lo; cur < hi; cur++) { - if (cur->tgt == Py_None) - continue; - kind = self->cli->def->classify(self->cli->self, cur->tgt); - if (!kind) - goto Err; - if (NyNodeSet_setobj(Ri, kind) == -1) - goto Err; - Py_DECREF(kind); + if (cur->tgt == Py_None) + continue; + kind = self->cli->def->classify(self->cli->self, cur->tgt); + if (!kind) + goto Err; + if (NyNodeSet_setobj(Ri, kind) == -1) + goto Err; + Py_DECREF(kind); } if (NyNodeSet_be_immutable(&Ri) == -1) goto Err; kind = hv_cli_rcs_fast_memoized_kind(self, (PyObject *)Ri); Py_DECREF(Ri); return kind; - - Err: + +Err: Py_XDECREF(kind); Py_XDECREF(Ri); return 0; @@ -154,15 +154,15 @@ hv_cli_rcs(NyHeapViewObject *hv, PyObject *args) { PyObject *r; RetclasetObject *s, tmp; - if (!PyArg_ParseTuple(args, "O!O!O!:cli_rcs", - &NyNodeGraph_Type, &tmp.rg, - &NyObjectClassifier_Type, &tmp.cli, - &PyDict_Type, &tmp.memo)) { - return 0; + if (!PyArg_ParseTuple(args, "O!O!O!:cli_rcs", + &NyNodeGraph_Type, &tmp.rg, + &NyObjectClassifier_Type, &tmp.cli, + &PyDict_Type, &tmp.memo)) { + return 0; } s = NYTUPLELIKE_NEW(RetclasetObject); if (!s) - return 0; + return 0; s->hv = hv; Py_INCREF(hv); @@ -176,8 +176,3 @@ hv_cli_rcs(NyHeapViewObject *hv, PyObject *args) Py_DECREF(s); return r; } - - - - -