Skip to content

bpo-44821: Eagerly assign __dict__ for new objects. #27589

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Include/internal/pycore_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 7 additions & 3 deletions Lib/test/test_capi.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_gdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Create instance dictionaries (__dict__) eagerly, to improve regularity of
object layout and assist specialization.
31 changes: 28 additions & 3 deletions Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
10 changes: 9 additions & 1 deletion Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down