Hi Gabriele! > I hope you would indulge me in asking for some details about the new CFrame > structure, even in the form of existing literature (e.g. PEP) where the idea > behind it is explained.
There isn't too much documentation on this, unfortunately (since these are all very unstable, low-level interpreter details), but a good place to start would be https://bugs.python.org/issue46090. Based on my own understanding (from reading the source code): - There are three relevant structures: CFrame, InterpreterFrame, and PyFrameObject. - PyFrameObjects are just PyObject wrappers around an InterpreterFrame, where all of the *actual* frame state for the Python stack is maintained. - They are created lazily (for example, when sys._getframe() is called). - See https://github.com/python/cpython/pull/27077. - InterpreterFrames live in a "datastack" for fast allocation and deallocation. - This "datastack" lives on the PyThreadState. - Because of how it is designed, InterpreterFrames must be allocated/deallocated "in order". - If an InterpreterFrame is cleared, but still has a live PyFrameObject that points to it, it will copy itself *into* the PyFrameObject first (to guarantee that the PyFrameObject keeps working). - See https://github.com/python/cpython/pull/26076. - A single CFrame is statically allocated inside of each _PyEval_EvalFrameDefault call, so it corresponds to the C stack, not the Python stack. - It links to a chain of one or more InterpreterFrames. - Multiple InterpreterFrames can correspond to a single CFrame! - This is a performance optimization in 3.11: rather than enter a new call to _PyEval_EvalFrameDefault, calls to pure-Python code just create a new InterpreterFrame, set it as the current one, and continue execution. - You can see how many InterpreterFrames correspond to the current CFrame by reading the "depth" member of the current InterpreterFrame. - A value of 0 indicates that this is the only InterpreterFrame for this CFrame. - A value of 42 means that this optimization has been performed 42 times (and there are currently 43 InterpreterFrames executing in this CFrame). > Also, I'd like to a quick question, if I may. There now appear to be two ways > of unwinding the frame stack: either iterate over CFrame.previous, or the > more traditional PyFrameObject.f_back. I suspect there are reasons why these > are perhaps not actually equivalent, and indeed this is mainly what I'd like > to read in the literature I've requested above. The above outline probably makes the differences clear: - PyFrameObject.f_back just gives you a dummy wrapper around the previous frame object. - It's not really useful for unwinding anything. - InterpreterFrame.previous gives you the previous interpreter frame (duh!). - This is probably what you want. - CFrame.previous gives you the previous call to _PyEval_EvalFrameDefault. - It's not really useful for unwinding anything. - This is only really useful to maintain the current tracing state when returning. Hopefully this helps! Somebody (Pablo or Mark?) will probably jump in here if I got anything wrong. Brandt _______________________________________________ Python-Dev mailing list -- python-dev@python.org To unsubscribe send an email to python-dev-le...@python.org https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/GDCPNESE2BWJUNPYFANCZVZK4EZNTKAF/ Code of Conduct: http://python.org/psf/codeofconduct/