From c2e2639ff7d36b3ff88107cf05c4644b257eb366 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Tue, 14 Mar 2017 09:23:20 +0100 Subject: [PATCH 1/3] Update lnotab_notes.txt --- Objects/lnotab_notes.txt | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/Objects/lnotab_notes.txt b/Objects/lnotab_notes.txt index 515375772e6317..ed293a0bbf1d90 100644 --- a/Objects/lnotab_notes.txt +++ b/Objects/lnotab_notes.txt @@ -45,7 +45,8 @@ above example contains two such values. So we make two tweaks: line_incr -= 0x100 lineno += line_incr -(In C, this is implemented by PyCode_Addr2Line().) In order for this to work, +(In C, this is implemented by PyCode_Addr2Line(). Note that before 3.6, only +positive line_incr's were supported.) In order for this to work, when the addr field increments by more than 255, the line # increment in each pair generated must be 0 until the remaining addr increment is < 256. So, in the example above, assemble_lnotab in compile.c should not (as was actually done @@ -83,30 +84,34 @@ Consider this code: 1: def f(a): 2: while a: -3: print 1, +3: print(1) 4: break 5: else: -6: print 2, +6: print(2) which compiles to this: - 2 0 SETUP_LOOP 19 (to 22) - >> 3 LOAD_FAST 0 (a) - 6 POP_JUMP_IF_FALSE 17 + 2 0 SETUP_LOOP 26 (to 28) + >> 2 LOAD_FAST 0 (a) + 4 POP_JUMP_IF_FALSE 18 - 3 9 LOAD_CONST 1 (1) - 12 PRINT_ITEM + 3 6 LOAD_GLOBAL 0 (print) + 8 LOAD_CONST 1 (1) + 10 CALL_FUNCTION 1 + 12 POP_TOP - 4 13 BREAK_LOOP - 14 JUMP_ABSOLUTE 3 - >> 17 POP_BLOCK + 4 14 BREAK_LOOP + 16 JUMP_ABSOLUTE 2 + >> 18 POP_BLOCK - 6 18 LOAD_CONST 2 (2) - 21 PRINT_ITEM - >> 22 LOAD_CONST 0 (None) - 25 RETURN_VALUE + 6 20 LOAD_GLOBAL 0 (print) + 22 LOAD_CONST 2 (2) + 24 CALL_FUNCTION 1 + 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. In this case, we could instead associate the POP_BLOCK with line 5, but that would break jumps around loops without else clauses. From c1a265814734048c114f0c0fc8c92893773dac76 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Tue, 14 Mar 2017 14:43:35 +0100 Subject: [PATCH 2/3] Response to comments --- Objects/lnotab_notes.txt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Objects/lnotab_notes.txt b/Objects/lnotab_notes.txt index ed293a0bbf1d90..3b897d87f536dd 100644 --- a/Objects/lnotab_notes.txt +++ b/Objects/lnotab_notes.txt @@ -1,8 +1,9 @@ All about co_lnotab, the line number table. 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 -line #s for tracebacks and to identify line number boundaries for line tracing. +disguised as a Python bytes object. It is used to map bytecode offsets to +source code line #s for tracebacks and to identify line number boundaries for +line tracing. The array is conceptually a compressed list of (bytecode offset increment, line number increment) @@ -24,7 +25,8 @@ look like: 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 (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, and @@ -45,15 +47,14 @@ above example contains two such values. So we make two tweaks: line_incr -= 0x100 lineno += line_incr -(In C, this is implemented by PyCode_Addr2Line(). Note that before 3.6, only -positive line_incr's were supported.) In order for this to work, +(In C, this is implemented by PyCode_Addr2Line().) In order for this to work, when the addr field increments by more than 255, the line # increment in each pair generated must be 0 until the remaining addr increment is < 256. So, in the example above, assemble_lnotab in compile.c should not (as was actually done until 2.2) expand 300, 200 to 255, 255, 45, 45, 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 line tracing. Tracing is handled by PyCode_CheckLineNumber() in codeobject.c From 2926726f2f2e2c28aacc30dc1f19b2c4c746bd5f Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Tue, 14 Mar 2017 17:48:45 +0100 Subject: [PATCH 3/3] Replace tabs with spaces --- Objects/lnotab_notes.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Objects/lnotab_notes.txt b/Objects/lnotab_notes.txt index 3b897d87f536dd..3dab2b98661695 100644 --- a/Objects/lnotab_notes.txt +++ b/Objects/lnotab_notes.txt @@ -10,9 +10,9 @@ The array is conceptually a compressed list of pairs. The details are important and delicate, best illustrated by example: byte code offset source code line number - 0 1 - 6 2 - 50 7 + 0 1 + 6 2 + 50 7 350 207 361 208