diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 211831a6e497..3ea538ccc550 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -7,6 +7,75 @@ extern "C" { #include #include +/* Starting in CPython 3.11, CPython separates the frame state between the + * full frame objects exposed by the Python and C runtime state introspection + * APIs, and internal lighter weight interpreter frames, which are simple C + * structures owned by either the interpreter eval loop (while executing + * ordinary functions), by a generator or coroutine object (for frames that + * are able to be suspended), or by their corresponding full frame object (if + * a state instrospection API has been invoked and the full frame object has + * taken responsibility for the lifecycle of the interpreter frame). + * + * This split storage eliminates a lot of allocation and deallocation of full + * Python objects during code execution, providing a significant speed gain + * over the previous approach of using full Python objects for both + * introspection and code execution. + * + * Struct names: + * + * * PyFrameObject: the full Python frame object + * * _PyInterpreterFrame: the lightweight frame struct used by the eval loop + * * _PyCFrame: a struct that lives on the C stack and allows Python level + * recursive evaluation to be decoupled from recursive C level invocation + * of the bytecode eval loop + * * See pystate.h for more details on this struct + * + * Field naming conventions: + * + * * full frame object fields have an "f_*" (or "_f_*") prefix + * * new interpreter frame fields have no prefix + * * Several interpreter frame fields have the "f_*" prefix as a result of + * trying to keep diffs as small as was feasible when splitting the original + * frame struct definition in two. The following are all interpreter frame + * fields, NOT full frame object fields: + * * f_func + * * f_globals + * * f_builtins + * * f_locals + * * f_code + * * f_lasti + * * f_state + * * Renaming those fields was considered but ultimately deemed too disruptive + * to key third party projects that were trying to keep up with the Python + * 3.11 code evaluation changes during the alpha release cycle + * (see bpo-44800 for details) + * + * Naming conventions for local variables, function parameters and fields in other structs: + * + * * "frame" and "f" may refer to either full frame objects or interpreter frames + * * the context of use or the field naming conventions usually make the + * type being referenced unambiguous in code reviews + * * the following alternative names are used when more clarity is needed: + * * full frame objects: "frame_obj" (and variants like "frameobj" or "fobj") + * * interpreter frame structs: "frame_data" or "iframe" + * * "current frame" should NOT be abbreviated as "cframe", as the latter now + * typically refers to _PyCFrame structs + * + * Function/macro parameter types: + * + * * "PyFrame_*" functions and other public C API functions that relate to + * frames accept full frame object pointers + * * "_PyFrame_*" functions and other private C API functions that relate to + * frames accept either full frame object or interpreter frame pointers. + * Check the specific function signatures for details. + * + * Function return types: + * + * * Public C API functions will only ever return full frame object pointers + * * Private C API functions with an underscore prefix may return interpreter + * frame pointers instead. Check the specific function signatures for details. + */ + struct _frame { PyObject_HEAD PyFrameObject *f_back; /* previous frame, or NULL */