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 @@ -114,6 +114,7 @@ A lesson can also end with a boss fight, which is a problem the text does not so
| 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) |
| F11 | [Two tables on the side](lessons/f11-two-tables-on-the-side/f11.ipynb) | The two blobs beside the bytecode, why wrapping a loop in a try changes not one instruction, the four numbers in an exception table entry and the marker bit that makes a variable length table binary searchable, the six forms a location entry can take, and two decoders written here that agree with the interpreter's | 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/f11-two-tables-on-the-side/f11.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
50 changes: 50 additions & 0 deletions citations.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@
"first_line": "#define CO_OPTIMIZED 0x0001",
"lines": 36
},
"Include/cpython/code.h:314-325@v3.15.0rc1": {
"digest": "69c2883f3fd31c09",
"first_line": "typedef enum _PyCodeLocationInfoKind {",
"lines": 12
},
"Include/cpython/code.h:45-84@v3.15.0rc1": {
"digest": "b8093c5db4f33759",
"first_line": "#define _PyCode_DEF(SIZE) { \\",
Expand Down Expand Up @@ -130,6 +135,21 @@
"first_line": "#define CO_FAST_ARG_POS (0x02) // pos-only, pos-or-kw, varargs",
"lines": 8
},
"Include/internal/pycore_code.h:394-403@v3.15.0rc1": {
"digest": "f19a30d3d1b1672b",
"first_line": "static inline unsigned char *",
"lines": 10
},
"Include/internal/pycore_code.h:405-416@v3.15.0rc1": {
"digest": "4258457082674f92",
"first_line": "static inline int",
"lines": 12
},
"Include/internal/pycore_code.h:432-437@v3.15.0rc1": {
"digest": "3969a1749fa282ab",
"first_line": "static inline int",
"lines": 6
},
"Include/internal/pycore_flowgraph.h:27-31@v3.15.0rc1": {
"digest": "5f318ca1d3438caa",
"first_line": "struct _PyCfgBuilder* _PyCfg_FromInstructionSequence(_PyInstructionSequence *seq);",
Expand Down Expand Up @@ -490,6 +510,11 @@
"first_line": "static int",
"lines": 22
},
"Objects/codeobject.c:1201-1225@v3.15.0rc1": {
"digest": "db7d492e583ccdfe",
"first_line": "static void",
"lines": 25
},
"Objects/codeobject.c:2502-2541@v3.15.0rc1": {
"digest": "83840c731b19be0c",
"first_line": "code_richcompare(PyObject *self, PyObject *other, int op)",
Expand Down Expand Up @@ -1335,6 +1360,21 @@
"first_line": "self->tok = _PyTokenizer_FromReadline(readline, encoding, 1, 1);",
"lines": 1
},
"Python/assemble.c:133-156@v3.15.0rc1": {
"digest": "4e437d03e06750b5",
"first_line": "assemble_emit_exception_table_entry(struct assembler *a, int start, int end,",
"lines": 24
},
"Python/assemble.c:158-190@v3.15.0rc1": {
"digest": "976fe9d268bf6d82",
"first_line": "assemble_exception_table(struct assembler *a, instr_sequence *instrs)",
"lines": 33
},
"Python/assemble.c:257-267@v3.15.0rc1": {
"digest": "70e139cd9b341390",
"first_line": "static void",
"lines": 11
},
"Python/assemble.c:368-406@v3.15.0rc1": {
"digest": "08bbae3c3ba3a552",
"first_line": "static void",
Expand Down Expand Up @@ -1475,6 +1515,16 @@
"first_line": "PyObject *",
"lines": 30
},
"Python/ceval.h:440-444@v3.15.0rc1": {
"digest": "ab7807756cb3110a",
"first_line": "static inline unsigned char *",
"lines": 5
},
"Python/ceval.h:457-490@v3.15.0rc1": {
"digest": "7b8f661400efec41",
"first_line": "static Py_NO_INLINE int",
"lines": 34
},
"Python/ceval_macros.h:128-141@v3.15.0rc1": {
"digest": "b032ce0706e98a42",
"first_line": "#elif USE_COMPUTED_GOTOS",
Expand Down
14 changes: 13 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.

229 claims across 26 lessons, 19 of them not observable from Python.
236 claims across 27 lessons, 19 of them not observable from Python.

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

Expand Down Expand Up @@ -159,6 +159,18 @@ Without it the exception becomes the rule and this goes back to being a book.
| 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) |

## F11. Two tables on the side

| Claim | Proved by |
| --- | --- |
| the instructions inside a try block are identical to the same code with no try around it | [`f11-07`](f11-two-tables-on-the-side/f11.ipynb) |
| an exception table entry decodes to start, size, target and a doubled depth | [`f11-13`](f11-two-tables-on-the-side/f11.ipynb) |
| a dozen lines of Python decode co_exceptiontable exactly as dis does | [`f11-16`](f11-two-tables-on-the-side/f11.ipynb) |
| the caret in a traceback is drawn from the column numbers in co_linetable | [`f11-20`](f11-two-tables-on-the-side/f11.ipynb) |
| some instructions in a normal function have no source location at all | [`f11-23`](f11-two-tables-on-the-side/f11.ipynb) |
| a hand written decoder reproduces co_positions() for every code object in a standard library module | [`f11-26`](f11-two-tables-on-the-side/f11.ipynb) |
| the two tables encode integers with their chunks in opposite orders | [`f11-31`](f11-two-tables-on-the-side/f11.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 @@ -30,6 +30,7 @@ Each lesson is a notebook you can run. There is nothing to install and nothing t
| [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) |
| [F11. Two tables on the side](f11-two-tables-on-the-side/f11.ipynb) | Why a try you never trip costs nothing, the exception table decoded byte by byte and checked against dis, how a raise binary searches a table whose entries are not the same length, the six shapes a source location can take, and a hand written line table decoder run against every code object in dis.py | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tamnd/cpython-internals/blob/main/lessons/f11-two-tables-on-the-side/f11.ipynb) |

## The three programs

Expand Down
Loading
Loading