Skip to main content

Python/ceval.c (part 92)

Source:

cpython 3.14 @ ab2d84fe1023/Python/ceval.c

This annotation covers subscript and slice opcodes. See python_ceval91_detail for binary arithmetic specializations.

Map

LinesSymbolRole
1-80BINARY_SUBSCRobj[key] — generic subscript
81-160BINARY_SUBSCR_LIST_INTSpecialization for list[int]
161-240BINARY_SUBSCR_DICTSpecialization for dict[key]
241-320STORE_SUBSCRobj[key] = value
321-400BINARY_SLICE / STORE_SLICESlice read and write

Reading

BINARY_SUBSCR

// CPython: Python/ceval.c:5620 BINARY_SUBSCR
inst(BINARY_SUBSCR, (container, sub -- res)) {
res = PyObject_GetItem(container, sub);
ERROR_IF(res == NULL, error);
Py_DECREF(container);
Py_DECREF(sub);
}

BINARY_SUBSCR calls PyObject_GetItem which dispatches through tp_as_mapping->mp_subscript or tp_as_sequence->sq_item.

BINARY_SUBSCR_LIST_INT

// CPython: Python/ceval.c:5660 BINARY_SUBSCR_LIST_INT
inst(BINARY_SUBSCR_LIST_INT, (list, sub -- res)) {
DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR);
DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR);
Py_ssize_t index = _PyLong_IsCompact((PyLongObject*)sub) ?
_PyLong_CompactValue((PyLongObject*)sub) :
PyLong_AsSsize_t(sub);
DEOPT_IF(index < 0, BINARY_SUBSCR);
DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR);
res = Py_NewRef(PyList_GET_ITEM(list, index));
Py_DECREF(list);
Py_DECREF(sub);
}

Reads directly from ob_item[index] without bounds check overhead (after the deopt guards). Negative indices fall through to the generic path.

BINARY_SLICE

// CPython: Python/ceval.c:5780 BINARY_SLICE
inst(BINARY_SLICE, (container, start, stop -- res)) {
PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop);
res = PyObject_GetItem(container, slice);
Py_DECREF(slice);
ERROR_IF(res == NULL, error);
Py_DECREF(container);
}

BINARY_SLICE builds a slice object from start and stop (both on the stack). The step is always None for simple slice notation a[1:3].

STORE_SLICE

// CPython: Python/ceval.c:5820 STORE_SLICE
inst(STORE_SLICE, (v, container, start, stop --)) {
PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop);
int err = PyObject_SetItem(container, slice, v);
Py_DECREF(slice);
Py_DECREF(v);
Py_DECREF(container);
ERROR_IF(err, error);
}

a[1:3] = [10, 20] compiles to push [10, 20], push a, push 1, push 3, STORE_SLICE.

gopy notes

BINARY_SUBSCR is in vm/eval_simple.go and calls objects.GetItem. BINARY_SUBSCR_LIST_INT reads objects.List.Items[index] directly. BINARY_SLICE calls objects.BuildSlice then objects.GetItem. STORE_SLICE calls objects.SetItem.