Skip to content

Commit 6c8fab7

Browse files
author
rocky
committed
tolerates compatible Instruction nametuples
The control-flow project uses a compatible Instruction nametuple, ExtendedInstruction. To make this possible, we should not call Instruction, but self.__class__ to accomodate such extension.
1 parent 05eb0e0 commit 6c8fab7

File tree

2 files changed

+27
-21
lines changed

2 files changed

+27
-21
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ default_language_version:
22
python: python
33
repos:
44
- repo: https://github.com/pre-commit/pre-commit-hooks
5-
rev: v4.0.1
5+
rev: v4.5.0
66
hooks:
77
- id: check-merge-conflict
88
- id: debug-statements
@@ -15,10 +15,3 @@ repos:
1515
hooks:
1616
- id: isort
1717
stages: [commit]
18-
- repo: https://github.com/psf/black
19-
rev: 23.12.1
20-
hooks:
21-
- id: black
22-
language_version: python3
23-
stages: [commit]
24-
exclude: 'trepan/version.py'

xdis/instruction.py

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,8 @@ class Instruction(NamedTuple):
126126
arg: Optional numeric argument to operation (if any). Otherwise, None.
127127
128128
argval: resolved arg value (if known). Otherwise, the same as ``arg``.
129-
argrepr: human-readable description of operation argument.
130129
131-
tos_str: If not None, a string representation of the top of the stack (TOS).
132-
This is obtained by scanning previous instructions and
133-
using information there and in their ``tos_str`` fields.
130+
argrepr: human-readable description of operation argument.
134131
135132
positions: Optional dis.Positions object holding the start and end locations that
136133
are covered by this instruction. This not implemented yet.
@@ -148,6 +145,14 @@ class Instruction(NamedTuple):
148145
instruction. Note conditionals are in this category, but
149146
returns, raise, and unconditional jumps are not.
150147
148+
Note: the following fields have to appear in the order below and be at the end.
149+
disassembly may replace (delete and insert) an instruction, and it assumes
150+
the ending fields are as follows:
151+
152+
tos_str: If not None, a string representation of the top of the stack (TOS).
153+
This is obtained by scanning previous instructions and
154+
using information there and in their ``tos_str`` fields.
155+
151156
start_offset: if not None the instruction with the lowest offset that
152157
pushes a stack entry that is consume by this opcode
153158
"""
@@ -305,6 +310,7 @@ def disassemble(
305310

306311
# Column: Opcode argument
307312
if self.arg is not None:
313+
308314
argrepr = self.argrepr
309315
# The ``argrepr`` value when the instruction was created
310316
# generally has all the information we require. However,
@@ -337,14 +343,18 @@ def disassemble(
337343
):
338344
new_instruction = list(self)
339345
new_instruction[-2] = f"To line {line_starts[self.argval]}"
340-
self = Instruction(*new_instruction)
346+
# Here and below we use self.__class__ instead of Instruction
347+
# so that other kinds of compatible namedtuple Instructions
348+
# can be used. In particular, the control-flow project
349+
# defines such an ExtendedInstruction namedtuple
350+
self = self.__class__(*new_instruction)
341351
del instructions[-1]
342352
instructions.append(self)
343353
elif (
344354
hasattr(opc, "opcode_extended_fmt")
345-
and opc.opname[opcode] in opc.opcode_extended_fmt
355+
and self.opname in opc.opcode_extended_fmt
346356
):
347-
new_repr = opc.opcode_extended_fmt[opc.opname[opcode]](
357+
new_repr = opc.opcode_extended_fmt.get(self.opname, lambda opc, instr: None)(
348358
opc, list(reversed(instructions))
349359
)
350360
start_offset = None
@@ -357,15 +367,17 @@ def disassemble(
357367
new_instruction[-1] = start_offset
358368
new_instruction[-2] = new_repr
359369
del instructions[-1]
360-
self = Instruction(*new_instruction)
370+
# See comment above abut the use of self.__class__
371+
self = self.__class__(*new_instruction)
361372
instructions.append(self)
362373
argrepr = new_repr
363374
elif opcode in opc.nullaryloadop:
364375
new_instruction = list(self)
365376
new_instruction[-2] = self.argrepr
366377
start_offset = new_instruction[-1] = self.offset
367378
del instructions[-1]
368-
self = Instruction(*new_instruction)
379+
# See comment above abut the use of self.__class__
380+
self = self.__class__(*new_instruction)
369381
instructions.append(self)
370382
pass
371383
if not argrepr:
@@ -396,17 +408,18 @@ def disassemble(
396408
elif asm_format in ("extended", "extended-bytes"):
397409
if (
398410
hasattr(opc, "opcode_extended_fmt")
399-
and opc.opname[opcode] in opc.opcode_extended_fmt
411+
and self.opname in opc.opcode_extended_fmt
400412
):
401-
new_repr, start_offset = opc.opcode_extended_fmt[opc.opname[opcode]](
413+
new_repr, start_offset = opc.opcode_extended_fmt.get(self.opname, (None, 0))(
402414
opc, list(reversed(instructions))
403415
)
404416
if new_repr:
405417
new_instruction = list(self)
406418
new_instruction[-2] = new_repr
407419
new_instruction[-1] = start_offset
408420
del instructions[-1]
409-
instructions.append(Instruction(*new_instruction))
421+
# See comment above abut the use of self.__class__
422+
instructions.append(self.__class__(*new_instruction))
410423
argval = self.argval
411424
prefix = "" if argval is None else f"({argval}) | "
412425
if self.opcode in opc.operator_set:
@@ -415,7 +428,7 @@ def disassemble(
415428
pass
416429
elif (
417430
hasattr(opc, "opcode_arg_fmt")
418-
and opc.opname[opcode] in opc.opcode_arg_fmt
431+
and self.opname in opc.opcode_arg_fmt
419432
) and self.argrepr is not None:
420433
fields.append(self.argrepr)
421434
pass

0 commit comments

Comments
 (0)