These releases record source lines in two ways at once: SET_LINENO
instructions in the bytecode, and the table co_lnotab in the code object.
The explorer works out line numbers from the table.
SET_LINENO
A normal compile puts a SET_LINENO instruction (opcode 127) before each
statement. Its argument is the line number, and at run time it stores that number in
the frame. It costs an instruction for every statement, so the -O option
leaves them out, and a .pyo file has none. The table is written either
way.
The co_lnotab table
co_lnotab is a string of byte pairs. The first byte of a pair is how far
the address moves on, in bytes of co_code. The second is how far the line
number moves on. Both are unsigned, so neither can go down.
To read it, start with address 0 and line co_firstlineno. For each pair,
add the first byte to the address, and if the address is now past the instruction you
are looking for, stop: the line so far is its line. Otherwise add the second byte to
the line and go on.
A step too big for one byte is spread over several pairs. compile.c in
1.5.2 and 2.0.1 cuts the address step and the line step at 255 together, so a step of
300 bytes and 3 lines is written as FF 03 2D 00: 255 bytes and 3 lines,
then 45 bytes and no lines. A reader that adds the pairs up does not need to know
this. It only matters if you try to read a single pair on its own.
Worked example
This example is constructed by hand from the rules above, with no Python this old running it. It is two statements of a function body on lines 2 and 3, and it leaves out the code that follows them.
| Offset | Bytes | Instruction |
|---|---|---|
| 0 | 7F 02 00 | SET_LINENO 2 |
| 3 | 7C 00 00 | LOAD_FAST 0 |
| 6 | 7D 01 00 | STORE_FAST 1 |
| 9 | 7F 03 00 | SET_LINENO 3 |
| 12 | 7C 01 00 | LOAD_FAST 1 |
| 15 | 53 | RETURN_VALUE |
co_firstlineno is 2, which the first statement sets. The table only
needs an entry when the line changes, so it is the single pair 09 01:
move on 9 bytes and 1 line. Reading it back, offsets 0 to 8 are line 2 and offsets
from 9 are line 3.
In a .pyo file the two SET_LINENO instructions are not
written. The second statement then starts at offset 6, and the table is
06 01.