]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-46841: Don't use an oparg counter for `STORE_SUBSCR` (GH-31742)
authorBrandt Bucher <brandtbucher@microsoft.com>
Tue, 8 Mar 2022 15:53:22 +0000 (07:53 -0800)
committerGitHub <noreply@github.com>
Tue, 8 Mar 2022 15:53:22 +0000 (15:53 +0000)
Include/internal/pycore_code.h
Include/opcode.h
Lib/importlib/_bootstrap_external.py
Lib/opcode.py
Misc/NEWS.d/next/Core and Builtins/2022-03-07-15-54-39.bpo-46841.7wG92r.rst [new file with mode: 0644]
Python/ceval.c
Python/specialize.c

index 21c657afed6c8f9d8cae5bc606f71fa3516da47c..0d324e9e4c0f59824780aad69113d9ca4e5ba725 100644 (file)
@@ -86,6 +86,12 @@ typedef struct {
 
 #define INLINE_CACHE_ENTRIES_PRECALL CACHE_ENTRIES(_PyPrecallCache)
 
+typedef struct {
+    _Py_CODEUNIT counter;
+} _PyStoreSubscrCache;
+
+#define INLINE_CACHE_ENTRIES_STORE_SUBSCR CACHE_ENTRIES(_PyStoreSubscrCache)
+
 /* Maximum size of code to quicken, in code units. */
 #define MAX_SIZE_TO_QUICKEN 10000
 
index 930a975897e293dbe96fae75ec3b5b88d5434886..7bf0ba70fd7de0e399baf83e366741583534961c 100644 (file)
@@ -211,6 +211,7 @@ static const uint32_t _PyOpcode_Jump[8] = {
 
 const uint8_t _PyOpcode_InlineCacheEntries[256] = {
     [BINARY_SUBSCR] = 4,
+    [STORE_SUBSCR] = 1,
     [UNPACK_SEQUENCE] = 1,
     [STORE_ATTR] = 4,
     [LOAD_ATTR] = 4,
index 32a41f852e5d7ef594b4cd89923b93877a3ec755..a6f0a1b3c4c7d8089d38fa45b4d563750bd22504 100644 (file)
@@ -394,6 +394,7 @@ _code_type = type(_write_atomic.__code__)
 #                         STORE_ATTR)
 #     Python 3.11a5 3485 (Add an oparg to GET_AWAITABLE)
 #     Python 3.11a6 3486 (Use inline caching for PRECALL and CALL)
+#     Python 3.11a6 3487 (Remove the adaptive "oparg counter" mechanism)
 
 #     Python 3.12 will start with magic number 3500
 
@@ -408,7 +409,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 = (3486).to_bytes(2, 'little') + b'\r\n'
+MAGIC_NUMBER = (3487).to_bytes(2, 'little') + b'\r\n'
 _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little')  # For import.c
 
 _PYCACHE = '__pycache__'
index a31a77a61c8af891648f86c8a235f9630d074bda..eb9dd35fabf8d9cc20c71eb0a8402db999c2c0a3 100644 (file)
@@ -84,7 +84,7 @@ def_op('BEFORE_ASYNC_WITH', 52)
 def_op('BEFORE_WITH', 53)
 def_op('END_ASYNC_FOR', 54)
 
-def_op('STORE_SUBSCR', 60)
+def_op('STORE_SUBSCR', 60, 1)
 def_op('DELETE_SUBSCR', 61)
 
 def_op('GET_ITER', 68)
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-03-07-15-54-39.bpo-46841.7wG92r.rst b/Misc/NEWS.d/next/Core and Builtins/2022-03-07-15-54-39.bpo-46841.7wG92r.rst
new file mode 100644 (file)
index 0000000..f863c75
--- /dev/null
@@ -0,0 +1,2 @@
+Modify :opcode:`STORE_SUBSCR` to use an inline cache entry (rather than its
+oparg) as an adaptive counter.
index b15c1015cd24210ff55843bcadc4041f35d37957..83309e2c5219a79497a41da7cbf7c8c5c4eae814 100644 (file)
@@ -2267,13 +2267,16 @@ handle_eval_breaker:
             Py_DECREF(v);
             Py_DECREF(container);
             Py_DECREF(sub);
-            if (err != 0)
+            if (err != 0) {
                 goto error;
+            }
+            JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR);
             DISPATCH();
         }
 
         TARGET(STORE_SUBSCR_ADAPTIVE) {
-            if (oparg == 0) {
+            _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr;
+            if (cache->counter == 0) {
                 PyObject *sub = TOP();
                 PyObject *container = SECOND();
                 next_instr--;
@@ -2284,8 +2287,7 @@ handle_eval_breaker:
             }
             else {
                 STAT_INC(STORE_SUBSCR, deferred);
-                // oparg is the adaptive cache counter
-                UPDATE_PREV_INSTR_OPARG(next_instr, oparg - 1);
+                cache->counter--;
                 JUMP_TO_INSTRUCTION(STORE_SUBSCR);
             }
         }
@@ -2312,6 +2314,7 @@ handle_eval_breaker:
             Py_DECREF(old_value);
             Py_DECREF(sub);
             Py_DECREF(list);
+            JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR);
             NOTRACE_DISPATCH();
         }
 
