Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b2af50c

Browse files
authored
gh-111969: refactor to make it easier to construct a dis.Instruction object (#111970)
1 parent 40752c1 commit b2af50c

2 files changed

Lines changed: 101 additions & 64 deletions

File tree

Lib/dis.py

Lines changed: 84 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,84 @@ class Instruction(_Instruction):
330330
covered by this instruction
331331
"""
332332

333+
@staticmethod
334+
def _get_argval_argrepr(op, arg, offset, co_consts, names, varname_from_oparg):
335+
get_name = None if names is None else names.__getitem__
336+
argval = None
337+
argrepr = ''
338+
deop = _deoptop(op)
339+
if arg is not None:
340+
# Set argval to the dereferenced value of the argument when
341+
# available, and argrepr to the string representation of argval.
342+
# _disassemble_bytes needs the string repr of the
343+
# raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
344+
argval = arg
345+
if deop in hasconst:
346+
argval, argrepr = _get_const_info(deop, arg, co_consts)
347+
elif deop in hasname:
348+
if deop == LOAD_GLOBAL:
349+
argval, argrepr = _get_name_info(arg//2, get_name)
350+
if (arg & 1) and argrepr:
351+
argrepr = f"{argrepr} + NULL"
352+
elif deop == LOAD_ATTR:
353+
argval, argrepr = _get_name_info(arg//2, get_name)
354+
if (arg & 1) and argrepr:
355+
argrepr = f"{argrepr} + NULL|self"
356+
elif deop == LOAD_SUPER_ATTR:
357+
argval, argrepr = _get_name_info(arg//4, get_name)
358+
if (arg & 1) and argrepr:
359+
argrepr = f"{argrepr} + NULL|self"
360+
else:
361+
argval, argrepr = _get_name_info(arg, get_name)
362+
elif deop in hasjabs:
363+
argval = arg*2
364+
argrepr = "to " + repr(argval)
365+
elif deop in hasjrel:
366+
signed_arg = -arg if _is_backward_jump(deop) else arg
367+
argval = offset + 2 + signed_arg*2
368+
caches = _get_cache_size(_all_opname[deop])
369+
argval += 2 * caches
370+
argrepr = "to " + repr(argval)
371+
elif deop in (LOAD_FAST_LOAD_FAST, STORE_FAST_LOAD_FAST, STORE_FAST_STORE_FAST):
372+
arg1 = arg >> 4
373+
arg2 = arg & 15
374+
val1, argrepr1 = _get_name_info(arg1, varname_from_oparg)
375+
val2, argrepr2 = _get_name_info(arg2, varname_from_oparg)
376+
argrepr = argrepr1 + ", " + argrepr2
377+
argval = val1, val2
378+
elif deop in haslocal or deop in hasfree:
379+
argval, argrepr = _get_name_info(arg, varname_from_oparg)
380+
elif deop in hascompare:
381+
argval = cmp_op[arg >> 5]
382+
argrepr = argval
383+
if arg & 16:
384+
argrepr = f"bool({argrepr})"
385+
elif deop == CONVERT_VALUE:
386+
argval = (None, str, repr, ascii)[arg]
387+
argrepr = ('', 'str', 'repr', 'ascii')[arg]
388+
elif deop == SET_FUNCTION_ATTRIBUTE:
389+
argrepr = ', '.join(s for i, s in enumerate(FUNCTION_ATTR_FLAGS)
390+
if arg & (1<<i))
391+
elif deop == BINARY_OP:
392+
_, argrepr = _nb_ops[arg]
393+
elif deop == CALL_INTRINSIC_1:
394+
argrepr = _intrinsic_1_descs[arg]
395+
elif deop == CALL_INTRINSIC_2:
396+
argrepr = _intrinsic_2_descs[arg]
397+
return argval, argrepr
398+
399+
400+
@classmethod
401+
def _create(cls, op, arg, offset, start_offset, starts_line, line_number,
402+
is_jump_target, positions,
403+
co_consts=None, varname_from_oparg=None, names=None):
404+
argval, argrepr = cls._get_argval_argrepr(
405+
op, arg, offset,
406+
co_consts, names, varname_from_oparg)
407+
return Instruction(_all_opname[op], op, arg, argval, argrepr,
408+
offset, start_offset, starts_line, line_number,
409+
is_jump_target, positions)
410+
333411
@property
334412
def oparg(self):
335413
"""Alias for Instruction.arg."""
@@ -544,73 +622,15 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
544622
else:
545623
line_number = None
546624
is_jump_target = offset in labels
547-
argval = None
548-
argrepr = ''
549625
positions = Positions(*next(co_positions, ()))
550626
deop = _deoptop(op)
551-
caches = _get_cache_size(_all_opname[deop])
552627
op = code[offset]
553-
if arg is not None:
554-
# Set argval to the dereferenced value of the argument when
555-
# available, and argrepr to the string representation of argval.
556-
# _disassemble_bytes needs the string repr of the
557-
# raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
558-
argval = arg
559-
if deop in hasconst:
560-
argval, argrepr = _get_const_info(deop, arg, co_consts)
561-
elif deop in hasname:
562-
if deop == LOAD_GLOBAL:
563-
argval, argrepr = _get_name_info(arg//2, get_name)
564-
if (arg & 1) and argrepr:
565-
argrepr = f"{argrepr} + NULL"
566-
elif deop == LOAD_ATTR:
567-
argval, argrepr = _get_name_info(arg//2, get_name)
568-
if (arg & 1) and argrepr:
569-
argrepr = f"{argrepr} + NULL|self"
570-
elif deop == LOAD_SUPER_ATTR:
571-
argval, argrepr = _get_name_info(arg//4, get_name)
572-
if (arg & 1) and argrepr:
573-
argrepr = f"{argrepr} + NULL|self"
574-
else:
575-
argval, argrepr = _get_name_info(arg, get_name)
576-
elif deop in hasjabs:
577-
argval = arg*2
578-
argrepr = "to " + repr(argval)
579-
elif deop in hasjrel:
580-
signed_arg = -arg if _is_backward_jump(deop) else arg
581-
argval = offset + 2 + signed_arg*2
582-
argval += 2 * caches
583-
argrepr = "to " + repr(argval)
584-
elif deop in (LOAD_FAST_LOAD_FAST, STORE_FAST_LOAD_FAST, STORE_FAST_STORE_FAST):
585-
arg1 = arg >> 4
586-
arg2 = arg & 15
587-
val1, argrepr1 = _get_name_info(arg1, varname_from_oparg)
588-
val2, argrepr2 = _get_name_info(arg2, varname_from_oparg)
589-
argrepr = argrepr1 + ", " + argrepr2
590-
argval = val1, val2
591-
elif deop in haslocal or deop in hasfree:
592-
argval, argrepr = _get_name_info(arg, varname_from_oparg)
593-
elif deop in hascompare:
594-
argval = cmp_op[arg >> 5]
595-
argrepr = argval
596-
if arg & 16:
597-
argrepr = f"bool({argrepr})"
598-
elif deop == CONVERT_VALUE:
599-
argval = (None, str, repr, ascii)[arg]
600-
argrepr = ('', 'str', 'repr', 'ascii')[arg]
601-
elif deop == SET_FUNCTION_ATTRIBUTE:
602-
argrepr = ', '.join(s for i, s in enumerate(FUNCTION_ATTR_FLAGS)
603-
if arg & (1<<i))
604-
elif deop == BINARY_OP:
605-
_, argrepr = _nb_ops[arg]
606-
elif deop == CALL_INTRINSIC_1:
607-
argrepr = _intrinsic_1_descs[arg]
608-
elif deop == CALL_INTRINSIC_2:
609-
argrepr = _intrinsic_2_descs[arg]
610-
yield Instruction(_all_opname[op], op,
611-
arg, argval, argrepr,
612-
offset, start_offset, starts_line, line_number,
613-
is_jump_target, positions)
628+
629+
yield Instruction._create(op, arg, offset, start_offset, starts_line, line_number,
630+
is_jump_target, positions, co_consts=co_consts,
631+
varname_from_oparg=varname_from_oparg, names=names)
632+
633+
caches = _get_cache_size(_all_opname[deop])
614634
if not caches:
615635
continue
616636
if not show_caches:

Lib/test/test_dis.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2001,6 +2001,23 @@ def test_jump_target(self):
20012001
positions=None)
20022002
self.assertEqual(10 + 2 + 1*2 + 100*2, instruction.jump_target)
20032003

2004+
def test_argval_argrepr(self):
2005+
f = dis.Instruction._get_argval_argrepr
2006+
2007+
offset = 42
2008+
co_consts = (0, 1, 2, 3)
2009+
names = {1: 'a', 2: 'b'}
2010+
varname_from_oparg = lambda i : names[i]
2011+
args = (offset, co_consts, names, varname_from_oparg)
2012+
self.assertEqual(f(opcode.opmap["POP_TOP"], None, *args), (None, ''))
2013+
self.assertEqual(f(opcode.opmap["LOAD_CONST"], 1, *args), (1, '1'))
2014+
self.assertEqual(f(opcode.opmap["LOAD_GLOBAL"], 2, *args), ('a', 'a'))
2015+
self.assertEqual(f(opcode.opmap["JUMP_BACKWARD"], 11, *args), (24, 'to 24'))
2016+
self.assertEqual(f(opcode.opmap["COMPARE_OP"], 3, *args), ('<', '<'))
2017+
self.assertEqual(f(opcode.opmap["SET_FUNCTION_ATTRIBUTE"], 2, *args), (2, 'kwdefaults'))
2018+
self.assertEqual(f(opcode.opmap["BINARY_OP"], 3, *args), (3, '<<'))
2019+
self.assertEqual(f(opcode.opmap["CALL_INTRINSIC_1"], 2, *args), (2, 'INTRINSIC_IMPORT_STAR'))
2020+
20042021
def test_start_offset(self):
20052022
# When no extended args are present,
20062023
# start_offset should be equal to offset

0 commit comments

Comments
 (0)