mirror of https://github.com/python/cpython
bpo-28810: Update lnotab_notes.txt (#665)
This commit is contained in:
parent
2e4e011795
commit
9135275cba
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue