Skip to content

Commit

Permalink
Merge branch 'main' into remove-ghccc
Browse files Browse the repository at this point in the history
  • Loading branch information
savannahostrowski authored Oct 22, 2024
2 parents 3a2ecee + 03f9264 commit 3259994
Show file tree
Hide file tree
Showing 16 changed files with 595 additions and 508 deletions.
3 changes: 1 addition & 2 deletions InternalDocs/adaptive.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ although these are not fundamental and may change:

## Example family

The `LOAD_GLOBAL` instruction (in
[Python/bytecodes.c](https://github.com/python/cpython/blob/main/Python/bytecodes.c))
The `LOAD_GLOBAL` instruction (in [Python/bytecodes.c](../Python/bytecodes.c))
already has an adaptive family that serves as a relatively simple example.

The `LOAD_GLOBAL` instruction performs adaptive specialization,
Expand Down
418 changes: 194 additions & 224 deletions InternalDocs/compiler.md

Large diffs are not rendered by default.

28 changes: 12 additions & 16 deletions InternalDocs/exception_handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,16 @@ Handling Exceptions
-------------------

At runtime, when an exception occurs, the interpreter calls
``get_exception_handler()`` in
[Python/ceval.c](https://github.com/python/cpython/blob/main/Python/ceval.c)
`get_exception_handler()` in [Python/ceval.c](../Python/ceval.c)
to look up the offset of the current instruction in the exception
table. If it finds a handler, control flow transfers to it. Otherwise, the
exception bubbles up to the caller, and the caller's frame is
checked for a handler covering the `CALL` instruction. This
repeats until a handler is found or the topmost frame is reached.
If no handler is found, then the interpreter function
(``_PyEval_EvalFrameDefault()``) returns NULL. During unwinding,
(`_PyEval_EvalFrameDefault()`) returns NULL. During unwinding,
the traceback is constructed as each frame is added to it by
``PyTraceBack_Here()``, which is in
[Python/traceback.c](https://github.com/python/cpython/blob/main/Python/traceback.c).
`PyTraceBack_Here()`, which is in [Python/traceback.c](../Python/traceback.c).

Along with the location of an exception handler, each entry of the
exception table also contains the stack depth of the `try` instruction
Expand Down Expand Up @@ -174,22 +172,20 @@ which is then encoded as:

for a total of five bytes.

The code to construct the exception table is in ``assemble_exception_table()``
in [Python/assemble.c](https://github.com/python/cpython/blob/main/Python/assemble.c).
The code to construct the exception table is in `assemble_exception_table()`
in [Python/assemble.c](../Python/assemble.c).

The interpreter's function to lookup the table by instruction offset is
``get_exception_handler()`` in
[Python/ceval.c](https://github.com/python/cpython/blob/main/Python/ceval.c).
The Python function ``_parse_exception_table()`` in
[Lib/dis.py](https://github.com/python/cpython/blob/main/Lib/dis.py)
`get_exception_handler()` in [Python/ceval.c](../Python/ceval.c).
The Python function `_parse_exception_table()` in [Lib/dis.py](../Lib/dis.py)
returns the exception table content as a list of namedtuple instances.

Exception Chaining Implementation
---------------------------------

[Exception chaining](https://docs.python.org/dev/tutorial/errors.html#exception-chaining)
refers to setting the ``__context__`` and ``__cause__`` fields of an exception as it is
being raised. The ``__context__`` field is set by ``_PyErr_SetObject()`` in
[Python/errors.c](https://github.com/python/cpython/blob/main/Python/errors.c)
(which is ultimately called by all ``PyErr_Set*()`` functions).
The ``__cause__`` field (explicit chaining) is set by the ``RAISE_VARARGS`` bytecode.
refers to setting the `__context__` and `__cause__` fields of an exception as it is
being raised. The `__context__` field is set by `_PyErr_SetObject()` in
[Python/errors.c](../Python/errors.c) (which is ultimately called by all
`PyErr_Set*()` functions). The `__cause__` field (explicit chaining) is set by
the `RAISE_VARARGS` bytecode.
18 changes: 8 additions & 10 deletions InternalDocs/frames.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,19 @@ of three conceptual sections:
globals dict, code object, instruction pointer, stack depth, the
previous frame, etc.

The definition of the ``_PyInterpreterFrame`` struct is in
[Include/internal/pycore_frame.h](https://github.com/python/cpython/blob/main/Include/internal/pycore_frame.h).
The definition of the `_PyInterpreterFrame` struct is in
[Include/internal/pycore_frame.h](../Include/internal/pycore_frame.h).

# Allocation

Python semantics allows frames to outlive the activation, so they need to
be allocated outside the C call stack. To reduce overhead and improve locality
of reference, most frames are allocated contiguously in a per-thread stack
(see ``_PyThreadState_PushFrame`` in
[Python/pystate.c](https://github.com/python/cpython/blob/main/Python/pystate.c)).
(see `_PyThreadState_PushFrame` in [Python/pystate.c](../Python/pystate.c)).

Frames of generators and coroutines are embedded in the generator and coroutine
objects, so are not allocated in the per-thread stack. See ``PyGenObject`` in
[Include/internal/pycore_genobject.h](https://github.com/python/cpython/blob/main/Include/internal/pycore_genobject.h).
objects, so are not allocated in the per-thread stack. See `PyGenObject` in
[Include/internal/pycore_genobject.h](../Include/internal/pycore_genobject.h).

## Layout

Expand Down Expand Up @@ -82,16 +81,15 @@ frames for each activation, but with low runtime overhead.

### Generators and Coroutines

Generators (objects of type ``PyGen_Type``, ``PyCoro_Type`` or
``PyAsyncGen_Type``) have a `_PyInterpreterFrame` embedded in them, so
Generators (objects of type `PyGen_Type`, `PyCoro_Type` or
`PyAsyncGen_Type`) have a `_PyInterpreterFrame` embedded in them, so
that they can be created with a single memory allocation.
When such an embedded frame is iterated or awaited, it can be linked with
frames on the per-thread stack via the linkage fields.

If a frame object associated with a generator outlives the generator, then
the embedded `_PyInterpreterFrame` is copied into the frame object (see
``take_ownership()`` in
[Python/frame.c](https://github.com/python/cpython/blob/main/Python/frame.c)).
`take_ownership()` in [Python/frame.c](../Python/frame.c)).

### Field names

Expand Down
Loading

0 comments on commit 3259994

Please sign in to comment.