summaryrefslogtreecommitdiffstats
path: root/Include
diff options
context:
space:
mode:
authorNick Coghlan <ncoghlan@gmail.com>2022-04-03 06:55:55 (GMT)
committerGitHub <noreply@github.com>2022-04-03 06:55:55 (GMT)
commit124227c95f310d2ecd4b567271ab1919fc7000cb (patch)
tree2928c003695d7d6877954e7df877479a1d55e5a7 /Include
parent4f5d56f8f33196f5ed8ffad0ab2f012afda2f9b3 (diff)
downloadcpython-124227c95f310d2ecd4b567271ab1919fc7000cb.zip
cpython-124227c95f310d2ecd4b567271ab1919fc7000cb.tar.gz
cpython-124227c95f310d2ecd4b567271ab1919fc7000cb.tar.bz2
bpo-44800: Document internal frame naming conventions (GH-32281)
The fact interpreter frames were split out from full frame objects rather than always being part of the eval loop implementation means that it's tricky to infer the expected naming conventions simply from looking at the code. Documenting the de facto conventions in pycore_frame.h means future readers of the code will have a clear explanation of the rationale for those conventions (i.e. minimising non-functional code churn).
Diffstat (limited to 'Include')
-rw-r--r--Include/internal/pycore_frame.h69
1 files changed, 69 insertions, 0 deletions
diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h
index 211831a..3ea538c 100644
--- a/Include/internal/pycore_frame.h
+++ b/Include/internal/pycore_frame.h
@@ -7,6 +7,75 @@ extern "C" {
#include <stdbool.h>
#include <stddef.h>
+/* 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 */