]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-44821: Eagerly assign __dict__ for new objects. (GH-27589)
authorMark Shannon <mark@hotpy.org>
Wed, 4 Aug 2021 15:41:14 +0000 (16:41 +0100)
committerGitHub <noreply@github.com>
Wed, 4 Aug 2021 15:41:14 +0000 (16:41 +0100)
Include/internal/pycore_object.h
Lib/test/test_capi.py
Lib/test/test_gdb.py
Misc/NEWS.d/next/Core and Builtins/2021-08-04-11-37-38.bpo-44821.67YHGI.rst [new file with mode: 0644]
Objects/dictobject.c
Objects/typeobject.c

index 4091f5178eed1816d3e1e392e660b4978ab4096a..744b41ae5d90d6f9583e6ba146c48f3faf033ed1 100644 (file)
@@ -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
index 169e7acbf92b4ca78b71ca0eb3a18573557bb4a9..9165f45db64f347139326d800f894580d5e975c8 100644 (file)
@@ -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):
index 7bdef25c76384a354a55c5ceb4a99560a108ef92..98b36d6cd049c5ac9536c5b3f58be75f4168e3e3 100644 (file)
@@ -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 (file)
index 0000000..1e254a6
--- /dev/null
@@ -0,0 +1,2 @@
+Create instance dictionaries (__dict__) eagerly, to improve regularity of
+object layout and assist specialization.
index 5fb9d015612363da55b3907d652c9bca574743be..5ad630feaf1e864e8283761a8d05a3578eebdd1d 100644 (file)
@@ -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));
         }
index 2240f780bb9cebd82292466d253c64afeaf3b50f..7ae50c453ed2f862852cecbbd53eb8b88b971191 100644 (file)
@@ -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