Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 5498a61

Browse files
authoredMar 8, 2022
bpo-46841: Don't use an oparg counter for STORE_SUBSCR (pythonGH-31742)
1 parent 28f84c7 commit 5498a61

File tree

7 files changed

+28
-29
lines changed

7 files changed

+28
-29
lines changed
 

‎Include/internal/pycore_code.h

+6
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ typedef struct {
8686

8787
#define INLINE_CACHE_ENTRIES_PRECALL CACHE_ENTRIES(_PyPrecallCache)
8888

89+
typedef struct {
90+
_Py_CODEUNIT counter;
91+
} _PyStoreSubscrCache;
92+
93+
#define INLINE_CACHE_ENTRIES_STORE_SUBSCR CACHE_ENTRIES(_PyStoreSubscrCache)
94+
8995
/* Maximum size of code to quicken, in code units. */
9096
#define MAX_SIZE_TO_QUICKEN 10000
9197

‎Include/opcode.h

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Lib/importlib/_bootstrap_external.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ def _write_atomic(path, data, mode=0o666):
394394
# STORE_ATTR)
395395
# Python 3.11a5 3485 (Add an oparg to GET_AWAITABLE)
396396
# Python 3.11a6 3486 (Use inline caching for PRECALL and CALL)
397+
# Python 3.11a6 3487 (Remove the adaptive "oparg counter" mechanism)
397398

398399
# Python 3.12 will start with magic number 3500
399400

@@ -408,7 +409,7 @@ def _write_atomic(path, data, mode=0o666):
408409
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
409410
# in PC/launcher.c must also be updated.
410411

411-
MAGIC_NUMBER = (3486).to_bytes(2, 'little') + b'\r\n'
412+
MAGIC_NUMBER = (3487).to_bytes(2, 'little') + b'\r\n'
412413
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
413414

414415
_PYCACHE = '__pycache__'

‎Lib/opcode.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def jabs_op(name, op, entries=0):
8484
def_op('BEFORE_WITH', 53)
8585
def_op('END_ASYNC_FOR', 54)
8686

87-
def_op('STORE_SUBSCR', 60)
87+
def_op('STORE_SUBSCR', 60, 1)
8888
def_op('DELETE_SUBSCR', 61)
8989

9090
def_op('GET_ITER', 68)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Modify :opcode:`STORE_SUBSCR` to use an inline cache entry (rather than its
2+
oparg) as an adaptive counter.

‎Python/ceval.c

+9-20
Original file line numberDiff line numberDiff line change
@@ -2267,13 +2267,16 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
22672267
Py_DECREF(v);
22682268
Py_DECREF(container);
22692269
Py_DECREF(sub);
2270-
if (err != 0)
2270+
if (err != 0) {
22712271
goto error;
2272+
}
2273+
JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR);
22722274
DISPATCH();
22732275
}
22742276

22752277
TARGET(STORE_SUBSCR_ADAPTIVE) {
2276-
if (oparg == 0) {
2278+
_PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr;
2279+
if (cache->counter == 0) {
22772280
PyObject *sub = TOP();
22782281
PyObject *container = SECOND();
22792282
next_instr--;
@@ -2284,8 +2287,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
22842287
}
22852288
else {
22862289
STAT_INC(STORE_SUBSCR, deferred);
2287-
// oparg is the adaptive cache counter
2288-
UPDATE_PREV_INSTR_OPARG(next_instr, oparg - 1);
2290+
cache->counter--;
22892291
JUMP_TO_INSTRUCTION(STORE_SUBSCR);
22902292
}
22912293
}
@@ -2312,6 +2314,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
23122314
Py_DECREF(old_value);
23132315
Py_DECREF(sub);
23142316
Py_DECREF(list);
2317+
JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR);
23152318
NOTRACE_DISPATCH();
23162319
}
23172320

@@ -2328,6 +2331,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
23282331
if (err != 0) {
23292332
goto error;
23302333
}
2334+
JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR);
23312335
DISPATCH();
23322336
}
23332337

@@ -5520,21 +5524,6 @@ opname ## _miss: \
55205524
JUMP_TO_INSTRUCTION(opname); \
55215525
}
55225526

