]> granicus.if.org Git - python/commitdiff
bpo-28810: Update lnotab_notes.txt (#665)
authorIvan Levkivskyi <levkivskyi@gmail.com>
Tue, 14 Mar 2017 19:42:09 +0000 (20:42 +0100)
committerSerhiy Storchaka <storchaka@gmail.com>
Tue, 14 Mar 2017 19:42:09 +0000 (21:42 +0200)
Objects/lnotab_notes.txt

index 515375772e631713cff133a4de9a6042b763e89a..3dab2b98661695a6089d1668d0054c997df09efb 100644 (file)
@@ -1,17 +1,18 @@
 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)
 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
 
@@ -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
@@ -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
     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
@@ -83,30 +85,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.