@@ -2328,6 +2331,7 @@ handle_eval_breaker:
             if (err != 0) {
                 goto error;
             }
+            JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR);
             DISPATCH();
         }
 
@@ -5520,21 +5524,6 @@ opname ## _miss: \
         JUMP_TO_INSTRUCTION(opname); \
     }
 
-#define MISS_WITH_OPARG_COUNTER(opname) \
-opname ## _miss: \
-    { \
-        STAT_INC(opname, miss); \
-        uint8_t oparg = _Py_OPARG(next_instr[-1])-1; \
-        UPDATE_PREV_INSTR_OPARG(next_instr, oparg); \
-        assert(_Py_OPARG(next_instr[-1]) == oparg); \
-        if (oparg == 0) /* too many cache misses */ { \
-            oparg = ADAPTIVE_CACHE_BACKOFF; \
-            next_instr[-1] = _Py_MAKECODEUNIT(opname ## _ADAPTIVE, oparg); \
-            STAT_INC(opname, deopt); \
-        } \
-        JUMP_TO_INSTRUCTION(opname); \
-    }
-
 MISS_WITH_INLINE_CACHE(LOAD_ATTR)
 MISS_WITH_INLINE_CACHE(STORE_ATTR)
 MISS_WITH_INLINE_CACHE(LOAD_GLOBAL)
@@ -5545,7 +5534,7 @@ MISS_WITH_INLINE_CACHE(BINARY_OP)
 MISS_WITH_INLINE_CACHE(COMPARE_OP)
 MISS_WITH_INLINE_CACHE(BINARY_SUBSCR)
 MISS_WITH_INLINE_CACHE(UNPACK_SEQUENCE)
-MISS_WITH_OPARG_COUNTER(STORE_SUBSCR)
+MISS_WITH_INLINE_CACHE(STORE_SUBSCR)
 
 binary_subscr_dict_error:
         {
index dae4e3fa188bd0ef801b624cc26df25f792c62d9..a11a76c4ef118b2fb0998c310a3b95d484c2da71 100644 (file)
@@ -301,12 +301,11 @@ optimize(_Py_CODEUNIT *instructions, int len)
         uint8_t adaptive_opcode = adaptive_opcodes[opcode];
         if (adaptive_opcode) {
             instructions[i] = _Py_MAKECODEUNIT(adaptive_opcode, oparg);
-            int caches = _PyOpcode_InlineCacheEntries[opcode];
             // Make sure the adaptive counter is zero:
-            assert((caches ? instructions[i + 1] : oparg) == 0);
+            assert(instructions[i + 1] == 0);
             previous_opcode = -1;
             previous_oparg = -1;
-            i += caches;
+            i += _PyOpcode_InlineCacheEntries[opcode];
         }
         else {
             assert(!_PyOpcode_InlineCacheEntries[opcode]);
@@ -1313,6 +1312,7 @@ success:
 int
 _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr)
 {
+    _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)(instr + 1);
     PyTypeObject *container_type = Py_TYPE(container);
     if (container_type == &PyList_Type) {
         if (PyLong_CheckExact(sub)) {
@@ -1320,7 +1320,7 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins
                 && ((PyLongObject *)sub)->ob_digit[0] < (size_t)PyList_GET_SIZE(container))
             {
                 *instr = _Py_MAKECODEUNIT(STORE_SUBSCR_LIST_INT,
-                                          initial_counter_value());
+                                          _Py_OPARG(*instr));
                 goto success;
             }
             else {
@@ -1338,8 +1338,7 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins
         }
     }
     if (container_type == &PyDict_Type) {
-        *instr = _Py_MAKECODEUNIT(STORE_SUBSCR_DICT,
-                                  initial_counter_value());
+        *instr = _Py_MAKECODEUNIT(STORE_SUBSCR_DICT, _Py_OPARG(*instr));
          goto success;
     }
 #ifdef Py_STATS
@@ -1406,11 +1405,12 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins
 fail:
     STAT_INC(STORE_SUBSCR, failure);
     assert(!PyErr_Occurred());
-    *instr = _Py_MAKECODEUNIT(_Py_OPCODE(*instr), ADAPTIVE_CACHE_BACKOFF);
+    cache->counter = ADAPTIVE_CACHE_BACKOFF;
     return 0;
 success:
     STAT_INC(STORE_SUBSCR, success);
     assert(!PyErr_Occurred());
+    cache->counter = initial_counter_value();
     return 0;
 }