Skip to content

gh-112720: make it easier to subclass and modify dis.ArgResolver's jump arg resolution #115564

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 deletions Lib/dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,20 @@ def __init__(self, co_consts=None, names=None, varname_from_oparg=None, labels_m
self.varname_from_oparg = varname_from_oparg
self.labels_map = labels_map or {}

def offset_from_jump_arg(self, op, arg, offset):
deop = _deoptop(op)
if deop in hasjabs:
return arg * 2
elif deop in hasjrel:
signed_arg = -arg if _is_backward_jump(deop) else arg
argval = offset + 2 + signed_arg*2
caches = _get_cache_size(_all_opname[deop])
argval += 2 * caches
if deop == ENTER_EXECUTOR:
argval += 2
return argval
return None

def get_label_for_offset(self, offset):
return self.labels_map.get(offset, None)

Expand Down Expand Up @@ -536,17 +550,11 @@ def get_argval_argrepr(self, op, arg, offset):
argrepr = f"{argrepr} + NULL|self"
else:
argval, argrepr = _get_name_info(arg, get_name)
elif deop in hasjabs:
argval = arg*2
argrepr = f"to L{self.labels_map[argval]}"
elif deop in hasjrel:
signed_arg = -arg if _is_backward_jump(deop) else arg
argval = offset + 2 + signed_arg*2
caches = _get_cache_size(_all_opname[deop])
argval += 2 * caches
if deop == ENTER_EXECUTOR:
argval += 2
argrepr = f"to L{self.labels_map[argval]}"
elif deop in hasjump or deop in hasexc:
argval = self.offset_from_jump_arg(op, arg, offset)
lbl = self.get_label_for_offset(argval)
assert lbl is not None
argrepr = f"to L{lbl}"
elif deop in (LOAD_FAST_LOAD_FAST, STORE_FAST_LOAD_FAST, STORE_FAST_STORE_FAST):
arg1 = arg >> 4
arg2 = arg & 15
Expand Down
16 changes: 16 additions & 0 deletions Lib/test/test_dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -1986,6 +1986,22 @@ def f(opcode, oparg, offset, *init_args):
self.assertEqual(f(opcode.opmap["BINARY_OP"], 3, *args), (3, '<<'))
self.assertEqual(f(opcode.opmap["CALL_INTRINSIC_1"], 2, *args), (2, 'INTRINSIC_IMPORT_STAR'))

def test_custom_arg_resolver(self):
class MyArgResolver(dis.ArgResolver):
def offset_from_jump_arg(self, op, arg, offset):
return arg + 1

def get_label_for_offset(self, offset):
return 2 * offset

def f(opcode, oparg, offset, *init_args):
arg_resolver = MyArgResolver(*init_args)
return arg_resolver.get_argval_argrepr(opcode, oparg, offset)
offset = 42
self.assertEqual(f(opcode.opmap["JUMP_BACKWARD"], 1, offset), (2, 'to L4'))
self.assertEqual(f(opcode.opmap["SETUP_FINALLY"], 2, offset), (3, 'to L6'))


def get_instructions(self, code):
return dis._get_instructions_bytes(code)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Refactor :class:`dis.ArgResolver` to make it possible to subclass and change
the way jump args are interpreted.