Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ A lesson can also end with a boss fight, which is a problem the text does not so
| F07 | [The list becomes a graph](lessons/f07-the-list-becomes-a-graph/f07.ipynb) | The three rules that split bytecode into basic blocks, why the disassembly of a try is not in source order, unreachable code disappearing because nothing points at its block, why the stack depth of a handler cannot be added up in order, and how little of the graph survives into the code object | M3 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tamnd/cpython-internals/blob/main/lessons/f07-the-list-becomes-a-graph/f07.ipynb) |
| F08 | [The optimizer](lessons/f08-the-optimizer/f08.ipynb) | Why 2 ** 64 is worked out at compile time and 2 ** 65 is not, the four size limits written down as constants, the leftover number that survives because slot zero might be a docstring, a jump deleted by copying the two instructions it pointed at, the line break that costs you a superinstruction, and how the compiler proves a local has a value | M3 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tamnd/cpython-internals/blob/main/lessons/f08-the-optimizer/f08.ipynb) |
| F09 | [Two bytes at a time](lessons/f09-two-bytes-at-a-time/f09.ipynb) | Every byte of a two line function read by hand, the cache slots that are in the instruction stream but never run, why dis offsets go 0, 4, 6, 8, 20, how to rebuild a jump target from its argument, the boundary where one argument byte stops being enough, and the awful hack that sorts it out | M3 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tamnd/cpython-internals/blob/main/lessons/f09-two-bytes-at-a-time/f09.ipynb) |
| F10 | [Inside a code object](lessons/f10-inside-a-code-object/f10.ipynb) | The record the compiler hands back, walked from a module down to a method, the seven slots behind three tuples that add up to eight, why a closure's first instruction runs before line one, every bit in co_flags, what equality compares and what it deliberately ignores, and what happens when you try to change one | M3 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tamnd/cpython-internals/blob/main/lessons/f10-inside-a-code-object/f10.ipynb) |

More are landing in order. [lessons/README.md](lessons/README.md) explains how one is put together and how to run them locally.

