Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit c3c7848

Browse filesBrowse files
pythongh-100288: Specialise LOAD_ATTR_METHOD for managed dictionaries (pythonGH-100289)
1 parent 7fc7909 commit c3c7848
Copy full SHA for c3c7848

File tree

Expand file treeCollapse file tree

8 files changed

+101
-43
lines changed
Filter options
Expand file treeCollapse file tree

8 files changed

+101
-43
lines changed

‎Include/internal/pycore_opcode.h

Copy file name to clipboardExpand all lines: Include/internal/pycore_opcode.h
+11-11Lines changed: 11 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Include/opcode.h

Copy file name to clipboardExpand all lines: Include/opcode.h
+18-17Lines changed: 18 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Lib/opcode.py

Copy file name to clipboardExpand all lines: Lib/opcode.py
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ def pseudo_op(name, op, real_ops):
336336
# These will always push [unbound method, self] onto the stack.
337337
"LOAD_ATTR_METHOD_LAZY_DICT",
338338
"LOAD_ATTR_METHOD_NO_DICT",
339+
"LOAD_ATTR_METHOD_MANAGED_DICT",
339340
"LOAD_ATTR_METHOD_WITH_DICT",
340341
"LOAD_ATTR_METHOD_WITH_VALUES",
341342
],
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Specialize method loading for objects with ``Py_TPFLAGS_MANAGED_DICT`` set.

‎Python/bytecodes.c

Copy file name to clipboardExpand all lines: Python/bytecodes.c
+25Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2717,6 +2717,31 @@ dummy_func(
27172717
JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
27182718
}
27192719

2720+
// error: LOAD_ATTR has irregular stack effect
2721+
inst(LOAD_ATTR_METHOD_MANAGED_DICT) {
2722+
assert(cframe.use_tracing == 0);
2723+
PyObject *self = TOP();
2724+
PyTypeObject *self_cls = Py_TYPE(self);
2725+
_PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr;
2726+
uint32_t type_version = read_u32(cache->type_version);
2727+
assert(type_version != 0);
2728+
DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR)
2729+
assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
2730+
PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self);
2731+
DEOPT_IF(_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
2732+
PyObject *dict = _PyDictOrValues_GetDict(dorv);
2733+
PyDictKeysObject *keys = (dict == NULL) ? NULL : ((PyDictObject *)dict)->ma_keys;
2734+
// Note: cache->keys_version can be 0 when dict is NULL.
2735+
DEOPT_IF(keys != NULL && keys->dk_version != read_u32(cache->keys_version), LOAD_ATTR);
2736+
STAT_INC(LOAD_ATTR, hit);
2737+
PyObject *res = read_obj(cache->descr);
2738+
assert(res != NULL);
2739+
assert(_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR));
2740+
SET_TOP(Py_NewRef(res));
2741+
PUSH(self);
2742+
JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
2743+
}
2744+
27202745
// error: LOAD_ATTR has irregular stack effect
27212746
inst(LOAD_ATTR_METHOD_WITH_DICT) {
27222747
/* Can be either a managed dict, or a tp_dictoffset offset.*/

‎Python/generated_cases.c.h

Copy file name to clipboardExpand all lines: Python/generated_cases.c.h
+25Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Python/opcode_targets.h

Copy file name to clipboardExpand all lines: Python/opcode_targets.h
+10-10Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Python/specialize.c

Copy file name to clipboardExpand all lines: Python/specialize.c
+10-5Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,6 @@ _PyCode_Quicken(PyCodeObject *code)
335335
#define SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD 22
336336
#define SPEC_FAIL_ATTR_CLASS_METHOD_OBJ 23
337337
#define SPEC_FAIL_ATTR_OBJECT_SLOT 24
338-
#define SPEC_FAIL_ATTR_HAS_MANAGED_DICT 25
339338
#define SPEC_FAIL_ATTR_INSTANCE_ATTRIBUTE 26
340339
#define SPEC_FAIL_ATTR_METACLASS_ATTRIBUTE 27
341340
#define SPEC_FAIL_ATTR_PROPERTY_NOT_PY_FUNCTION 28
@@ -1036,11 +1035,14 @@ PyObject *descr, DescriptorClassification kind)
10361035
PyDictKeysObject *keys;
10371036
if (owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
10381037
PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
1039-
keys = ((PyHeapTypeObject *)owner_cls)->ht_cached_keys;
10401038
if (_PyDictOrValues_IsValues(dorv)) {
1039+
keys = ((PyHeapTypeObject *)owner_cls)->ht_cached_keys;
10411040
dictkind = MANAGED_VALUES;
10421041
}
10431042
else {
1043+
PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv);
1044+
keys = dict != NULL ? dict->ma_keys : NULL;
1045+
// User has directly accessed __dict__.
10441046
dictkind = MANAGED_DICT;
10451047
}
10461048
}
@@ -1067,7 +1069,7 @@ PyObject *descr, DescriptorClassification kind)
10671069
}
10681070
}
10691071
}
1070-
if (dictkind == MANAGED_VALUES || dictkind == OFFSET_DICT) {
1072+
if (dictkind == MANAGED_VALUES || dictkind == OFFSET_DICT || (dictkind == MANAGED_DICT && keys != NULL)) {
10711073
Py_ssize_t index = _PyDictKeys_StringLookup(keys, name);
10721074
if (index != DKIX_EMPTY) {
10731075
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_SHADOWED);
@@ -1088,8 +1090,11 @@ PyObject *descr, DescriptorClassification kind)
10881090
_py_set_opcode(instr, LOAD_ATTR_METHOD_WITH_VALUES);
10891091
break;
10901092
case MANAGED_DICT:
1091-
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_HAS_MANAGED_DICT);
1092-
goto fail;
1093+
if (keys == NULL) {
1094+
write_u32(cache->keys_version, 0);
1095+
}
1096+
_py_set_opcode(instr, LOAD_ATTR_METHOD_MANAGED_DICT);
1097+
break;
10931098
case OFFSET_DICT:
10941099
assert(owner_cls->tp_dictoffset > 0 && owner_cls->tp_dictoffset <= INT16_MAX);
10951100
_py_set_opcode(instr, LOAD_ATTR_METHOD_WITH_DICT);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.