bpo-28810: Update lnotab_notes.txt (#665)

This commit is contained in:
Ivan Levkivskyi 2017-03-14 20:42:09 +01:00 committed by Serhiy Storchaka
parent 2e4e011795
commit 9135275cba
1 changed files with 28 additions and 22 deletions

View File

@ -1,17 +1,18 @@
All about co_lnotab, the line number table. All about co_lnotab, the line number table.
Code objects store a field named co_lnotab. This is an array of unsigned bytes Code objects store a field named co_lnotab. This is an array of unsigned bytes
disguised as a Python string. It is used to map bytecode offsets to source code disguised as a Python bytes object. It is used to map bytecode offsets to
line #s for tracebacks and to identify line number boundaries for line tracing. source code line #s for tracebacks and to identify line number boundaries for
line tracing.
The array is conceptually a compressed list of The array is conceptually a compressed list of
(bytecode offset increment, line number increment) (bytecode offset increment, line number increment)
pairs. The details are important and delicate, best illustrated by example: pairs. The details are important and delicate, best illustrated by example:
byte code offset source code line number byte code offset source code line number
0 1 0 1
6 2 6 2
50 7 50 7
350 207 350 207
361 208 361 208
@ -24,7 +25,8 @@ look like:
The above doesn't really work, but it's a start. An unsigned byte (byte code The above doesn't really work, but it's a start. An unsigned byte (byte code
offset) can't hold negative values, or values larger than 255, a signed byte offset) can't hold negative values, or values larger than 255, a signed byte
(line number) can't hold values larger than 127 or less than -128, and the (line number) can't hold values larger than 127 or less than -128, and the
above example contains two such values. So we make two tweaks: above example contains two such values. (Note that before 3.6, line number
was also encoded by an unsigned byte.) So we make two tweaks:
(a) there's a deep assumption that byte code offsets increase monotonically, (a) there's a deep assumption that byte code offsets increase monotonically,
and and
@ -52,7 +54,7 @@ the example above, assemble_lnotab in compile.c should not (as was actually done
until 2.2) expand 300, 200 to until 2.2) expand 300, 200 to
255, 255, 45, 45, 255, 255, 45, 45,
but to but to
255, 0, 45, 128, 0, 72. 255, 0, 45, 127, 0, 73.
The above is sufficient to reconstruct line numbers for tracebacks, but not for The above is sufficient to reconstruct line numbers for tracebacks, but not for
line tracing. Tracing is handled by PyCode_CheckLineNumber() in codeobject.c line tracing. Tracing is handled by PyCode_CheckLineNumber() in codeobject.c
@ -83,30 +85,34 @@ Consider this code:
1: def f(a): 1: def f(a):
2: while a: 2: while a:
3: print 1, 3: print(1)
4: break 4: break
5: else: 5: else:
6: print 2, 6: print(2)
which compiles to this: which compiles to this:
2 0 SETUP_LOOP 19 (to 22) 2 0 SETUP_LOOP 26 (to 28)
>> 3 LOAD_FAST 0 (a) >> 2 LOAD_FAST 0 (a)
6 POP_JUMP_IF_FALSE 17 4 POP_JUMP_IF_FALSE 18
3 9 LOAD_CONST 1 (1) 3 6 LOAD_GLOBAL 0 (print)
12 PRINT_ITEM 8 LOAD_CONST 1 (1)
10 CALL_FUNCTION 1
12 POP_TOP
4 13 BREAK_LOOP 4 14 BREAK_LOOP
14 JUMP_ABSOLUTE 3 16 JUMP_ABSOLUTE 2
>> 17 POP_BLOCK >> 18 POP_BLOCK
6 18 LOAD_CONST 2 (2) 6 20 LOAD_GLOBAL 0 (print)
21 PRINT_ITEM 22 LOAD_CONST 2 (2)
>> 22 LOAD_CONST 0 (None) 24 CALL_FUNCTION 1
25 RETURN_VALUE 26 POP_TOP
>> 28 LOAD_CONST 0 (None)
30 RETURN_VALUE
If 'a' is false, execution will jump to the POP_BLOCK instruction at offset 17 If 'a' is false, execution will jump to the POP_BLOCK instruction at offset 18
and the co_lnotab will claim that execution has moved to line 4, which is wrong. and the co_lnotab will claim that execution has moved to line 4, which is wrong.
In this case, we could instead associate the POP_BLOCK with line 5, but that In this case, we could instead associate the POP_BLOCK with line 5, but that
would break jumps around loops without else clauses. would break jumps around loops without else clauses.