Expand Down
35 changes: 35 additions & 0 deletions citations.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,21 @@
"first_line": "fstring_replacement_field[expr_ty]:",
"lines": 3
},
"Include/cpython/code.h:118-153@v3.15.0rc1": {
"digest": "796288f2efca9a8f",
"first_line": "#define CO_OPTIMIZED 0x0001",
"lines": 36
},
"Include/cpython/code.h:45-84@v3.15.0rc1": {
"digest": "b8093c5db4f33759",
"first_line": "#define _PyCode_DEF(SIZE) { \\",
"lines": 40
},
"Include/cpython/code.h:82-95@v3.15.0rc1": {
"digest": "6e0e3361dc8d74dd",
"first_line": "/* redundant values (derived from co_localsplusnames and \\",
"lines": 14
},
"Include/cpython/listobject.h:5-22@v3.15.0rc1": {
"digest": "707b180de55e923a",
"first_line": "typedef struct {",
Expand Down Expand Up @@ -115,6 +125,11 @@
"first_line": "struct _stmt {",
"lines": 12
},
"Include/internal/pycore_code.h:192-199@v3.15.0rc1": {
"digest": "fc05fedf627a517c",
"first_line": "#define CO_FAST_ARG_POS (0x02) // pos-only, pos-or-kw, varargs",
"lines": 8
},
"Include/internal/pycore_flowgraph.h:27-31@v3.15.0rc1": {
"digest": "5f318ca1d3438caa",
"first_line": "struct _PyCfgBuilder* _PyCfg_FromInstructionSequence(_PyInstructionSequence *seq);",
Expand Down Expand Up @@ -475,6 +490,21 @@
"first_line": "static int",
"lines": 22
},
"Objects/codeobject.c:2502-2541@v3.15.0rc1": {
"digest": "83840c731b19be0c",
"first_line": "code_richcompare(PyObject *self, PyObject *other, int op)",
"lines": 40
},
"Objects/codeobject.c:423-443@v3.15.0rc1": {
"digest": "9429e466c83d6c29",
"first_line": "static PyObject *",
"lines": 21
},
"Objects/codeobject.c:446-485@v3.15.0rc1": {
"digest": "ecced15598ef0f01",
"first_line": "_PyCode_Validate(struct _PyCodeConstructor *con)",
"lines": 40
},
"Objects/codeobject.c:510-519@v3.15.0rc1": {
"digest": "da2de0ce00cbfa54",
"first_line": "static int",
Expand Down Expand Up @@ -1320,6 +1350,11 @@
"first_line": "static int",
"lines": 26
},
"Python/assemble.c:516-528@v3.15.0rc1": {
"digest": "5891a4c578341344",
"first_line": "_PyLocals_Kind kind = CO_FAST_LOCAL | argvarkinds[i].kind;",
"lines": 13
},
"Python/assemble.c:705-708@v3.15.0rc1": {
"digest": "75168c43621dfa26",
"first_line": "/* jump offsets are computed relative to",
Expand Down
13 changes: 12 additions & 1 deletion lessons/CLAIMS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ header, what the allocator does with a freed block, the shape of the eval loop.
marked with the reason, and a lesson is allowed at most 3 of them. The cap is the point.
Without it the exception becomes the rule and this goes back to being a book.

223 claims across 25 lessons, 19 of them not observable from Python.
229 claims across 26 lessons, 19 of them not observable from Python.

## B01. Building CPython, and whether you need to

Expand Down Expand Up @@ -148,6 +148,17 @@ Without it the exception becomes the rule and this goes back to being a book.
| the step that first needs an EXTENDED_ARG is one pair bigger than every other step | [`f09-16`](f09-two-bytes-at-a-time/f09.ipynb) |
| the same jump is a label before the assembler and a signed distance after it | [`f09-19`](f09-two-bytes-at-a-time/f09.ipynb) |

## F10. Inside a code object

| Claim | Proved by |
| --- | --- |
| the code objects of a file form a tree, reachable through co_consts alone | [`f10-07`](f10-inside-a-code-object/f10.ipynb) |
| a parameter that a nested function reads is tagged twice, so it appears in two tuples | [`f10-09`](f10-inside-a-code-object/f10.ipynb) |
| a function whose parameter is captured starts with instructions that belong to no line of source | [`f10-11`](f10-inside-a-code-object/f10.ipynb) |
| a module body and a class body have no flags set at all, and a function has several | [`f10-13`](f10-inside-a-code-object/f10.ipynb) |
| the same source compiled from two different filenames gives two equal code objects | [`f10-15`](f10-inside-a-code-object/f10.ipynb) |
| replace gives you a new code object and leaves the original alone | [`f10-17`](f10-inside-a-code-object/f10.ipynb) |

## T01. One line, seven stages

| Claim | Proved by |
Expand Down
1 change: 1 addition & 0 deletions lessons/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Each lesson is a notebook you can run. There is nothing to install and nothing t
| [F07. The list becomes a graph](f07-the-list-becomes-a-graph/f07.ipynb) | The fourth compiler pass and the shape it works in, three rules for finding basic blocks, why a try compiles out of source order, unreachable code going because nothing points at its block, stack depth as a walk over every path, and cold handlers pushed past the end | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tamnd/cpython-internals/blob/main/lessons/f07-the-list-becomes-a-graph/f07.ipynb) |
| [F08. The optimizer](f08-the-optimizer/f08.ipynb) | The pass that runs while the graph is in that shape, constant folding and the four numbers that stop it, the unused constant that slot zero protects, jumps removed by copying a short ending, two instructions merged into one when they fit, and the graph walk behind LOAD_FAST_CHECK | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tamnd/cpython-internals/blob/main/lessons/f08-the-optimizer/f08.ipynb) |
| [F09. Two bytes at a time](f09-two-bytes-at-a-time/f09.ipynb) | The assembler, reading the bytes of a small function one pair at a time, the cache slots that make the offsets skip, why a jump argument is counted from after the fetch, what an EXTENDED_ARG costs, and the loop that has to run twice because widening a jump moves its target | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tamnd/cpython-internals/blob/main/lessons/f09-two-bytes-at-a-time/f09.ipynb) |
| [F10. Inside a code object](f10-inside-a-code-object/f10.ipynb) | What compiling a file actually hands you, the code objects that live in other code objects' constants, the one array behind co_varnames and co_cellvars and co_freevars, the instructions that run before your first line, what co_flags remembers, and why two code objects can be equal without being the same one | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tamnd/cpython-internals/blob/main/lessons/f10-inside-a-code-object/f10.ipynb) |

## The three programs

Expand Down
Loading
Loading