]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Shrink the LOAD_METHOD cache by one codeunit. (#93537)
authorMark Shannon <mark@hotpy.org>
Tue, 7 Jun 2022 09:28:53 +0000 (10:28 +0100)
committerGitHub <noreply@github.com>
Tue, 7 Jun 2022 09:28:53 +0000 (10:28 +0100)
Include/internal/pycore_code.h
Include/internal/pycore_opcode.h
Lib/importlib/_bootstrap_external.py
Lib/opcode.py
Lib/test/test_dis.py
Misc/NEWS.d/next/Core and Builtins/2022-06-06-14-28-24.gh-issue-93533.lnC0CC.rst [new file with mode: 0644]
Python/ceval.c
Python/specialize.c

index 9d33ed71e7890702c0c670dd6cfb220091f48fe3..c181543722f6e0c5d0d428a89864dff6c40f244a 100644 (file)
@@ -65,7 +65,6 @@ typedef struct {
 typedef struct {
     _Py_CODEUNIT counter;
     _Py_CODEUNIT type_version[2];
-    _Py_CODEUNIT dict_offset;
     _Py_CODEUNIT keys_version[2];
     _Py_CODEUNIT descr[4];
 } _PyLoadMethodCache;
index e5d948dd696a2b440f3e93ef218852183cb5eed4..e254537da763a24a4b33c32090204a188cbf2417 100644 (file)
@@ -49,7 +49,7 @@ const uint8_t _PyOpcode_Caches[256] = {
     [COMPARE_OP] = 2,
     [LOAD_GLOBAL] = 5,
     [BINARY_OP] = 1,
-    [LOAD_METHOD] = 10,
+    [LOAD_METHOD] = 9,
     [CALL] = 4,
 };
 
index 894848a15d97d843fd17a9c998d68c04ad0164b7..1b6654202f3d754f69eccc7c5849bb2883e3eda3 100644 (file)
@@ -407,6 +407,7 @@ _code_type = type(_write_atomic.__code__)
 #     Python 3.12a1 3500 (Remove PRECALL opcode)
 #     Python 3.12a1 3501 (YIELD_VALUE oparg == stack_depth)
 #     Python 3.12a1 3502 (LOAD_FAST_CHECK, no NULL-check in LOAD_FAST)
+#     Python 3.12a1 3503 (Shrink LOAD_METHOD cache)
 
 #     Python 3.13 will start with 3550
 
@@ -420,7 +421,7 @@ _code_type = type(_write_atomic.__code__)
 # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
 # in PC/launcher.c must also be updated.
 
-MAGIC_NUMBER = (3502).to_bytes(2, 'little') + b'\r\n'
+MAGIC_NUMBER = (3503).to_bytes(2, 'little') + b'\r\n'
 
 _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little')  # For import.c
 
index 5cbb5c57521ae3e8ce2d4d47968c954af5e44b25..0996cc7eb0f6cd3407543b1996994f1bf61d3694 100644 (file)
@@ -383,7 +383,6 @@ _cache_format = {
     "LOAD_METHOD": {
         "counter": 1,
         "type_version": 2,
-        "dict_offset": 1,
         "keys_version": 2,
         "descr": 4,
     },
index a4f7f84995bf5f9d9e236decc2150cb759ec5a81..a94cd6432e123256f17430efb643bfa827a5ad14 100644 (file)
@@ -1047,7 +1047,7 @@ class DisTests(DisTestBase):
                     for cache in caches:
                         self.assertRegex(cache, pattern)
                     self.assertEqual(caches.count(""), 8)
-                    self.assertEqual(len(caches), 23)
+                    self.assertEqual(len(caches), 22)
 
 
 class DisWithFileTests(DisTests):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-06-14-28-24.gh-issue-93533.lnC0CC.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-06-14-28-24.gh-issue-93533.lnC0CC.rst
new file mode 100644 (file)
index 0000000..2d8ac70
--- /dev/null
@@ -0,0 +1 @@
+Reduce the size of the inline cache for ``LOAD_METHOD`` by 2 bytes.
index ec86c70673ca9ad51ccffa052eb70a3fdbb1c3ef..d1480ac190ea412aaa75c9890415dfb8bdad9bda 100644 (file)
@@ -4581,12 +4581,9 @@ handle_eval_breaker:
             DEOPT_IF(self_cls->tp_version_tag != read_u32(cache->type_version),
                      LOAD_METHOD);
             /* Treat index as a signed 16 bit value */
-            int dictoffset = *(int16_t *)&cache->dict_offset;
+            int dictoffset = self_cls->tp_dictoffset;
+            assert(dictoffset > 0);
             PyDictObject **dictptr = (PyDictObject**)(((char *)self)+dictoffset);
-            assert(
-                dictoffset == MANAGED_DICT_OFFSET ||
-                (dictoffset == self_cls->tp_dictoffset && dictoffset > 0)
-            );
             PyDictObject *dict = *dictptr;
             DEOPT_IF(dict == NULL, LOAD_METHOD);
             DEOPT_IF(dict->ma_keys->dk_version != read_u32(cache->keys_version),
@@ -4628,9 +4625,9 @@ handle_eval_breaker:
             _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr;
             uint32_t type_version = read_u32(cache->type_version);
             DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_METHOD);
-            int dictoffset = cache->dict_offset;
+            int dictoffset = self_cls->tp_dictoffset;
+            assert(dictoffset > 0);
             PyObject *dict = *(PyObject **)((char *)self + dictoffset);
-            assert(dictoffset == self_cls->tp_dictoffset && dictoffset > 0);
             /* This object has a __dict__, just not yet created */
             DEOPT_IF(dict != NULL, LOAD_METHOD);
             STAT_INC(LOAD_METHOD, hit);
index 4d30a2aea5f3be74f547622d3f46af1bcb73de42..1df281a19a41ea9a7c4e3d46fd14f9f1b5288374 100644 (file)
@@ -986,7 +986,7 @@ _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
             }
         }
     }
-    if (dictkind == MANAGED_VALUES || dictkind == MANAGED_DICT || dictkind == OFFSET_DICT) {
+    if (dictkind == MANAGED_VALUES || dictkind == OFFSET_DICT) {
         Py_ssize_t index = _PyDictKeys_StringLookup(keys, name);
         if (index != DKIX_EMPTY) {
             SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_LOAD_METHOD_IS_ATTR);
@@ -1007,17 +1007,14 @@ _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
             _Py_SET_OPCODE(*instr, LOAD_METHOD_WITH_VALUES);
             break;
         case MANAGED_DICT:
-            *(int16_t *)&cache->dict_offset = (int16_t)MANAGED_DICT_OFFSET;
-            _Py_SET_OPCODE(*instr, LOAD_METHOD_WITH_DICT);
-            break;
+            SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_LOAD_METHOD_HAS_MANAGED_DICT);
+            goto fail;
         case OFFSET_DICT:
             assert(owner_cls->tp_dictoffset > 0 && owner_cls->tp_dictoffset <= INT16_MAX);
-            cache->dict_offset = (uint16_t)owner_cls->tp_dictoffset;
             _Py_SET_OPCODE(*instr, LOAD_METHOD_WITH_DICT);
             break;
         case LAZY_DICT:
             assert(owner_cls->tp_dictoffset > 0 && owner_cls->tp_dictoffset <= INT16_MAX);
-            cache->dict_offset = (uint16_t)owner_cls->tp_dictoffset;
             _Py_SET_OPCODE(*instr, LOAD_METHOD_LAZY_DICT);
             break;
     }