diff -r 83814cdca928 Lib/dis.py --- a/Lib/dis.py Sun Feb 28 21:13:44 2016 +0100 +++ b/Lib/dis.py Sun Feb 28 12:57:16 2016 -0800 @@ -272,6 +272,23 @@ return argval, argrepr +def _scan_op_args(code): + """Iterate over code for the next op and arg, isolating EXTENDED_ARG handling.""" + extended_arg = 0 + next_i = 0 + n = len(code) + while next_i < n: + this_i = next_i + op = code[next_i] + next_i += 1 + if op < HAVE_ARGUMENT: + arg = None + else: + arg = code[next_i] + code[next_i+1]*256 + extended_arg*65536 + next_i += 2 + extended_arg = arg if op == EXTENDED_ARG else 0 + yield this_i, next_i, op, arg + def _get_instructions_bytes(code, varnames=None, names=None, constants=None, cells=None, linestarts=None, line_offset=0): """Iterate over the instructions in a bytecode string. @@ -283,33 +300,19 @@ """ labels = findlabels(code) - extended_arg = 0 starts_line = None - free = None - # enumerate() is not an option, since we sometimes process - # multiple elements on a single pass through the loop - n = len(code) - i = 0 - while i < n: - op = code[i] - offset = i + for i, offset, op, arg in _scan_op_args(code): if linestarts is not None: starts_line = linestarts.get(i, None) if starts_line is not None: starts_line += line_offset is_jump_target = i in labels - i = i+1 arg = None argval = None argrepr = '' - if op >= HAVE_ARGUMENT: - arg = code[i] + code[i+1]*256 + extended_arg - extended_arg = 0 - i = i+2 - if op == EXTENDED_ARG: - extended_arg = arg*65536 + if arg is not None: # Set argval to the dereferenced value of the argument when - # availabe, and argrepr to the string representation of argval. + # 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 @@ -318,7 +321,7 @@ elif op in hasname: argval, argrepr = _get_name_info(arg, names) elif op in hasjrel: - argval = i + arg + argval = offset + arg argrepr = "to " + repr(argval) elif op in haslocal: argval, argrepr = _get_name_info(arg, varnames) @@ -328,10 +331,10 @@ elif op in hasfree: argval, argrepr = _get_name_info(arg, cells) elif op in hasnargs: - argrepr = "%d positional, %d keyword pair" % (code[i-2], code[i-1]) + argrepr = "%d positional, %d keyword pair" % (code[offset-2], code[offset-1]) yield Instruction(opname[op], op, arg, argval, argrepr, - offset, starts_line, is_jump_target) + i, starts_line, is_jump_target) def disassemble(co, lasti=-1, *, file=None): """Disassemble a code object.""" @@ -371,24 +374,15 @@ """ labels = [] - # enumerate() is not an option, since we sometimes process - # multiple elements on a single pass through the loop - n = len(code) - i = 0 - while i < n: - op = code[i] - i = i+1 - if op >= HAVE_ARGUMENT: - arg = code[i] + code[i+1]*256 - i = i+2 + for _, offset, op, arg in _scan_op_args(code): + if arg is not None: label = -1 if op in hasjrel: - label = i+arg + label = offset+arg elif op in hasjabs: label = arg - if label >= 0: - if label not in labels: - labels.append(label) + if label >= 0 and label not in labels: + labels.append(label) return labels def findlinestarts(code):