diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 4091f5178ee..744b41ae5d9 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -180,6 +180,8 @@ extern int _Py_CheckSlotResult( extern PyObject* _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems); +extern int _PyObject_InitializeDict(PyObject *obj); + #ifdef __cplusplus } #endif diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 169e7acbf92..9165f45db64 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -323,9 +323,13 @@ class CAPITest(unittest.TestCase): break """ rc, out, err = assert_python_ok('-c', code) - self.assertIn(b'MemoryError 1', out) - self.assertIn(b'MemoryError 2 20', out) - self.assertIn(b'MemoryError 3 30', out) + lines = out.splitlines() + for i, line in enumerate(lines, 1): + self.assertIn(b'MemoryError', out) + *_, count = line.split(b' ') + count = int(count) + self.assertLessEqual(count, i*5) + self.assertGreaterEqual(count, i*5-1) def test_mapping_keys_values_items(self): class Mapping1(dict): diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py index 7bdef25c763..98b36d6cd04 100644 --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -566,7 +566,7 @@ id(foo)''') # http://bugs.python.org/issue8032#msg100537 ) gdb_repr, gdb_output = self.get_gdb_repr('id(__builtins__.help)', import_site=True) - m = re.match(r'<_Helper at remote 0x-?[0-9a-f]+>', gdb_repr) + m = re.match(r'<_Helper\(\) at remote 0x-?[0-9a-f]+>', gdb_repr) self.assertTrue(m, msg='Unexpected rendering %r' % gdb_repr) diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-08-04-11-37-38.bpo-44821.67YHGI.rst b/Misc/NEWS.d/next/Core and Builtins/2021-08-04-11-37-38.bpo-44821.67YHGI.rst new file mode 100644 index 00000000000..1e254a62773 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-08-04-11-37-38.bpo-44821.67YHGI.rst @@ -0,0 +1,2 @@ +Create instance dictionaries (__dict__) eagerly, to improve regularity of +object layout and assist specialization. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 5fb9d015612..5ad630feaf1 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -4866,19 +4866,44 @@ _PyDict_NewKeysForClass(void) #define CACHED_KEYS(tp) (((PyHeapTypeObject*)tp)->ht_cached_keys) +int +_PyObject_InitializeDict(PyObject *obj) +{ + PyObject **dictptr = _PyObject_GetDictPtr(obj); + if (dictptr == NULL) { + return 0; + } + assert(*dictptr == NULL); + PyTypeObject *tp = Py_TYPE(obj); + PyObject *dict; + if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) { + dictkeys_incref(CACHED_KEYS(tp)); + dict = new_dict_with_shared_keys(CACHED_KEYS(tp)); + } + else { + dict = PyDict_New(); + } + if (dict == NULL) { + return -1; + } + *dictptr = dict; + return 0; +} + + PyObject * PyObject_GenericGetDict(PyObject *obj, void *context) { - PyObject *dict, **dictptr = _PyObject_GetDictPtr(obj); + PyObject **dictptr = _PyObject_GetDictPtr(obj); if (dictptr == NULL) { PyErr_SetString(PyExc_AttributeError, "This object has no __dict__"); return NULL; } - dict = *dictptr; + PyObject *dict = *dictptr; if (dict == NULL) { PyTypeObject *tp = Py_TYPE(obj); - if ((tp->tp_flags & Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) { + if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) { dictkeys_incref(CACHED_KEYS(tp)); *dictptr = dict = new_dict_with_shared_keys(CACHED_KEYS(tp)); } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 2240f780bb9..7ae50c453ed 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4505,7 +4505,15 @@ object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) Py_DECREF(joined); return NULL; } - return type->tp_alloc(type, 0); + PyObject *obj = type->tp_alloc(type, 0); + if (obj == NULL) { + return NULL; + } + if (_PyObject_InitializeDict(obj)) { + Py_DECREF(obj); + return NULL; + } + return obj; } static void