17db96d56Sopenharmony_ci# The Frame Stack 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ciEach call to a Python function has an activation record, 47db96d56Sopenharmony_cicommonly known as a "frame". 57db96d56Sopenharmony_ciPython semantics allows frames to outlive the activation, 67db96d56Sopenharmony_ciso they have (before 3.11) been allocated on the heap. 77db96d56Sopenharmony_ciThis is expensive as it requires many allocations and 87db96d56Sopenharmony_ciresults in poor locality of reference. 97db96d56Sopenharmony_ci 107db96d56Sopenharmony_ciIn 3.11, rather than have these frames scattered about memory, 117db96d56Sopenharmony_cias happens for heap-allocated objects, frames are allocated 127db96d56Sopenharmony_cicontiguously in a per-thread stack. 137db96d56Sopenharmony_ciThis improves performance significantly for two reasons: 147db96d56Sopenharmony_ci* It reduces allocation overhead to a pointer comparison and increment. 157db96d56Sopenharmony_ci* Stack allocated data has the best possible locality and will always be in 167db96d56Sopenharmony_ci CPU cache. 177db96d56Sopenharmony_ci 187db96d56Sopenharmony_ciGenerator and coroutines still need heap allocated activation records, but 197db96d56Sopenharmony_cican be linked into the per-thread stack so as to not impact performance too much. 207db96d56Sopenharmony_ci 217db96d56Sopenharmony_ci## Layout 227db96d56Sopenharmony_ci 237db96d56Sopenharmony_ciEach activation record consists of four conceptual sections: 247db96d56Sopenharmony_ci 257db96d56Sopenharmony_ci* Local variables (including arguments, cells and free variables) 267db96d56Sopenharmony_ci* Evaluation stack 277db96d56Sopenharmony_ci* Specials: The per-frame object references needed by the VM: globals dict, 287db96d56Sopenharmony_ci code object, etc. 297db96d56Sopenharmony_ci* Linkage: Pointer to the previous activation record, stack depth, etc. 307db96d56Sopenharmony_ci 317db96d56Sopenharmony_ci### Layout 327db96d56Sopenharmony_ci 337db96d56Sopenharmony_ciThe specials and linkage sections are a fixed size, so are grouped together. 347db96d56Sopenharmony_ci 357db96d56Sopenharmony_ciEach activation record is laid out as: 367db96d56Sopenharmony_ci* Specials and linkage 377db96d56Sopenharmony_ci* Locals 387db96d56Sopenharmony_ci* Stack 397db96d56Sopenharmony_ci 407db96d56Sopenharmony_ciThis seems to provide the best performance without excessive complexity. 417db96d56Sopenharmony_ciIt needs the interpreter to hold two pointers, a frame pointer and a stack pointer. 427db96d56Sopenharmony_ci 437db96d56Sopenharmony_ci#### Alternative layout 447db96d56Sopenharmony_ci 457db96d56Sopenharmony_ciAn alternative layout that was used for part of 3.11 alpha was: 467db96d56Sopenharmony_ci 477db96d56Sopenharmony_ci* Locals 487db96d56Sopenharmony_ci* Specials and linkage 497db96d56Sopenharmony_ci* Stack 507db96d56Sopenharmony_ci 517db96d56Sopenharmony_ciThis has the advantage that no copying is required when making a call, 527db96d56Sopenharmony_cias the arguments on the stack are (usually) already in the correct 537db96d56Sopenharmony_cilocation for the parameters. However, it requires the VM to maintain 547db96d56Sopenharmony_cian extra pointer for the locals, which can hurt performance. 557db96d56Sopenharmony_ci 567db96d56Sopenharmony_ciA variant that only needs the need two pointers is to reverse the numbering 577db96d56Sopenharmony_ciof the locals, so that the last one is numbered `0`, and the first in memory 587db96d56Sopenharmony_ciis numbered `N-1`. 597db96d56Sopenharmony_ciThis allows the locals, specials and linkage to accessed from the frame pointer. 607db96d56Sopenharmony_ciWe may implement this in the future. 617db96d56Sopenharmony_ci 627db96d56Sopenharmony_ci#### Note: 637db96d56Sopenharmony_ci 647db96d56Sopenharmony_ci> In a contiguous stack, we would need to save one fewer registers, as the 657db96d56Sopenharmony_ci> top of the caller's activation record would be the same at the base of the 667db96d56Sopenharmony_ci> callee's. However, since some activation records are kept on the heap we 677db96d56Sopenharmony_ci> cannot do this. 687db96d56Sopenharmony_ci 697db96d56Sopenharmony_ci### Generators and Coroutines 707db96d56Sopenharmony_ci 717db96d56Sopenharmony_ciGenerators and coroutines contain a `_PyInterpreterFrame` 727db96d56Sopenharmony_ciThe specials sections contains the following pointers: 737db96d56Sopenharmony_ci 747db96d56Sopenharmony_ci* Globals dict 757db96d56Sopenharmony_ci* Builtins dict 767db96d56Sopenharmony_ci* Locals dict (not the "fast" locals, but the locals for eval and class creation) 777db96d56Sopenharmony_ci* Code object 787db96d56Sopenharmony_ci* Heap allocated `PyFrameObject` for this activation record, if any. 797db96d56Sopenharmony_ci* The function. 807db96d56Sopenharmony_ci 817db96d56Sopenharmony_ciThe pointer to the function is not strictly required, but it is cheaper to 827db96d56Sopenharmony_cistore a strong reference to the function and borrowed references to the globals 837db96d56Sopenharmony_ciand builtins, than strong references to both globals and builtins. 847db96d56Sopenharmony_ci 857db96d56Sopenharmony_ci### Frame objects 867db96d56Sopenharmony_ci 877db96d56Sopenharmony_ciWhen creating a backtrace or when calling `sys._getframe()` the frame becomes 887db96d56Sopenharmony_civisible to Python code. When this happens a new `PyFrameObject` is created 897db96d56Sopenharmony_ciand a strong reference to it placed in the `frame_obj` field of the specials 907db96d56Sopenharmony_cisection. The `frame_obj` field is initially `NULL`. 917db96d56Sopenharmony_ci 927db96d56Sopenharmony_ciThe `PyFrameObject` may outlive a stack-allocated `_PyInterpreterFrame`. 937db96d56Sopenharmony_ciIf it does then `_PyInterpreterFrame` is copied into the `PyFrameObject`, 947db96d56Sopenharmony_ciexcept the evaluation stack which must be empty at this point. 957db96d56Sopenharmony_ciThe linkage section is updated to reflect the new location of the frame. 967db96d56Sopenharmony_ci 977db96d56Sopenharmony_ciThis mechanism provides the appearance of persistent, heap-allocated 987db96d56Sopenharmony_ciframes for each activation, but with low runtime overhead. 997db96d56Sopenharmony_ci 1007db96d56Sopenharmony_ci### Generators and Coroutines 1017db96d56Sopenharmony_ci 1027db96d56Sopenharmony_ci 1037db96d56Sopenharmony_ciGenerator objects have a `_PyInterpreterFrame` embedded in them. 1047db96d56Sopenharmony_ciThis means that creating a generator requires only a single allocation, 1057db96d56Sopenharmony_cireducing allocation overhead and improving locality of reference. 1067db96d56Sopenharmony_ciThe embedded frame is linked into the per-thread frame when iterated or 1077db96d56Sopenharmony_ciawaited. 1087db96d56Sopenharmony_ci 1097db96d56Sopenharmony_ciIf a frame object associated with a generator outlives the generator, then 1107db96d56Sopenharmony_cithe embedded `_PyInterpreterFrame` is copied into the frame object. 1117db96d56Sopenharmony_ci 1127db96d56Sopenharmony_ci 1137db96d56Sopenharmony_ciAll the above applies to coroutines and async generators as well. 1147db96d56Sopenharmony_ci 1157db96d56Sopenharmony_ci### Field names 1167db96d56Sopenharmony_ci 1177db96d56Sopenharmony_ciMany of the fields in `_PyInterpreterFrame` were copied from the 3.10 `PyFrameObject`. 1187db96d56Sopenharmony_ciThus, some of the field names may be a bit misleading. 1197db96d56Sopenharmony_ci 1207db96d56Sopenharmony_ciFor example the `f_globals` field has a `f_` prefix implying it belongs to the 1217db96d56Sopenharmony_ci`PyFrameObject` struct, although it belongs to the `_PyInterpreterFrame` struct. 1227db96d56Sopenharmony_ciWe may rationalize this naming scheme for 3.12.