Skip to content

Commit 74e6f4b

Browse files
authored
gh-112720: make it easier to subclass and modify dis.ArgResolver's jump arg resolution (#115564)
1 parent f366e21 commit 74e6f4b

File tree

3 files changed

+37
-11
lines changed

3 files changed

+37
-11
lines changed

Lib/dis.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,20 @@ def __init__(self, co_consts=None, names=None, varname_from_oparg=None, labels_m
505505
self.varname_from_oparg = varname_from_oparg
506506
self.labels_map = labels_map or {}
507507

508+
def offset_from_jump_arg(self, op, arg, offset):
509+
deop = _deoptop(op)
510+
if deop in hasjabs:
511+
return arg * 2
512+
elif deop in hasjrel:
513+
signed_arg = -arg if _is_backward_jump(deop) else arg
514+
argval = offset + 2 + signed_arg*2
515+
caches = _get_cache_size(_all_opname[deop])
516+
argval += 2 * caches
517+
if deop == ENTER_EXECUTOR:
518+
argval += 2
519+
return argval
520+
return None
521+
508522
def get_label_for_offset(self, offset):
509523
return self.labels_map.get(offset, None)
510524

@@ -536,17 +550,11 @@ def get_argval_argrepr(self, op, arg, offset):
536550
argrepr = f"{argrepr} + NULL|self"
537551
else:
538552
argval, argrepr = _get_name_info(arg, get_name)
539-
elif deop in hasjabs:
540-
argval = arg*2
541-
argrepr = f"to L{self.labels_map[argval]}"
542-
elif deop in hasjrel:
543-
signed_arg = -arg if _is_backward_jump(deop) else arg
544-
argval = offset + 2 + signed_arg*2
545-
caches = _get_cache_size(_all_opname[deop])
546-
argval += 2 * caches
547-
if deop == ENTER_EXECUTOR:
548-
argval += 2
549-
argrepr = f"to L{self.labels_map[argval]}"
553+
elif deop in hasjump or deop in hasexc:
554+
argval = self.offset_from_jump_arg(op, arg, offset)
555+
lbl = self.get_label_for_offset(argval)
556+
assert lbl is not None
557+
argrepr = f"to L{lbl}"
550558
elif deop in (LOAD_FAST_LOAD_FAST, STORE_FAST_LOAD_FAST, STORE_FAST_STORE_FAST):
551559
arg1 = arg >> 4
552560
arg2 = arg & 15

Lib/test/test_dis.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1986,6 +1986,22 @@ def f(opcode, oparg, offset, *init_args):
19861986
self.assertEqual(f(opcode.opmap["BINARY_OP"], 3, *args), (3, '<<'))
19871987
self.assertEqual(f(opcode.opmap["CALL_INTRINSIC_1"], 2, *args), (2, 'INTRINSIC_IMPORT_STAR'))
19881988

1989+
def test_custom_arg_resolver(self):
1990+
class MyArgResolver(dis.ArgResolver):
1991+
def offset_from_jump_arg(self, op, arg, offset):
1992+
return arg + 1
1993+
1994+
def get_label_for_offset(self, offset):
1995+
return 2 * offset
1996+
1997+
def f(opcode, oparg, offset, *init_args):
1998+
arg_resolver = MyArgResolver(*init_args)
1999+
return arg_resolver.get_argval_argrepr(opcode, oparg, offset)
2000+
offset = 42
2001+
self.assertEqual(f(opcode.opmap["JUMP_BACKWARD"], 1, offset), (2, 'to L4'))
2002+
self.assertEqual(f(opcode.opmap["SETUP_FINALLY"], 2, offset), (3, 'to L6'))
2003+
2004+
19892005
def get_instructions(self, code):
19902006
return dis._get_instructions_bytes(code)
19912007

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Refactor :class:`dis.ArgResolver` to make it possible to subclass and change
2+
the way jump args are interpreted.

0 commit comments

Comments
 (0)