[Python-checkins] bpo-44821: Eagerly assign __dict__ for new objects. (GH-27589)

markshannon webhook-mailer at python.org
Wed Aug 4 11:41:23 EDT 2021


https://github.com/python/cpython/commit/cee67fa66129b5d1db5c8aa3884338f82f0da3de
commit: cee67fa66129b5d1db5c8aa3884338f82f0da3de
branch: main
author: Mark Shannon <mark at hotpy.org>
committer: markshannon <mark at hotpy.org>
date: 2021-08-04T16:41:14+01:00
summary:

bpo-44821: Eagerly assign __dict__ for new objects. (GH-27589)

files:
A Misc/NEWS.d/next/Core and Builtins/2021-08-04-11-37-38.bpo-44821.67YHGI.rst
M Include/internal/pycore_object.h
M Lib/test/test_capi.py
M Lib/test/test_gdb.py
M Objects/dictobject.c
M Objects/typeobject.c

diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h
index 4091f5178eed1..744b41ae5d90d 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 169e7acbf92b4..9165f45db64f3 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -323,9 +323,13 @@ class C(): pass
                         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 7bdef25c76384..98b36d6cd049c 100644
--- a/Lib/test/test_gdb.py
+++ b/Lib/test/test_gdb.py
@@ -566,7 +566,7 @@ def test_builtins_help(self):
         #  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 0000000000000..1e254a62773bb
--- /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 5fb9d01561236..5ad630feaf1e8 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 2240f780bb9ce..7ae50c453ed2f 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



More information about the Python-checkins mailing list