summaryrefslogtreecommitdiffstats
path: root/Python/specialize.c
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2024-04-02 10:59:21 (GMT)
committerGitHub <noreply@github.com>2024-04-02 10:59:21 (GMT)
commitc32dc47aca6e8fac152699bc613e015c44ccdba9 (patch)
treee183f7c56ad5e081879c3dd75f7e11887fe7e26c /Python/specialize.c
parentc97d3af2391e62ef456ef2365d48ab9b8cdbe27b (diff)
downloadcpython-c32dc47aca6e8fac152699bc613e015c44ccdba9.zip
cpython-c32dc47aca6e8fac152699bc613e015c44ccdba9.tar.gz
cpython-c32dc47aca6e8fac152699bc613e015c44ccdba9.tar.bz2
GH-115776: Embed the values array into the object, for "normal" Python objects. (GH-116115)
Diffstat (limited to 'Python/specialize.c')
-rw-r--r--Python/specialize.c51
1 files changed, 25 insertions, 26 deletions
diff --git a/Python/specialize.c b/Python/specialize.c
index c1edf88..f1e32d0 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -188,7 +188,7 @@ print_object_stats(FILE *out, ObjectStats *stats)
fprintf(out, "Object allocations to 4 kbytes: %" PRIu64 "\n", stats->allocations4k);
fprintf(out, "Object allocations over 4 kbytes: %" PRIu64 "\n", stats->allocations_big);
fprintf(out, "Object frees: %" PRIu64 "\n", stats->frees);
- fprintf(out, "Object new values: %" PRIu64 "\n", stats->new_values);
+ fprintf(out, "Object inline values: %" PRIu64 "\n", stats->inline_values);
fprintf(out, "Object interpreter increfs: %" PRIu64 "\n", stats->interpreter_increfs);
fprintf(out, "Object interpreter decrefs: %" PRIu64 "\n", stats->interpreter_decrefs);
fprintf(out, "Object increfs: %" PRIu64 "\n", stats->increfs);
@@ -197,7 +197,6 @@ print_object_stats(FILE *out, ObjectStats *stats)
fprintf(out, "Object materialize dict (new key): %" PRIu64 "\n", stats->dict_materialized_new_key);
fprintf(out, "Object materialize dict (too big): %" PRIu64 "\n", stats->dict_materialized_too_big);
fprintf(out, "Object materialize dict (str subclass): %" PRIu64 "\n", stats->dict_materialized_str_subclass);
- fprintf(out, "Object dematerialize dict: %" PRIu64 "\n", stats->dict_dematerialized);
fprintf(out, "Object method cache hits: %" PRIu64 "\n", stats->type_cache_hits);
fprintf(out, "Object method cache misses: %" PRIu64 "\n", stats->type_cache_misses);
fprintf(out, "Object method cache collisions: %" PRIu64 "\n", stats->type_cache_collisions);
@@ -479,12 +478,11 @@ _PyCode_Quicken(PyCodeObject *code)
#define SPEC_FAIL_ATTR_NOT_MANAGED_DICT 18
#define SPEC_FAIL_ATTR_NON_STRING_OR_SPLIT 19
#define SPEC_FAIL_ATTR_MODULE_ATTR_NOT_FOUND 20
-
#define SPEC_FAIL_ATTR_SHADOWED 21
#define SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD 22
#define SPEC_FAIL_ATTR_CLASS_METHOD_OBJ 23
#define SPEC_FAIL_ATTR_OBJECT_SLOT 24
-#define SPEC_FAIL_ATTR_HAS_MANAGED_DICT 25
+
#define SPEC_FAIL_ATTR_INSTANCE_ATTRIBUTE 26
#define SPEC_FAIL_ATTR_METACLASS_ATTRIBUTE 27
#define SPEC_FAIL_ATTR_PROPERTY_NOT_PY_FUNCTION 28
@@ -558,6 +556,7 @@ _PyCode_Quicken(PyCodeObject *code)
#define SPEC_FAIL_CALL_OPERATOR_WRAPPER 29
#define SPEC_FAIL_CALL_INIT_NOT_SIMPLE 30
#define SPEC_FAIL_CALL_METACLASS 31
+#define SPEC_FAIL_CALL_INIT_NOT_INLINE_VALUES 32
/* COMPARE_OP */
#define SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES 12
@@ -829,11 +828,7 @@ specialize_dict_access(
return 0;
}
_PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
- PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner);
- if (_PyDictOrValues_IsValues(*dorv) ||
- _PyObject_MakeInstanceAttributesFromDict(owner, dorv))
- {
- // Virtual dictionary
+ if (type->tp_flags & Py_TPFLAGS_INLINE_VALUES && _PyObject_InlineValues(owner)->valid) {
PyDictKeysObject *keys = ((PyHeapTypeObject *)type)->ht_cached_keys;
assert(PyUnicode_CheckExact(name));
Py_ssize_t index = _PyDictKeys_StringLookup(keys, name);
@@ -850,7 +845,8 @@ specialize_dict_access(
instr->op.code = values_op;
}
else {
- PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(*dorv);
+ PyManagedDictPointer *managed_dict = _PyObject_ManagedDictPointer(owner);
+ PyDictObject *dict = managed_dict->dict;
if (dict == NULL || !PyDict_CheckExact(dict)) {
SPECIALIZATION_FAIL(base_op, SPEC_FAIL_NO_DICT);
return 0;
@@ -1258,15 +1254,8 @@ PyObject *descr, DescriptorClassification kind, bool is_method)
assert(descr != NULL);
assert((is_method && kind == METHOD) || (!is_method && kind == NON_DESCRIPTOR));
- if (owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
- PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner);
+ if (owner_cls->tp_flags & Py_TPFLAGS_INLINE_VALUES) {
PyDictKeysObject *keys = ((PyHeapTypeObject *)owner_cls)->ht_cached_keys;
- if (!_PyDictOrValues_IsValues(*dorv) &&
- !_PyObject_MakeInstanceAttributesFromDict(owner, dorv))
- {
- SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_HAS_MANAGED_DICT);
- return 0;
- }
Py_ssize_t index = _PyDictKeys_StringLookup(keys, name);
if (index != DKIX_EMPTY) {
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_SHADOWED);
@@ -1282,10 +1271,16 @@ PyObject *descr, DescriptorClassification kind, bool is_method)
instr->op.code = is_method ? LOAD_ATTR_METHOD_WITH_VALUES : LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES;
}
else {
- Py_ssize_t dictoffset = owner_cls->tp_dictoffset;
- if (dictoffset < 0 || dictoffset > INT16_MAX) {
- SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE);
- return 0;
+ Py_ssize_t dictoffset;
+ if (owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
+ dictoffset = MANAGED_DICT_OFFSET;
+ }
+ else {
+ dictoffset = owner_cls->tp_dictoffset;
+ if (dictoffset < 0 || dictoffset > INT16_MAX + MANAGED_DICT_OFFSET) {
+ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE);
+ return 0;
+ }
}
if (dictoffset == 0) {
instr->op.code = is_method ? LOAD_ATTR_METHOD_NO_DICT : LOAD_ATTR_NONDESCRIPTOR_NO_DICT;
@@ -1296,8 +1291,12 @@ PyObject *descr, DescriptorClassification kind, bool is_method)
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NOT_MANAGED_DICT);
return 0;
}
- assert(owner_cls->tp_dictoffset > 0);
- assert(owner_cls->tp_dictoffset <= INT16_MAX);
+ /* Cache entries must be unsigned values, so we offset the
+ * dictoffset by MANAGED_DICT_OFFSET.
+ * We do the reverese offset in LOAD_ATTR_METHOD_LAZY_DICT */
+ dictoffset -= MANAGED_DICT_OFFSET;
+ assert(((uint16_t)dictoffset) == dictoffset);
+ cache->dict_offset = (uint16_t)dictoffset;
instr->op.code = LOAD_ATTR_METHOD_LAZY_DICT;
}
else {
@@ -1729,8 +1728,8 @@ get_init_for_simple_managed_python_class(PyTypeObject *tp)
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OVERRIDDEN);
return NULL;
}
- if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
- SPECIALIZATION_FAIL(CALL, SPEC_FAIL_NO_DICT);
+ if ((tp->tp_flags & Py_TPFLAGS_INLINE_VALUES) == 0) {
+ SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_INIT_NOT_INLINE_VALUES);
return NULL;
}
if (!(tp->tp_flags & Py_TPFLAGS_HEAPTYPE)) {