mirror of
https://github.com/python/cpython.git
synced 2025-12-09 10:37:17 +00:00
bpo-46841: Don't use an oparg counter for STORE_SUBSCR (GH-31742)
This commit is contained in:
parent
28f84c72b6
commit
5498a61c7c
7 changed files with 28 additions and 29 deletions
|
|
@ -86,6 +86,12 @@ typedef struct {
|
||||||
|
|
||||||
#define INLINE_CACHE_ENTRIES_PRECALL CACHE_ENTRIES(_PyPrecallCache)
|
#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. */
|
/* Maximum size of code to quicken, in code units. */
|
||||||
#define MAX_SIZE_TO_QUICKEN 10000
|
#define MAX_SIZE_TO_QUICKEN 10000
|
||||||
|
|
||||||
|
|
|
||||||
1
Include/opcode.h
generated
1
Include/opcode.h
generated
|
|
@ -211,6 +211,7 @@ static const uint32_t _PyOpcode_Jump[8] = {
|
||||||
|
|
||||||
const uint8_t _PyOpcode_InlineCacheEntries[256] = {
|
const uint8_t _PyOpcode_InlineCacheEntries[256] = {
|
||||||
[BINARY_SUBSCR] = 4,
|
[BINARY_SUBSCR] = 4,
|
||||||
|
[STORE_SUBSCR] = 1,
|
||||||
[UNPACK_SEQUENCE] = 1,
|
[UNPACK_SEQUENCE] = 1,
|
||||||
[STORE_ATTR] = 4,
|
[STORE_ATTR] = 4,
|
||||||
[LOAD_ATTR] = 4,
|
[LOAD_ATTR] = 4,
|
||||||
|
|
|
||||||
|
|
@ -394,6 +394,7 @@ _code_type = type(_write_atomic.__code__)
|
||||||
# STORE_ATTR)
|
# STORE_ATTR)
|
||||||
# Python 3.11a5 3485 (Add an oparg to GET_AWAITABLE)
|
# Python 3.11a5 3485 (Add an oparg to GET_AWAITABLE)
|
||||||
# Python 3.11a6 3486 (Use inline caching for PRECALL and CALL)
|
# 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
|
# 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
|
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
|
||||||
# in PC/launcher.c must also be updated.
|
# 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
|
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
|
||||||
|
|
||||||
_PYCACHE = '__pycache__'
|
_PYCACHE = '__pycache__'
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ def_op('BEFORE_ASYNC_WITH', 52)
|
||||||
def_op('BEFORE_WITH', 53)
|
def_op('BEFORE_WITH', 53)
|
||||||
def_op('END_ASYNC_FOR', 54)
|
def_op('END_ASYNC_FOR', 54)
|
||||||
|
|
||||||
def_op('STORE_SUBSCR', 60)
|
def_op('STORE_SUBSCR', 60, 1)
|
||||||
def_op('DELETE_SUBSCR', 61)
|
def_op('DELETE_SUBSCR', 61)
|
||||||
|
|
||||||
def_op('GET_ITER', 68)
|
def_op('GET_ITER', 68)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
Modify :opcode:`STORE_SUBSCR` to use an inline cache entry (rather than its
|
||||||
|
oparg) as an adaptive counter.
|
||||||
|
|
@ -2267,13 +2267,16 @@ handle_eval_breaker:
|
||||||
Py_DECREF(v);
|
Py_DECREF(v);
|
||||||
Py_DECREF(container);
|
Py_DECREF(container);
|
||||||
Py_DECREF(sub);
|
Py_DECREF(sub);
|
||||||
if (err != 0)
|
if (err != 0) {
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
|
JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
TARGET(STORE_SUBSCR_ADAPTIVE) {
|
TARGET(STORE_SUBSCR_ADAPTIVE) {
|
||||||
if (oparg == 0) {
|
_PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr;
|
||||||
|
if (cache->counter == 0) {
|
||||||
PyObject *sub = TOP();
|
PyObject *sub = TOP();
|
||||||
PyObject *container = SECOND();
|
PyObject *container = SECOND();
|
||||||
next_instr--;
|
next_instr--;
|
||||||
|
|
@ -2284,8 +2287,7 @@ handle_eval_breaker:
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
STAT_INC(STORE_SUBSCR, deferred);
|
STAT_INC(STORE_SUBSCR, deferred);
|
||||||
// oparg is the adaptive cache counter
|
cache->counter--;
|
||||||
UPDATE_PREV_INSTR_OPARG(next_instr, oparg - 1);
|
|
||||||
JUMP_TO_INSTRUCTION(STORE_SUBSCR);
|
JUMP_TO_INSTRUCTION(STORE_SUBSCR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2312,6 +2314,7 @@ handle_eval_breaker:
|
||||||
Py_DECREF(old_value);
|
Py_DECREF(old_value);
|
||||||
Py_DECREF(sub);
|
Py_DECREF(sub);
|
||||||
Py_DECREF(list);
|
Py_DECREF(list);
|
||||||
|
JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR);
|
||||||
NOTRACE_DISPATCH();
|
NOTRACE_DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2328,6 +2331,7 @@ handle_eval_breaker:
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5520,21 +5524,6 @@ opname ## _miss: \
|
||||||
JUMP_TO_INSTRUCTION(opname); \
|
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(LOAD_ATTR)
|
||||||
MISS_WITH_INLINE_CACHE(STORE_ATTR)
|
MISS_WITH_INLINE_CACHE(STORE_ATTR)
|
||||||
MISS_WITH_INLINE_CACHE(LOAD_GLOBAL)
|
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(COMPARE_OP)
|
||||||
MISS_WITH_INLINE_CACHE(BINARY_SUBSCR)
|
MISS_WITH_INLINE_CACHE(BINARY_SUBSCR)
|
||||||
MISS_WITH_INLINE_CACHE(UNPACK_SEQUENCE)
|
MISS_WITH_INLINE_CACHE(UNPACK_SEQUENCE)
|
||||||
MISS_WITH_OPARG_COUNTER(STORE_SUBSCR)
|
MISS_WITH_INLINE_CACHE(STORE_SUBSCR)
|
||||||
|
|
||||||
binary_subscr_dict_error:
|
binary_subscr_dict_error:
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -301,12 +301,11 @@ optimize(_Py_CODEUNIT *instructions, int len)
|
||||||
uint8_t adaptive_opcode = adaptive_opcodes[opcode];
|
uint8_t adaptive_opcode = adaptive_opcodes[opcode];
|
||||||
if (adaptive_opcode) {
|
if (adaptive_opcode) {
|
||||||
instructions[i] = _Py_MAKECODEUNIT(adaptive_opcode, oparg);
|
instructions[i] = _Py_MAKECODEUNIT(adaptive_opcode, oparg);
|
||||||
int caches = _PyOpcode_InlineCacheEntries[opcode];
|
|
||||||
// Make sure the adaptive counter is zero:
|
// Make sure the adaptive counter is zero:
|
||||||
assert((caches ? instructions[i + 1] : oparg) == 0);
|
assert(instructions[i + 1] == 0);
|
||||||
previous_opcode = -1;
|
previous_opcode = -1;
|
||||||
previous_oparg = -1;
|
previous_oparg = -1;
|
||||||
i += caches;
|
i += _PyOpcode_InlineCacheEntries[opcode];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assert(!_PyOpcode_InlineCacheEntries[opcode]);
|
assert(!_PyOpcode_InlineCacheEntries[opcode]);
|
||||||
|
|
@ -1313,6 +1312,7 @@ success:
|
||||||
int
|
int
|
||||||
_Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr)
|
_Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr)
|
||||||
{
|
{
|
||||||
|
_PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)(instr + 1);
|
||||||
PyTypeObject *container_type = Py_TYPE(container);
|
PyTypeObject *container_type = Py_TYPE(container);
|
||||||
if (container_type == &PyList_Type) {
|
if (container_type == &PyList_Type) {
|
||||||
if (PyLong_CheckExact(sub)) {
|
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))
|
&& ((PyLongObject *)sub)->ob_digit[0] < (size_t)PyList_GET_SIZE(container))
|
||||||
{
|
{
|
||||||
*instr = _Py_MAKECODEUNIT(STORE_SUBSCR_LIST_INT,
|
*instr = _Py_MAKECODEUNIT(STORE_SUBSCR_LIST_INT,
|
||||||
initial_counter_value());
|
_Py_OPARG(*instr));
|
||||||
goto success;
|
goto success;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -1338,8 +1338,7 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (container_type == &PyDict_Type) {
|
if (container_type == &PyDict_Type) {
|
||||||
*instr = _Py_MAKECODEUNIT(STORE_SUBSCR_DICT,
|
*instr = _Py_MAKECODEUNIT(STORE_SUBSCR_DICT, _Py_OPARG(*instr));
|
||||||
initial_counter_value());
|
|
||||||
goto success;
|
goto success;
|
||||||
}
|
}
|
||||||
#ifdef Py_STATS
|
#ifdef Py_STATS
|
||||||
|
|
@ -1406,11 +1405,12 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins
|
||||||
fail:
|
fail:
|
||||||
STAT_INC(STORE_SUBSCR, failure);
|
STAT_INC(STORE_SUBSCR, failure);
|
||||||
assert(!PyErr_Occurred());
|
assert(!PyErr_Occurred());
|
||||||
*instr = _Py_MAKECODEUNIT(_Py_OPCODE(*instr), ADAPTIVE_CACHE_BACKOFF);
|
cache->counter = ADAPTIVE_CACHE_BACKOFF;
|
||||||
return 0;
|
return 0;
|
||||||
success:
|
success:
|
||||||
STAT_INC(STORE_SUBSCR, success);
|
STAT_INC(STORE_SUBSCR, success);
|
||||||
assert(!PyErr_Occurred());
|
assert(!PyErr_Occurred());
|
||||||
|
cache->counter = initial_counter_value();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue