Skip to content

Commit 14e75f1

Browse files
committed
Demonstrate cache effect with BINARY_SUBSCR
This was a bin subtle, esp. BINARY_SUBSCR_DICT (which plays games with refcounts) and BINARY_SUBSCR_GETITEM (which ends with a goto).
1 parent d682118 commit 14e75f1

File tree

2 files changed

+59
-64
lines changed

2 files changed

+59
-64
lines changed

Python/bytecodes.c

Lines changed: 25 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ do { \
7979
// Dummy variables for stack effects.
8080
static PyObject *value, *value1, *value2, *left, *right, *res, *sum, *prod, *sub;
8181
static PyObject *container, *start, *stop, *v, *lhs, *rhs;
82+
static PyObject *list, *tuple, *dict;
8283

8384
static PyObject *
8485
dummy_func(
@@ -323,7 +324,15 @@ dummy_func(
323324
ERROR_IF(sum == NULL, error);
324325
}
325326

326-
inst(BINARY_SUBSCR, (container, sub -- res)) {
327+
family(binary_subscr, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = {
328+
BINARY_SUBSCR,
329+
BINARY_SUBSCR_DICT,
330+
BINARY_SUBSCR_GETITEM,
331+
BINARY_SUBSCR_LIST_INT,
332+
BINARY_SUBSCR_TUPLE_INT,
333+
};
334+
335+
inst(BINARY_SUBSCR, (container, sub, unused/4 -- res)) {
327336
_PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr;
328337
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
329338
assert(cframe.use_tracing == 0);
@@ -337,7 +346,6 @@ dummy_func(
337346
Py_DECREF(container);
338347
Py_DECREF(sub);
339348
ERROR_IF(res == NULL, error);
340-
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
341349
}
342350

343351
inst(BINARY_SLICE, (container, start, stop -- res)) {
@@ -370,11 +378,8 @@ dummy_func(
370378
ERROR_IF(err, error);
371379
}
372380

373-
// stack effect: (__0 -- )
374-
inst(BINARY_SUBSCR_LIST_INT) {
381+
inst(BINARY_SUBSCR_LIST_INT, (list, sub, unused/4 -- res)) {
375382
assert(cframe.use_tracing == 0);
376-
PyObject *sub = TOP();
377-
PyObject *list = SECOND();
378383
DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR);
379384
DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR);
380385

@@ -385,21 +390,15 @@ dummy_func(
385390
Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0];
386391
DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR);
387392
STAT_INC(BINARY_SUBSCR, hit);
388-
PyObject *res = PyList_GET_ITEM(list, index);
393+
res = PyList_GET_ITEM(list, index);
389394
assert(res != NULL);
390395
Py_INCREF(res);
391-
STACK_SHRINK(1);
392396
_Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free);
393-
SET_TOP(res);
394397
Py_DECREF(list);
395-
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
396398
}
397399

398-
// stack effect: (__0 -- )
399-
inst(BINARY_SUBSCR_TUPLE_INT) {
400+
inst(BINARY_SUBSCR_TUPLE_INT, (tuple, sub, unused/4 -- res)) {
400401
assert(cframe.use_tracing == 0);
401-
PyObject *sub = TOP();
402-
PyObject *tuple = SECOND();
403402
DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR);
404403
DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR);
405404

@@ -410,51 +409,40 @@ dummy_func(
410409
Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0];
411410
DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR);
412411
STAT_INC(BINARY_SUBSCR, hit);
413-
PyObject *res = PyTuple_GET_ITEM(tuple, index);
412+
res = PyTuple_GET_ITEM(tuple, index);
414413
assert(res != NULL);
415414
Py_INCREF(res);
416-
STACK_SHRINK(1);
417415
_Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free);
418-
SET_TOP(res);
419416
Py_DECREF(tuple);
420-
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
421417
}
422418

423-
// stack effect: (__0 -- )
424-
inst(BINARY_SUBSCR_DICT) {
419+
inst(BINARY_SUBSCR_DICT, (dict, sub, unused/4 -- res)) {
425420
assert(cframe.use_tracing == 0);
426-
PyObject *dict = SECOND();
427-
DEOPT_IF(!PyDict_CheckExact(SECOND()), BINARY_SUBSCR);
421+
DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR);
428422
STAT_INC(BINARY_SUBSCR, hit);
429-
PyObject *sub = TOP();
430-
PyObject *res = PyDict_GetItemWithError(dict, sub);
423+
res = PyDict_GetItemWithError(dict, sub);
424+
Py_DECREF(dict);
431425
if (res == NULL) {
432426
if (!_PyErr_Occurred(tstate)) {
433427
_PyErr_SetKeyError(sub);
434428
}
435-
goto error;
429+
else {
430+
Py_DECREF(sub);
431+
}
432+
ERROR_IF(1, error);
436433
}
437-
Py_INCREF(res);
438-
STACK_SHRINK(1);
439434
Py_DECREF(sub);
440-
SET_TOP(res);
441-
Py_DECREF(dict);
442-
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
435+
Py_INCREF(res);
443436
}
444437

445-
// stack effect: (__0 -- )
446-
inst(BINARY_SUBSCR_GETITEM) {
447-
PyObject *sub = TOP();
448-
PyObject *container = SECOND();
449-
_PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr;
450-
uint32_t type_version = read_u32(cache->type_version);
438+
inst(BINARY_SUBSCR_GETITEM, (container, sub, unused/1, type_version/2, func_version/1 -- unused)) {
451439
PyTypeObject *tp = Py_TYPE(container);
452440
DEOPT_IF(tp->tp_version_tag != type_version, BINARY_SUBSCR);
453441
assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE);
454442
PyObject *cached = ((PyHeapTypeObject *)tp)->_spec_cache.getitem;
455443
assert(PyFunction_Check(cached));
456444
PyFunctionObject *getitem = (PyFunctionObject *)cached;
457-
DEOPT_IF(getitem->func_version != cache->func_version, BINARY_SUBSCR);
445+
DEOPT_IF(getitem->func_version != func_version, BINARY_SUBSCR);
458446
PyCodeObject *code = (PyCodeObject *)getitem->func_code;
459447
assert(code->co_argcount == 2);
460448
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), BINARY_SUBSCR);

Python/generated_cases.c.h

Lines changed: 34 additions & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)