Skip to content

Commit 852c5c4

Browse files
committed
distinguish between jump targets (J) and exception handlers (H)
1 parent 6ac23fd commit 852c5c4

File tree

3 files changed

+96
-75
lines changed

3 files changed

+96
-75
lines changed

Doc/whatsnew/3.13.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,13 @@ copy
168168
any user classes which define the :meth:`!__replace__` method.
169169
(Contributed by Serhiy Storchaka in :gh:`108751`.)
170170

171+
dis
172+
---
173+
174+
* Change the output of :mod:`dis` module functions to show logical
175+
labels for jump targets and exception handlers, rather than offsets.
176+
(Contributed by Irit Katriel in :gh:`112137`.)
177+
171178
dbm
172179
---
173180

Lib/dis.py

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -284,9 +284,12 @@ def show_code(co, *, file=None):
284284
_Instruction.label.__doc__ = "A label (int > 0) if this instruction is a jump target, otherwise None"
285285
_Instruction.positions.__doc__ = "dis.Positions object holding the span of source code covered by this instruction"
286286

287-
_ExceptionTableEntry = collections.namedtuple("_ExceptionTableEntry",
287+
_ExceptionTableEntryBase = collections.namedtuple("_ExceptionTableEntryBase",
288288
"start end target depth lasti")
289289

290+
class _ExceptionTableEntry(_ExceptionTableEntryBase):
291+
pass
292+
290293
_OPNAME_WIDTH = 20
291294
_OPARG_WIDTH = 5
292295

@@ -311,12 +314,13 @@ def _get_jump_target(op, arg, offset):
311314
target = None
312315
return target
313316

314-
def _label_string(label, width=None, suffix=''):
315-
if label is not None:
317+
def _label_string(label_info, width=None, suffix=''):
318+
if label_info is not None:
319+
label, prefix = label_info
316320
lbl = f'{label}'
317321
padding = width - len(lbl) if width is not None else 0
318322
assert padding >= 0
319-
return f"L{lbl}{suffix}{'':<{padding}}"
323+
return f"{prefix}{lbl}{suffix}{'':<{padding}}"
320324
else:
321325
return ' ' * (width + 1 + len(suffix))
322326

@@ -334,7 +338,7 @@ class Instruction(_Instruction):
334338
otherwise equal to Instruction.offset
335339
starts_line - True if this opcode starts a source line, otherwise False
336340
line_number - source line number associated with this opcode (if any), otherwise None
337-
label - A label (int > 0) if this instruction is a jump target, otherwise None
341+
label - A label if this instruction is a jump target, otherwise None
338342
positions - Optional dis.Positions object holding the span of source code
339343
covered by this instruction
340344
"""
@@ -421,7 +425,8 @@ def _create(cls, op, arg, offset, start_offset, starts_line, line_number,
421425
label = labels_map.get(offset, None)
422426
instr = Instruction(_all_opname[op], op, arg, argval, argrepr,
423427
offset, start_offset, starts_line, line_number,
424-
label, positions)
428+
label[0] if label else None, positions)
429+
instr.label_info = label
425430
instr.label_width = label_width
426431
return instr
427432

@@ -491,7 +496,9 @@ def _disassemble(self, lineno_width=3, mark_as_current=False, offset_width=4):
491496
else:
492497
fields.append(' ')
493498
# Column: Jump target marker
494-
fields.append(_label_string(self.label, width=self.label_width, suffix=': '))
499+
fields.append(_label_string(self.label_info,
500+
width=self.label_width,
501+
suffix=': '))
495502
# Column: Opcode name
496503
fields.append(self.opname.ljust(_OPNAME_WIDTH))
497504
# Column: Opcode argument
@@ -624,11 +631,17 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
624631
get_name = None if names is None else names.__getitem__
625632

626633
def make_labels_map(original_code, exception_entries):
627-
labels = set(findlabels(original_code))
634+
jump_targets = set(findlabels(original_code))
635+
labels = set(jump_targets)
628636
for start, end, target, _, _ in exception_entries:
629637
for i in range(start, end):
630638
labels.add(target)
631-
return {offset: i+1 for (i, offset) in enumerate(sorted(labels))}
639+
labels = sorted(labels)
640+
labels_map = {offset: (i+1, 'J' if offset in jump_targets else 'H')
641+
for (i, offset) in enumerate(sorted(labels))}
642+
for e in exception_entries:
643+
e.target_label = labels_map[e.target][0]
644+
return labels_map
632645

633646
labels_map = make_labels_map(original_code, exception_entries)
634647

@@ -752,7 +765,8 @@ def _disassemble_bytes(code, lasti=-1, varname_from_oparg=None,
752765
for entry in exception_entries:
753766
lasti = " lasti" if entry.lasti else ""
754767
end = entry.end-2
755-
print(f" {entry.start} to {end} -> {entry.target} [{entry.depth}]{lasti}", file=file)
768+
target_lbl = entry.target_label
769+
print(f" {entry.start} to {end} -> H{target_lbl} [{entry.depth}]{lasti}", file=file)
756770

757771
def _disassemble_str(source, **kwargs):
758772
"""Compile the source string, then disassemble the code object."""

0 commit comments

Comments
 (0)