Skip to content

Commit cee67fa

Browse files
authored
bpo-44821: Eagerly assign __dict__ for new objects. (GH-27589)
1 parent c83919b commit cee67fa

File tree

6 files changed

+49
-8
lines changed

6 files changed

+49
-8
lines changed

Include/internal/pycore_object.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ extern int _Py_CheckSlotResult(
180180

181181
extern PyObject* _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems);
182182

183+
extern int _PyObject_InitializeDict(PyObject *obj);
184+
183185
#ifdef __cplusplus
184186
}
185187
#endif

Lib/test/test_capi.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,13 @@ class C(): pass
323323
break
324324
"""
325325
rc, out, err = assert_python_ok('-c', code)
326-
self.assertIn(b'MemoryError 1', out)
327-
self.assertIn(b'MemoryError 2 20', out)
328-
self.assertIn(b'MemoryError 3 30', out)
326+
lines = out.splitlines()
327+
for i, line in enumerate(lines, 1):
328+
self.assertIn(b'MemoryError', out)
329+
*_, count = line.split(b' ')
330+
count = int(count)
331+
self.assertLessEqual(count, i*5)
332+
self.assertGreaterEqual(count, i*5-1)
329333

330334
def test_mapping_keys_values_items(self):
331335
class Mapping1(dict):

Lib/test/test_gdb.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ def test_builtins_help(self):
566566
# http://bugs.python.org/issue8032#msg100537 )
567567
gdb_repr, gdb_output = self.get_gdb_repr('id(__builtins__.help)', import_site=True)
568568

569-
m = re.match(r'<_Helper at remote 0x-?[0-9a-f]+>', gdb_repr)
569+
m = re.match(r'<_Helper\(\) at remote 0x-?[0-9a-f]+>', gdb_repr)
570570
self.assertTrue(m,
571571
msg='Unexpected rendering %r' % gdb_repr)
572572

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Create instance dictionaries (__dict__) eagerly, to improve regularity of
2+
object layout and assist specialization.

Objects/dictobject.c

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4866,19 +4866,44 @@ _PyDict_NewKeysForClass(void)
48664866

48674867
#define CACHED_KEYS(tp) (((PyHeapTypeObject*)tp)->ht_cached_keys)
48684868

4869+
int
4870+
_PyObject_InitializeDict(PyObject *obj)
4871+
{
4872+
PyObject **dictptr = _PyObject_GetDictPtr(obj);
4873+
if (dictptr == NULL) {
4874+
return 0;
4875+
}
4876+
assert(*dictptr == NULL);
4877+
PyTypeObject *tp = Py_TYPE(obj);
4878+
PyObject *dict;
4879+
if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) {
4880+
dictkeys_incref(CACHED_KEYS(tp));
4881+
dict = new_dict_with_shared_keys(CACHED_KEYS(tp));
4882+
}
4883+
else {
4884+
dict = PyDict_New();
4885+
}
4886+
if (dict == NULL) {
4887+
return -1;
4888+
}
4889+
*dictptr = dict;
4890+
return 0;
4891+
}
4892+
4893+
48694894
PyObject *
48704895
PyObject_GenericGetDict(PyObject *obj, void *context)
48714896
{
4872-
PyObject *dict, **dictptr = _PyObject_GetDictPtr(obj);
4897+
PyObject **dictptr = _PyObject_GetDictPtr(obj);
48734898
if (dictptr == NULL) {
48744899
PyErr_SetString(PyExc_AttributeError,
48754900
"This object has no __dict__");
48764901
return NULL;
48774902
}
4878-
dict = *dictptr;
4903+
PyObject *dict = *dictptr;
48794904
if (dict == NULL) {
48804905
PyTypeObject *tp = Py_TYPE(obj);
4881-
if ((tp->tp_flags & Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) {
4906+
if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) {
48824907
dictkeys_incref(CACHED_KEYS(tp));
48834908
*dictptr = dict = new_dict_with_shared_keys(CACHED_KEYS(tp));
48844909
}

Objects/typeobject.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4505,7 +4505,15 @@ object_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
45054505
Py_DECREF(joined);
45064506
return NULL;
45074507
}
4508-
return type->tp_alloc(type, 0);
4508+
PyObject *obj = type->tp_alloc(type, 0);
4509+
if (obj == NULL) {
4510+
return NULL;
4511+
}
4512+
if (_PyObject_InitializeDict(obj)) {
4513+
Py_DECREF(obj);
4514+
return NULL;
4515+
}
4516+
return obj;
45094517
}
45104518

45114519
static void

0 commit comments

Comments
 (0)