5523-
#define MISS_WITH_OPARG_COUNTER(opname) \
5524-
opname ## _miss: \
5525-
{ \
5526-
STAT_INC(opname, miss); \
5527-
uint8_t oparg = _Py_OPARG(next_instr[-1])-1; \
5528-
UPDATE_PREV_INSTR_OPARG(next_instr, oparg); \
5529-
assert(_Py_OPARG(next_instr[-1]) == oparg); \
5530-
if (oparg == 0) /* too many cache misses */ { \
5531-
oparg = ADAPTIVE_CACHE_BACKOFF; \
5532-
next_instr[-1] = _Py_MAKECODEUNIT(opname ## _ADAPTIVE, oparg); \
5533-
STAT_INC(opname, deopt); \
5534-
} \
5535-
JUMP_TO_INSTRUCTION(opname); \
5536-
}
5537-
55385527
MISS_WITH_INLINE_CACHE(LOAD_ATTR)
55395528
MISS_WITH_INLINE_CACHE(STORE_ATTR)
55405529
MISS_WITH_INLINE_CACHE(LOAD_GLOBAL)
@@ -5545,7 +5534,7 @@ MISS_WITH_INLINE_CACHE(BINARY_OP)
55455534
MISS_WITH_INLINE_CACHE(COMPARE_OP)
55465535
MISS_WITH_INLINE_CACHE(BINARY_SUBSCR)
55475536
MISS_WITH_INLINE_CACHE(UNPACK_SEQUENCE)
5548-
MISS_WITH_OPARG_COUNTER(STORE_SUBSCR)
5537+
MISS_WITH_INLINE_CACHE(STORE_SUBSCR)
55495538

55505539
binary_subscr_dict_error:
55515540
{

‎Python/specialize.c

+7-7
Original file line numberDiff line numberDiff line change
@@ -301,12 +301,11 @@ optimize(_Py_CODEUNIT *instructions, int len)
301301
uint8_t adaptive_opcode = adaptive_opcodes[opcode];
302302
if (adaptive_opcode) {
303303
instructions[i] = _Py_MAKECODEUNIT(adaptive_opcode, oparg);
304-
int caches = _PyOpcode_InlineCacheEntries[opcode];
305304
// Make sure the adaptive counter is zero:
306-
assert((caches ? instructions[i + 1] : oparg) == 0);
305+
assert(instructions[i + 1] == 0);
307306
previous_opcode = -1;
308307
previous_oparg = -1;
309-
i += caches;
308+
i += _PyOpcode_InlineCacheEntries[opcode];
310309
}
311310
else {
312311
assert(!_PyOpcode_InlineCacheEntries[opcode]);
@@ -1313,14 +1312,15 @@ _Py_Specialize_BinarySubscr(
13131312
int
13141313
_Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr)
13151314
{
1315+
_PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)(instr + 1);
13161316
PyTypeObject *container_type = Py_TYPE(container);
13171317
if (container_type == &PyList_Type) {
13181318
if (PyLong_CheckExact(sub)) {
13191319
if ((Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1)
13201320
&& ((PyLongObject *)sub)->ob_digit[0] < (size_t)PyList_GET_SIZE(container))
13211321
{
13221322
*instr = _Py_MAKECODEUNIT(STORE_SUBSCR_LIST_INT,
1323-
initial_counter_value());
1323+
_Py_OPARG(*instr));
13241324
goto success;
13251325
}
13261326
else {
@@ -1338,8 +1338,7 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins
13381338
}
13391339
}
13401340
if (container_type == &PyDict_Type) {
1341-
*instr = _Py_MAKECODEUNIT(STORE_SUBSCR_DICT,
1342-
initial_counter_value());
1341+
*instr = _Py_MAKECODEUNIT(STORE_SUBSCR_DICT, _Py_OPARG(*instr));
13431342
goto success;
13441343
}
13451344
#ifdef Py_STATS
@@ -1406,11 +1405,12 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins
14061405
fail:
14071406
STAT_INC(STORE_SUBSCR, failure);
14081407
assert(!PyErr_Occurred());
1409-
*instr = _Py_MAKECODEUNIT(_Py_OPCODE(*instr), ADAPTIVE_CACHE_BACKOFF);
1408+
cache->counter = ADAPTIVE_CACHE_BACKOFF;
14101409
return 0;
14111410
success:
14121411
STAT_INC(STORE_SUBSCR, success);
14131412
assert(!PyErr_Occurred());
1413+
cache->counter = initial_counter_value();
14141414
return 0;
14151415
}
14161416

0 commit comments

Comments
 (0)
Failed to load comments.