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

This commit is contained in:
Mark Shannon 2021-08-04 16:41:14 +01:00 committed by GitHub
parent c83919bd63
commit cee67fa661
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 49 additions and 8 deletions

View File

@ -180,6 +180,8 @@ extern int _Py_CheckSlotResult(
extern PyObject* _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems); extern PyObject* _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems);
extern int _PyObject_InitializeDict(PyObject *obj);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -323,9 +323,13 @@ class CAPITest(unittest.TestCase):
break break
""" """
rc, out, err = assert_python_ok('-c', code) rc, out, err = assert_python_ok('-c', code)
self.assertIn(b'MemoryError 1', out) lines = out.splitlines()
self.assertIn(b'MemoryError 2 20', out) for i, line in enumerate(lines, 1):
self.assertIn(b'MemoryError 3 30', out) 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): def test_mapping_keys_values_items(self):
class Mapping1(dict): class Mapping1(dict):

View File

@ -566,7 +566,7 @@ id(foo)''')
# http://bugs.python.org/issue8032#msg100537 ) # http://bugs.python.org/issue8032#msg100537 )
gdb_repr, gdb_output = self.get_gdb_repr('id(__builtins__.help)', import_site=True) 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, self.assertTrue(m,
msg='Unexpected rendering %r' % gdb_repr) msg='Unexpected rendering %r' % gdb_repr)

View File

@ -0,0 +1,2 @@
Create instance dictionaries (__dict__) eagerly, to improve regularity of
object layout and assist specialization.

View File

@ -4866,19 +4866,44 @@ _PyDict_NewKeysForClass(void)
#define CACHED_KEYS(tp) (((PyHeapTypeObject*)tp)->ht_cached_keys) #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 *
PyObject_GenericGetDict(PyObject *obj, void *context) PyObject_GenericGetDict(PyObject *obj, void *context)
{ {
PyObject *dict, **dictptr = _PyObject_GetDictPtr(obj); PyObject **dictptr = _PyObject_GetDictPtr(obj);
if (dictptr == NULL) { if (dictptr == NULL) {
PyErr_SetString(PyExc_AttributeError, PyErr_SetString(PyExc_AttributeError,
"This object has no __dict__"); "This object has no __dict__");
return NULL; return NULL;
} }
dict = *dictptr; PyObject *dict = *dictptr;
if (dict == NULL) { if (dict == NULL) {
PyTypeObject *tp = Py_TYPE(obj); 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)); dictkeys_incref(CACHED_KEYS(tp));
*dictptr = dict = new_dict_with_shared_keys(CACHED_KEYS(tp)); *dictptr = dict = new_dict_with_shared_keys(CACHED_KEYS(tp));
} }

View File

@ -4505,7 +4505,15 @@ object_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_DECREF(joined); Py_DECREF(joined);
return NULL; 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 static void