Skip to main content

Python/ceval.c (part 47)

Source:

cpython 3.14 @ ab2d84fe1023/Python/ceval.c

This annotation covers LOAD_ATTR specializations for modules, instance dicts with hints, and slot-based types. See python_ceval46_detail for subscript specializations and stack manipulation.

Map

LinesSymbolRole
1-80LOAD_ATTR_MODULEAttribute lookup on a module object
81-160LOAD_ATTR_WITH_HINTInstance dict lookup with cached hash/index hint
161-260LOAD_ATTR_SLOTC-extension slot attribute (no dict)
261-360LOAD_ATTR_CLASSClass attribute that is not a descriptor
361-500LOAD_ATTR_GETATTRIBUTE_OVERRIDDENCustom __getattribute__ path

Reading

LOAD_ATTR_MODULE

// CPython: Python/ceval.c:3180 LOAD_ATTR_MODULE
inst(LOAD_ATTR_MODULE, (unused/2, owner -- attr, null if (oparg & 1))) {
DEOPT_IF(!PyModule_CheckExact(owner));
PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict;
DEOPT_IF(dict == NULL);
PyObject *res;
Py_ssize_t index = cache->index;
DEOPT_IF(!_PyDict_HasOnlyUnicodeKeys(dict));
_PyDictValues *values = dict->ma_values;
DEOPT_IF(values == NULL);
res = _PyDictValues_GetItemByIndex(values, index);
DEOPT_IF(res == NULL);
Py_INCREF(res);
DECREF_INPUTS();
DISPATCH();
}

Module attribute access is very common (os.path, sys.argv). The specialization caches the value's index in the module dict's compact values array. No hash computation is needed on the hot path.

LOAD_ATTR_WITH_HINT

// CPython: Python/ceval.c:3240 LOAD_ATTR_WITH_HINT
inst(LOAD_ATTR_WITH_HINT, (unused/2, owner -- attr, null if (oparg & 1))) {
/* Cache: (dict_version, index_hint) */
DEOPT_IF(!PyObject_TypeHasFeature(Py_TYPE(owner), Py_TPFLAGS_MANAGED_DICT));
PyDictObject *dict = _PyObject_GetManagedDict(owner);
DEOPT_IF(dict == NULL || !PyDict_CheckExact(dict));
DEOPT_IF(dict->ma_version_tag != cache->version);
PyObject *name = GETITEM(FRAME_CO_NAMES, cache->name_or_flag);
PyObject *res = NULL;
Py_ssize_t hint = cache->index;
if (_PyDict_GetItemHint(dict, name, hint, &res) != hint) {
DEOPT_IF(true);
}
Py_INCREF(res);
DECREF_INPUTS();
DISPATCH();
}

The "hint" is the expected index in the instance dict. If the dict version matches and the item is still at that index, the lookup is O(1) without hashing. On version mismatch the specialization deoptimizes back to LOAD_ATTR.

LOAD_ATTR_SLOT

// CPython: Python/ceval.c:3300 LOAD_ATTR_SLOT
inst(LOAD_ATTR_SLOT, (unused/2, owner -- attr, null if (oparg & 1))) {
/* C extension type with __slots__; no instance dict */
Py_ssize_t offset = cache->index;
PyObject *res = *(PyObject **)((char *)owner + offset);
DEOPT_IF(res == NULL);
Py_INCREF(res);
DECREF_INPUTS();
DISPATCH();
}

For types defined with __slots__ (or C extension types), attributes live at fixed offsets in the object struct. The cache stores the offset; the hot path is a single pointer dereference.

gopy notes

LOAD_ATTR_MODULE is in vm/eval_simple.go; it checks for *objects.Module type and uses a cached index into module.AttrValues. LOAD_ATTR_WITH_HINT checks objects.Dict.Version and uses objects.DictGetHint. LOAD_ATTR_SLOT reads from a fixed offset in the object's Go struct using unsafe.Pointer arithmetic.