mirror of
https://github.com/python/cpython.git
synced 2025-08-22 09:45:06 +00:00
gh-107932: Fix dis module for bytecode that does not have an associated source line (GH-107988)
This commit is contained in:
parent
8d4052075e
commit
24aa249a66
5 changed files with 460 additions and 397 deletions
53
Lib/dis.py
53
Lib/dis.py
|
@ -262,6 +262,7 @@ _Instruction = collections.namedtuple(
|
|||
'offset',
|
||||
'start_offset',
|
||||
'starts_line',
|
||||
'line_number',
|
||||
'is_jump_target',
|
||||
'positions'
|
||||
],
|
||||
|
@ -278,7 +279,8 @@ _Instruction.start_offset.__doc__ = (
|
|||
"Start index of operation within bytecode sequence, including extended args if present; "
|
||||
"otherwise equal to Instruction.offset"
|
||||
)
|
||||
_Instruction.starts_line.__doc__ = "Line started by this opcode (if any), otherwise None"
|
||||
_Instruction.starts_line.__doc__ = "True if this opcode starts a source line, otherwise False"
|
||||
_Instruction.line_number.__doc__ = "source line number associated with this opcode (if any), otherwise None"
|
||||
_Instruction.is_jump_target.__doc__ = "True if other code jumps to here, otherwise False"
|
||||
_Instruction.positions.__doc__ = "dis.Positions object holding the span of source code covered by this instruction"
|
||||
|
||||
|
@ -321,7 +323,8 @@ class Instruction(_Instruction):
|
|||
offset - start index of operation within bytecode sequence
|
||||
start_offset - start index of operation within bytecode sequence including extended args if present;
|
||||
otherwise equal to Instruction.offset
|
||||
starts_line - line started by this opcode (if any), otherwise None
|
||||
starts_line - True if this opcode starts a source line, otherwise False
|
||||
line_number - source line number associated with this opcode (if any), otherwise None
|
||||
is_jump_target - True if other code jumps to here, otherwise False
|
||||
positions - Optional dis.Positions object holding the span of source code
|
||||
covered by this instruction
|
||||
|
@ -376,9 +379,10 @@ class Instruction(_Instruction):
|
|||
fields = []
|
||||
# Column: Source code line number
|
||||
if lineno_width:
|
||||
if self.starts_line is not None:
|
||||
lineno_fmt = "%%%dd" % lineno_width
|
||||
fields.append(lineno_fmt % self.starts_line)
|
||||
if self.starts_line:
|
||||
lineno_fmt = "%%%dd" if self.line_number is not None else "%%%ds"
|
||||
lineno_fmt = lineno_fmt % lineno_width
|
||||
fields.append(lineno_fmt % self.line_number)
|
||||
else:
|
||||
fields.append(' ' * lineno_width)
|
||||
# Column: Current instruction indicator
|
||||
|
@ -527,12 +531,18 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
|
|||
for start, end, target, _, _ in exception_entries:
|
||||
for i in range(start, end):
|
||||
labels.add(target)
|
||||
starts_line = None
|
||||
starts_line = False
|
||||
local_line_number = None
|
||||
line_number = None
|
||||
for offset, start_offset, op, arg in _unpack_opargs(original_code):
|
||||
if linestarts is not None:
|
||||
starts_line = linestarts.get(offset, None)
|
||||
if starts_line is not None:
|
||||
starts_line += line_offset
|
||||
starts_line = offset in linestarts
|
||||
if starts_line:
|
||||
local_line_number = linestarts[offset]
|
||||
if local_line_number is not None:
|
||||
line_number = local_line_number + line_offset
|
||||
else:
|
||||
line_number = None
|
||||
is_jump_target = offset in labels
|
||||
argval = None
|
||||
argrepr = ''
|
||||
|
@ -599,7 +609,8 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
|
|||
argrepr = _intrinsic_2_descs[arg]
|
||||
yield Instruction(_all_opname[op], op,
|
||||
arg, argval, argrepr,
|
||||
offset, start_offset, starts_line, is_jump_target, positions)
|
||||
offset, start_offset, starts_line, line_number,
|
||||
is_jump_target, positions)
|
||||
if not caches:
|
||||
continue
|
||||
if not show_caches:
|
||||
|
@ -618,7 +629,7 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
|
|||
else:
|
||||
argrepr = ""
|
||||
yield Instruction(
|
||||
"CACHE", CACHE, 0, None, argrepr, offset, offset, None, False,
|
||||
"CACHE", CACHE, 0, None, argrepr, offset, offset, False, None, False,
|
||||
Positions(*next(co_positions, ()))
|
||||
)
|
||||
|
||||
|
@ -651,13 +662,21 @@ def _disassemble_bytes(code, lasti=-1, varname_from_oparg=None,
|
|||
*, file=None, line_offset=0, exception_entries=(),
|
||||
co_positions=None, show_caches=False, original_code=None):
|
||||
# Omit the line number column entirely if we have no line number info
|
||||
show_lineno = bool(linestarts)
|
||||
if bool(linestarts):
|
||||
linestarts_ints = [line for line in linestarts.values() if line is not None]
|
||||
show_lineno = len(linestarts_ints) > 0
|
||||
else:
|
||||
show_lineno = False
|
||||
|
||||
if show_lineno:
|
||||
maxlineno = max(linestarts.values()) + line_offset
|
||||
maxlineno = max(linestarts_ints) + line_offset
|
||||
if maxlineno >= 1000:
|
||||
lineno_width = len(str(maxlineno))
|
||||
else:
|
||||
lineno_width = 3
|
||||
|
||||
if lineno_width < len(str(None)) and None in linestarts.values():
|
||||
lineno_width = len(str(None))
|
||||
else:
|
||||
lineno_width = 0
|
||||
maxoffset = len(code) - 2
|
||||
|
@ -673,7 +692,7 @@ def _disassemble_bytes(code, lasti=-1, varname_from_oparg=None,
|
|||
show_caches=show_caches,
|
||||
original_code=original_code):
|
||||
new_source_line = (show_lineno and
|
||||
instr.starts_line is not None and
|
||||
instr.starts_line and
|
||||
instr.offset > 0)
|
||||
if new_source_line:
|
||||
print(file=file)
|
||||
|
@ -755,10 +774,12 @@ def findlinestarts(code):
|
|||
"""Find the offsets in a byte code which are start of lines in the source.
|
||||
|
||||
Generate pairs (offset, lineno)
|
||||
lineno will be an integer or None the offset does not have a source line.
|
||||
"""
|
||||
lastline = None
|
||||
|
||||
lastline = False # None is a valid line number
|
||||
for start, end, line in code.co_lines():
|
||||
if line is not None and line != lastline:
|
||||
if line is not lastline:
|
||||
lastline = line
|
||||
yield start, line
|
||||
return
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue