Mercurial > cpython-lru_cache-weakref
comparison Python/compile.c @ 18065:889db6d55506 legacy-trunk
SF bug 430991: wrong co_lnotab
Armin Rigo pointed out that the way the line-# table got built didn't work
for lines generating more than 255 bytes of bytecode. Fixed as he
suggested, plus corresponding changes to pyassem.py, plus added some
long overdue docs about this subtle table to compile.c.
Bugfix candidate (line numbers may be off in tracebacks under -O).
| author | Tim Peters <tim.peters@gmail.com> |
|---|---|
| date | Sat, 09 Jun 2001 09:26:21 +0000 |
| parents | 437482fe55e6 |
| children | 7bc473b2c654 |
comparison
equal
deleted
inserted
replaced
| 18064:ac5489a2548d | 18065:889db6d55506 |
|---|---|
| 332 | 332 |
| 333 The two passes communicate via symtable_load_symbols() and via | 333 The two passes communicate via symtable_load_symbols() and via |
| 334 is_local() and is_global(). The former initializes several slots | 334 is_local() and is_global(). The former initializes several slots |
| 335 in the compiling struct: c_varnames, c_locals, c_nlocals, | 335 in the compiling struct: c_varnames, c_locals, c_nlocals, |
| 336 c_argcount, c_globals, and c_flags. | 336 c_argcount, c_globals, and c_flags. |
| 337 */ | |
| 338 | |
| 339 /* All about c_lnotab. | |
| 340 | |
| 341 c_lnotab is an array of unsigned bytes disguised as a Python string. In -O | |
| 342 mode, SET_LINENO opcodes aren't generated, and bytecode offsets are mapped | |
| 343 to source code line #s (when needed for tracebacks) via c_lnotab instead. | |
| 344 The array is conceptually a list of | |
| 345 (bytecode offset increment, line number increment) | |
| 346 pairs. The details are important and delicate, best illustrated by example: | |
| 347 | |
| 348 byte code offset source code line number | |
| 349 0 1 | |
| 350 6 2 | |
| 351 50 7 | |
| 352 350 307 | |
| 353 361 308 | |
| 354 | |
| 355 The first trick is that these numbers aren't stored, only the increments | |
| 356 from one row to the next (this doesn't really work, but it's a start): | |
| 357 | |
| 358 0, 1, 6, 1, 44, 5, 300, 300, 11, 1 | |
| 359 | |
| 360 The second trick is that an unsigned byte can't hold negative values, or | |
| 361 values larger than 255, so (a) there's a deep assumption that byte code | |
| 362 offsets and their corresponding line #s both increase monotonically, and (b) | |
| 363 if at least one column jumps by more than 255 from one row to the next, more | |
| 364 than one pair is written to the table. In case #b, there's no way to know | |
| 365 from looking at the table later how many were written. That's the delicate | |
| 366 part. A user of c_lnotab desiring to find the source line number | |
| 367 corresponding to a bytecode address A should do something like this | |
| 368 | |
| 369 lineno = addr = 0 | |
| 370 for addr_incr, line_incr in c_lnotab: | |
| 371 addr += addr_incr | |
| 372 if addr > A: | |
| 373 return lineno | |
| 374 lineno += line_incr | |
| 375 | |
| 376 In order for this to work, when the addr field increments by more than 255, | |
| 377 the line # increment in each pair generated must be 0 until the remaining addr | |
| 378 increment is < 256. So, in the example above, com_set_lineno should not (as | |
| 379 was actually done until 2.2) expand 300, 300 to 255, 255, 45, 45, but to | |
| 380 255, 0, 45, 255, 0, 45. | |
| 337 */ | 381 */ |
| 338 | 382 |
| 339 struct compiling { | 383 struct compiling { |
| 340 PyObject *c_code; /* string */ | 384 PyObject *c_code; /* string */ |
| 341 PyObject *c_consts; /* list of objects */ | 385 PyObject *c_consts; /* list of objects */ |
| 690 c->c_firstlineno = c->c_last_line = lineno; | 734 c->c_firstlineno = c->c_last_line = lineno; |
| 691 } | 735 } |
| 692 else { | 736 else { |
| 693 int incr_addr = c->c_nexti - c->c_last_addr; | 737 int incr_addr = c->c_nexti - c->c_last_addr; |
| 694 int incr_line = lineno - c->c_last_line; | 738 int incr_line = lineno - c->c_last_line; |
| 695 while (incr_addr > 0 || incr_line > 0) { | 739 while (incr_addr > 255) { |
| 696 int trunc_addr = incr_addr; | 740 com_add_lnotab(c, 255, 0); |
| 697 int trunc_line = incr_line; | 741 incr_addr -= 255; |
| 698 if (trunc_addr > 255) | 742 } |
| 699 trunc_addr = 255; | 743 while (incr_line > 255) { |
| 700 if (trunc_line > 255) | 744 com_add_lnotab(c, incr_addr, 255); |
| 701 trunc_line = 255; | 745 incr_line -=255; |
| 702 com_add_lnotab(c, trunc_addr, trunc_line); | 746 incr_addr = 0; |
| 703 incr_addr -= trunc_addr; | 747 } |
| 704 incr_line -= trunc_line; | 748 if (incr_addr > 0 || incr_line > 0) |
| 705 } | 749 com_add_lnotab(c, incr_addr, incr_line); |
| 706 c->c_last_addr = c->c_nexti; | 750 c->c_last_addr = c->c_nexti; |
| 707 c->c_last_line = lineno; | 751 c->c_last_line = lineno; |
| 708 } | 752 } |
| 709 } | 753 } |
| 710 | 754 |
