Skip to content

Commit de93f71

Browse files
corona10tonghuaroot
andcommitted
gh-151722: Defer GC tracking of frozendict.fromkeys() as possible
Co-authored-by: tonghuaroot <tonghuaroot@gmail.com>
1 parent 5858e42 commit de93f71

2 files changed

Lines changed: 25 additions & 10 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Defer GC tracking of a :class:`frozendict` created by
2+
:meth:`!frozendict.fromkeys` until the end of construction as possible.

Objects/dictobject.c

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ static PyObject* frozendict_new(PyTypeObject *type, PyObject *args,
140140
PyObject *kwds);
141141
static PyObject* frozendict_new_untracked(PyTypeObject *type);
142142
static PyObject* dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
143+
static PyObject* dict_new_untracked(PyTypeObject *type);
143144
static int dict_merge(PyObject *a, PyObject *b, int override, PyObject **dupkey);
144145
static int dict_contains(PyObject *op, PyObject *key);
145146
static int dict_merge_from_seq2(PyObject *d, PyObject *seq2, int override);
@@ -3419,22 +3420,26 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
34193420
PyObject *d;
34203421
int status;
34213422

3423+
PyTypeObject *cls_type = _PyType_CAST(cls);
34223424
d = _PyObject_CallNoArgs(cls);
34233425
if (d == NULL) {
34243426
return NULL;
34253427
}
3428+
// The constructor returns a tracked object; keep it untracked while it is
3429+
// filled and GC-track it once complete (done:), so a half-built frozendict
3430+
// is never observable.
3431+
_PyObject_GC_UNTRACK(d);
34263432

34273433
// If cls is a dict or frozendict subclass with overridden constructor,
34283434
// copy the frozendict.
3429-
PyTypeObject *cls_type = _PyType_CAST(cls);
34303435
if (PyFrozenDict_Check(d) && cls_type->tp_new != frozendict_new) {
34313436
// Subclass-friendly copy
34323437
PyObject *copy;
34333438
if (PyObject_IsSubclass(cls, (PyObject*)&PyFrozenDict_Type)) {
3434-
copy = frozendict_new(cls_type, NULL, NULL);
3439+
copy = frozendict_new_untracked(cls_type);
34353440
}
34363441
else {
3437-
copy = dict_new(cls_type, NULL, NULL);
3442+
copy = dict_new_untracked(cls_type);
34383443
}
34393444
if (copy == NULL) {
34403445
Py_DECREF(d);
@@ -3456,23 +3461,23 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
34563461
Py_BEGIN_CRITICAL_SECTION2(d, iterable);
34573462
d = (PyObject *)dict_dict_fromkeys(mp, iterable, value);
34583463
Py_END_CRITICAL_SECTION2();
3459-
return d;
3464+
goto done;
34603465
}
34613466
else if (PyFrozenDict_CheckExact(iterable)) {
34623467
PyDictObject *mp = (PyDictObject *)d;
34633468

34643469
Py_BEGIN_CRITICAL_SECTION(d);
34653470
d = (PyObject *)dict_dict_fromkeys(mp, iterable, value);
34663471
Py_END_CRITICAL_SECTION();
3467-
return d;
3472+
goto done;
34683473
}
34693474
else if (PyAnySet_CheckExact(iterable)) {
34703475
PyDictObject *mp = (PyDictObject *)d;
34713476

34723477
Py_BEGIN_CRITICAL_SECTION2(d, iterable);
34733478
d = (PyObject *)dict_set_fromkeys(mp, iterable, value);
34743479
Py_END_CRITICAL_SECTION2();
3475-
return d;
3480+
goto done;
34763481
}
34773482
}
34783483
else if (PyFrozenDict_CheckExact(d)) {
@@ -3482,20 +3487,20 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
34823487
Py_BEGIN_CRITICAL_SECTION(iterable);
34833488
d = (PyObject *)dict_dict_fromkeys(mp, iterable, value);
34843489
Py_END_CRITICAL_SECTION();
3485-
return d;
3490+
goto done;
34863491
}
34873492
else if (PyFrozenDict_CheckExact(iterable)) {
34883493
PyDictObject *mp = (PyDictObject *)d;
34893494
d = (PyObject *)dict_dict_fromkeys(mp, iterable, value);
3490-
return d;
3495+
goto done;
34913496
}
34923497
else if (PyAnySet_CheckExact(iterable)) {
34933498
PyDictObject *mp = (PyDictObject *)d;
34943499

34953500
Py_BEGIN_CRITICAL_SECTION(iterable);
34963501
d = (PyObject *)dict_set_fromkeys(mp, iterable, value);
34973502
Py_END_CRITICAL_SECTION();
3498-
return d;
3503+
goto done;
34993504
}
35003505
}
35013506

@@ -3541,12 +3546,20 @@ dict_iter_exit:;
35413546
if (PyErr_Occurred())
35423547
goto Fail;
35433548
Py_DECREF(it);
3544-
return d;
3549+
goto done;
35453550

35463551
Fail:
35473552
Py_DECREF(it);
35483553
Py_DECREF(d);
35493554
return NULL;
3555+
3556+
done:
3557+
// Built untracked above; GC-track now that it is complete.
3558+
if (d != NULL) {
3559+
assert(!_PyObject_GC_IS_TRACKED(d));
3560+
_PyObject_GC_TRACK(d);
3561+
}
3562+
return d;
35503563
}
35513564

35523565
/* Methods */

0 commit comments

Comments
 (0)