mirror of
https://github.com/python/cpython
synced 2024-09-15 23:46:26 +00:00
gh-111969: refactor to make it easier to construct a dis.Instruction object (#111970)
This commit is contained in:
parent
40752c1c1e
commit
b2af50cb02
148
Lib/dis.py
148
Lib/dis.py
|
@ -330,6 +330,84 @@ class Instruction(_Instruction):
|
||||||
covered by this instruction
|
covered by this instruction
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_argval_argrepr(op, arg, offset, co_consts, names, varname_from_oparg):
|
||||||
|
get_name = None if names is None else names.__getitem__
|
||||||
|
argval = None
|
||||||
|
argrepr = ''
|
||||||
|
deop = _deoptop(op)
|
||||||
|
if arg is not None:
|
||||||
|
# Set argval to the dereferenced value of the argument when
|
||||||
|
# available, and argrepr to the string representation of argval.
|
||||||
|
# _disassemble_bytes needs the string repr of the
|
||||||
|
# raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
|
||||||
|
argval = arg
|
||||||
|
if deop in hasconst:
|
||||||
|
argval, argrepr = _get_const_info(deop, arg, co_consts)
|
||||||
|
elif deop in hasname:
|
||||||
|
if deop == LOAD_GLOBAL:
|
||||||
|
argval, argrepr = _get_name_info(arg//2, get_name)
|
||||||
|
if (arg & 1) and argrepr:
|
||||||
|
argrepr = f"{argrepr} + NULL"
|
||||||
|
elif deop == LOAD_ATTR:
|
||||||
|
argval, argrepr = _get_name_info(arg//2, get_name)
|
||||||
|
if (arg & 1) and argrepr:
|
||||||
|
argrepr = f"{argrepr} + NULL|self"
|
||||||
|
elif deop == LOAD_SUPER_ATTR:
|
||||||
|
argval, argrepr = _get_name_info(arg//4, get_name)
|
||||||
|
if (arg & 1) and argrepr:
|
||||||
|
argrepr = f"{argrepr} + NULL|self"
|
||||||
|
else:
|
||||||
|
argval, argrepr = _get_name_info(arg, get_name)
|
||||||
|
elif deop in hasjabs:
|
||||||
|
argval = arg*2
|
||||||
|
argrepr = "to " + repr(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
|
||||||
|
argrepr = "to " + repr(argval)
|
||||||
|
elif deop in (LOAD_FAST_LOAD_FAST, STORE_FAST_LOAD_FAST, STORE_FAST_STORE_FAST):
|
||||||
|
arg1 = arg >> 4
|
||||||
|
arg2 = arg & 15
|
||||||
|
val1, argrepr1 = _get_name_info(arg1, varname_from_oparg)
|
||||||
|
val2, argrepr2 = _get_name_info(arg2, varname_from_oparg)
|
||||||
|
argrepr = argrepr1 + ", " + argrepr2
|
||||||
|
argval = val1, val2
|
||||||
|
elif deop in haslocal or deop in hasfree:
|
||||||
|
argval, argrepr = _get_name_info(arg, varname_from_oparg)
|
||||||
|
elif deop in hascompare:
|
||||||
|
argval = cmp_op[arg >> 5]
|
||||||
|
argrepr = argval
|
||||||
|
if arg & 16:
|
||||||
|
argrepr = f"bool({argrepr})"
|
||||||
|
elif deop == CONVERT_VALUE:
|
||||||
|
argval = (None, str, repr, ascii)[arg]
|
||||||
|
argrepr = ('', 'str', 'repr', 'ascii')[arg]
|
||||||
|
elif deop == SET_FUNCTION_ATTRIBUTE:
|
||||||
|
argrepr = ', '.join(s for i, s in enumerate(FUNCTION_ATTR_FLAGS)
|
||||||
|
if arg & (1<<i))
|
||||||
|
elif deop == BINARY_OP:
|
||||||
|
_, argrepr = _nb_ops[arg]
|
||||||
|
elif deop == CALL_INTRINSIC_1:
|
||||||
|
argrepr = _intrinsic_1_descs[arg]
|
||||||
|
elif deop == CALL_INTRINSIC_2:
|
||||||
|
argrepr = _intrinsic_2_descs[arg]
|
||||||
|
return argval, argrepr
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _create(cls, op, arg, offset, start_offset, starts_line, line_number,
|
||||||
|
is_jump_target, positions,
|
||||||
|
co_consts=None, varname_from_oparg=None, names=None):
|
||||||
|
argval, argrepr = cls._get_argval_argrepr(
|
||||||
|
op, arg, offset,
|
||||||
|
co_consts, names, varname_from_oparg)
|
||||||
|
return Instruction(_all_opname[op], op, arg, argval, argrepr,
|
||||||
|
offset, start_offset, starts_line, line_number,
|
||||||
|
is_jump_target, positions)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def oparg(self):
|
def oparg(self):
|
||||||
"""Alias for Instruction.arg."""
|
"""Alias for Instruction.arg."""
|
||||||
|
@ -544,73 +622,15 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
|
||||||
else:
|
else:
|
||||||
line_number = None
|
line_number = None
|
||||||
is_jump_target = offset in labels
|
is_jump_target = offset in labels
|
||||||
argval = None
|
|
||||||
argrepr = ''
|
|
||||||
positions = Positions(*next(co_positions, ()))
|
positions = Positions(*next(co_positions, ()))
|
||||||
deop = _deoptop(op)
|
deop = _deoptop(op)
|
||||||
caches = _get_cache_size(_all_opname[deop])
|
|
||||||
op = code[offset]
|
op = code[offset]
|
||||||
if arg is not None:
|
|
||||||
# Set argval to the dereferenced value of the argument when
|
yield Instruction._create(op, arg, offset, start_offset, starts_line, line_number,
|
||||||
# available, and argrepr to the string representation of argval.
|
is_jump_target, positions, co_consts=co_consts,
|
||||||
# _disassemble_bytes needs the string repr of the
|
varname_from_oparg=varname_from_oparg, names=names)
|
||||||
# raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
|
|
||||||
argval = arg
|
caches = _get_cache_size(_all_opname[deop])
|
||||||
if deop in hasconst:
|
|
||||||
argval, argrepr = _get_const_info(deop, arg, co_consts)
|
|
||||||
elif deop in hasname:
|
|
||||||
if deop == LOAD_GLOBAL:
|
|
||||||
argval, argrepr = _get_name_info(arg//2, get_name)
|
|
||||||
if (arg & 1) and argrepr:
|
|
||||||
argrepr = f"{argrepr} + NULL"
|
|
||||||
elif deop == LOAD_ATTR:
|
|
||||||
argval, argrepr = _get_name_info(arg//2, get_name)
|
|
||||||
if (arg & 1) and argrepr:
|
|
||||||
argrepr = f"{argrepr} + NULL|self"
|
|
||||||
elif deop == LOAD_SUPER_ATTR:
|
|
||||||
argval, argrepr = _get_name_info(arg//4, get_name)
|
|
||||||
if (arg & 1) and argrepr:
|
|
||||||
argrepr = f"{argrepr} + NULL|self"
|
|
||||||
else:
|
|
||||||
argval, argrepr = _get_name_info(arg, get_name)
|
|
||||||
elif deop in hasjabs:
|
|
||||||
argval = arg*2
|
|
||||||
argrepr = "to " + repr(argval)
|
|
||||||
elif deop in hasjrel:
|
|
||||||
signed_arg = -arg if _is_backward_jump(deop) else arg
|
|
||||||
argval = offset + 2 + signed_arg*2
|
|
||||||
argval += 2 * caches
|
|
||||||
argrepr = "to " + repr(argval)
|
|
||||||
elif deop in (LOAD_FAST_LOAD_FAST, STORE_FAST_LOAD_FAST, STORE_FAST_STORE_FAST):
|
|
||||||
arg1 = arg >> 4
|
|
||||||
arg2 = arg & 15
|
|
||||||
val1, argrepr1 = _get_name_info(arg1, varname_from_oparg)
|
|
||||||
val2, argrepr2 = _get_name_info(arg2, varname_from_oparg)
|
|
||||||
argrepr = argrepr1 + ", " + argrepr2
|
|
||||||
argval = val1, val2
|
|
||||||
elif deop in haslocal or deop in hasfree:
|
|
||||||
argval, argrepr = _get_name_info(arg, varname_from_oparg)
|
|
||||||
elif deop in hascompare:
|
|
||||||
argval = cmp_op[arg >> 5]
|
|
||||||
argrepr = argval
|
|
||||||
if arg & 16:
|
|
||||||
argrepr = f"bool({argrepr})"
|
|
||||||
elif deop == CONVERT_VALUE:
|
|
||||||
argval = (None, str, repr, ascii)[arg]
|
|
||||||
argrepr = ('', 'str', 'repr', 'ascii')[arg]
|
|
||||||
elif deop == SET_FUNCTION_ATTRIBUTE:
|
|
||||||
argrepr = ', '.join(s for i, s in enumerate(FUNCTION_ATTR_FLAGS)
|
|
||||||
if arg & (1<<i))
|
|
||||||
elif deop == BINARY_OP:
|
|
||||||
_, argrepr = _nb_ops[arg]
|
|
||||||
elif deop == CALL_INTRINSIC_1:
|
|
||||||
argrepr = _intrinsic_1_descs[arg]
|
|
||||||
elif deop == CALL_INTRINSIC_2:
|
|
||||||
argrepr = _intrinsic_2_descs[arg]
|
|
||||||
yield Instruction(_all_opname[op], op,
|
|
||||||
arg, argval, argrepr,
|
|
||||||
offset, start_offset, starts_line, line_number,
|
|
||||||
is_jump_target, positions)
|
|
||||||
if not caches:
|
if not caches:
|
||||||
continue
|
continue
|
||||||
if not show_caches:
|
if not show_caches:
|
||||||
|
|
|
@ -2001,6 +2001,23 @@ def test_jump_target(self):
|
||||||
positions=None)
|
positions=None)
|
||||||
self.assertEqual(10 + 2 + 1*2 + 100*2, instruction.jump_target)
|
self.assertEqual(10 + 2 + 1*2 + 100*2, instruction.jump_target)
|
||||||
|
|
||||||
|
def test_argval_argrepr(self):
|
||||||
|
f = dis.Instruction._get_argval_argrepr
|
||||||
|
|
||||||
|
offset = 42
|
||||||
|
co_consts = (0, 1, 2, 3)
|
||||||
|
names = {1: 'a', 2: 'b'}
|
||||||
|
varname_from_oparg = lambda i : names[i]
|
||||||
|
args = (offset, co_consts, names, varname_from_oparg)
|
||||||
|
self.assertEqual(f(opcode.opmap["POP_TOP"], None, *args), (None, ''))
|
||||||
|
self.assertEqual(f(opcode.opmap["LOAD_CONST"], 1, *args), (1, '1'))
|
||||||
|
self.assertEqual(f(opcode.opmap["LOAD_GLOBAL"], 2, *args), ('a', 'a'))
|
||||||
|
self.assertEqual(f(opcode.opmap["JUMP_BACKWARD"], 11, *args), (24, 'to 24'))
|
||||||
|
self.assertEqual(f(opcode.opmap["COMPARE_OP"], 3, *args), ('<', '<'))
|
||||||
|
self.assertEqual(f(opcode.opmap["SET_FUNCTION_ATTRIBUTE"], 2, *args), (2, 'kwdefaults'))
|
||||||
|
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_start_offset(self):
|
def test_start_offset(self):
|
||||||
# When no extended args are present,
|
# When no extended args are present,
|
||||||
# start_offset should be equal to offset
|
# start_offset should be equal to offset
|
||||||
|
|
Loading…
Reference in a new issue