From 5498a61c7c25db6f9e76032aa9c5153d79e09889 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Tue, 8 Mar 2022 07:53:22 -0800 Subject: bpo-46841: Don't use an oparg counter for `STORE_SUBSCR` (GH-31742) --- Include/internal/pycore_code.h | 6 +++++ Include/opcode.h | 1 + Lib/importlib/_bootstrap_external.py | 3 ++- Lib/opcode.py | 2 +- .../2022-03-07-15-54-39.bpo-46841.7wG92r.rst | 2 ++ Python/ceval.c | 29 +++++++--------------- Python/specialize.c | 14 +++++------ 7 files changed, 28 insertions(+), 29 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-03-07-15-54-39.bpo-46841.7wG92r.rst diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 21c657a..0d324e9 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -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 diff --git a/Include/opcode.h b/Include/opcode.h index 930a975..7bf0ba7 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -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, diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 32a41f8..a6f0a1b 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -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__' diff --git a/Lib/opcode.py b/Lib/opcode.py index a31a77a..eb9dd35 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -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 index 0000000..f863c75 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-03-07-15-54-39.bpo-46841.7wG92r.rst @@ -0,0 +1,2 @@ +Modify :opcode:`STORE_SUBSCR` to use an inline cache entry (rather than its +oparg) as an adaptive counter. diff --git a/Python/ceval.c b/Python/ceval.c index b15c101..83309e2 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -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: { diff --git a/Python/specialize.c b/Python/specialize.c index dae4e3f..a11a76c 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -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; } -- cgit v0.12