Skip to content

Commit

Permalink
bpo-42972: Fully implement GC protocol for functools keywrapper and p…
Browse files Browse the repository at this point in the history
…artial types (pythonGH-26363)
  • Loading branch information
Erlend Egeberg Aasland authored May 28, 2021
1 parent 4e2e5c1 commit 8994e9c
Showing 1 changed file with 37 additions and 22 deletions.
59 changes: 37 additions & 22 deletions Modules/_functoolsmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,18 +147,37 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
return (PyObject *)pto;
}

static int
partial_clear(partialobject *pto)
{
Py_CLEAR(pto->fn);
Py_CLEAR(pto->args);
Py_CLEAR(pto->kw);
Py_CLEAR(pto->dict);
return 0;
}

static int
partial_traverse(partialobject *pto, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(pto));
Py_VISIT(pto->fn);
Py_VISIT(pto->args);
Py_VISIT(pto->kw);
Py_VISIT(pto->dict);
return 0;
}

static void
partial_dealloc(partialobject *pto)
{
PyTypeObject *tp = Py_TYPE(pto);
/* bpo-31095: UnTrack is needed before calling any callbacks */
PyObject_GC_UnTrack(pto);
if (pto->weakreflist != NULL)
if (pto->weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *) pto);
Py_XDECREF(pto->fn);
Py_XDECREF(pto->args);
Py_XDECREF(pto->kw);
Py_XDECREF(pto->dict);
}
(void)partial_clear(pto);
tp->tp_free(pto);
Py_DECREF(tp);
}
Expand Down Expand Up @@ -307,16 +326,6 @@ partial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
return res;
}

static int
partial_traverse(partialobject *pto, visitproc visit, void *arg)
{
Py_VISIT(pto->fn);
Py_VISIT(pto->args);
Py_VISIT(pto->kw);
Py_VISIT(pto->dict);
return 0;
}

PyDoc_STRVAR(partial_doc,
"partial(func, *args, **keywords) - new function with partial application\n\
of the given arguments and keywords.\n");
Expand Down Expand Up @@ -469,6 +478,7 @@ static PyType_Slot partial_type_slots[] = {
{Py_tp_setattro, PyObject_GenericSetAttr},
{Py_tp_doc, (void *)partial_doc},
{Py_tp_traverse, partial_traverse},
{Py_tp_clear, partial_clear},
{Py_tp_methods, partial_methods},
{Py_tp_members, partial_memberlist},
{Py_tp_getset, partial_getsetlist},
Expand Down Expand Up @@ -506,14 +516,16 @@ static void
keyobject_dealloc(keyobject *ko)
{
PyTypeObject *tp = Py_TYPE(ko);
keyobject_clear(ko);
PyObject_Free(ko);
PyObject_GC_UnTrack(ko);
(void)keyobject_clear(ko);
tp->tp_free(ko);
Py_DECREF(tp);
}

static int
keyobject_traverse(keyobject *ko, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(ko));
Py_VISIT(ko->cmp);
Py_VISIT(ko->object);
return 0;
Expand Down Expand Up @@ -546,7 +558,8 @@ static PyType_Slot keyobject_type_slots[] = {
static PyType_Spec keyobject_type_spec = {
.name = "functools.KeyWrapper",
.basicsize = sizeof(keyobject),
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
Py_TPFLAGS_HAVE_GC),
.slots = keyobject_type_slots
};

Expand All @@ -560,14 +573,15 @@ keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds)
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:K", kwargs, &object))
return NULL;

result = PyObject_New(keyobject, Py_TYPE(ko));
result = PyObject_GC_New(keyobject, Py_TYPE(ko));
if (result == NULL) {
return NULL;
}
Py_INCREF(ko->cmp);
result->cmp = ko->cmp;
Py_INCREF(object);
result->object = object;
PyObject_GC_Track(result);
return (PyObject *)result;
}

Expand Down Expand Up @@ -621,12 +635,13 @@ functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
return NULL;

state = get_functools_state(self);
object = PyObject_New(keyobject, state->keyobject_type);
object = PyObject_GC_New(keyobject, state->keyobject_type);
if (!object)
return NULL;
Py_INCREF(cmp);
object->cmp = cmp;
object->object = NULL;
PyObject_GC_Track(object);
return (PyObject *)object;
}

Expand Down Expand Up @@ -754,7 +769,7 @@ lru_list_elem_dealloc(lru_list_elem *link)
PyTypeObject *tp = Py_TYPE(link);
Py_XDECREF(link->key);
Py_XDECREF(link->result);
PyObject_Free(link);
tp->tp_free(link);
Py_DECREF(tp);
}

Expand Down Expand Up @@ -1260,7 +1275,7 @@ lru_cache_dealloc(lru_cache_object *obj)
PyObject_ClearWeakRefs((PyObject*)obj);
}

lru_cache_tp_clear(obj);
(void)lru_cache_tp_clear(obj);
tp->tp_free(obj);
Py_DECREF(tp);
}
Expand Down

0 comments on commit 8994e9c

Please sign in to comment.