summaryrefslogtreecommitdiff
path: root/Lib/dis.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/dis.py')
-rw-r--r--Lib/dis.py70
1 files changed, 37 insertions, 33 deletions
diff --git a/Lib/dis.py b/Lib/dis.py
index 81cbe7f4f9..f7e3c7f8d7 100644
--- a/Lib/dis.py
+++ b/Lib/dis.py
@@ -13,7 +13,8 @@ __all__ = ["code_info", "dis", "disassemble", "distb", "disco",
"get_instructions", "Instruction", "Bytecode"] + _opcodes_all
del _opcodes_all
-_have_code = (types.MethodType, types.FunctionType, types.CodeType, type)
+_have_code = (types.MethodType, types.FunctionType, types.CodeType,
+ classmethod, staticmethod, type)
def _try_compile(source, name):
"""Attempts to compile the given source, first as an expression and
@@ -29,7 +30,7 @@ def _try_compile(source, name):
return c
def dis(x=None, *, file=None):
- """Disassemble classes, methods, functions, or code.
+ """Disassemble classes, methods, functions, generators, or code.
With no argument, disassemble the last traceback.
@@ -41,6 +42,8 @@ def dis(x=None, *, file=None):
x = x.__func__
if hasattr(x, '__code__'): # Function
x = x.__code__
+ if hasattr(x, 'gi_code'): # Generator
+ x = x.gi_code
if hasattr(x, '__dict__'): # Class or module
items = sorted(x.__dict__.items())
for name, x1 in items:
@@ -82,6 +85,8 @@ COMPILER_FLAG_NAMES = {
16: "NESTED",
32: "GENERATOR",
64: "NOFREE",
+ 128: "COROUTINE",
+ 256: "ITERABLE_COROUTINE",
}
def pretty_flags(flags):
@@ -99,11 +104,13 @@ def pretty_flags(flags):
return ", ".join(names)
def _get_code_object(x):
- """Helper to handle methods, functions, strings and raw code objects"""
+ """Helper to handle methods, functions, generators, strings and raw code objects"""
if hasattr(x, '__func__'): # Method
x = x.__func__
if hasattr(x, '__code__'): # Function
x = x.__code__
+ if hasattr(x, 'gi_code'): # Generator
+ x = x.gi_code
if isinstance(x, str): # Source code
x = _try_compile(x, "<disassembly>")
if hasattr(x, 'co_code'): # Code object
@@ -268,33 +275,19 @@ def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
"""
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 offset, op, arg in _unpack_opargs(code):
if linestarts is not None:
- starts_line = linestarts.get(i, None)
+ starts_line = linestarts.get(offset, None)
if starts_line is not None:
starts_line += line_offset
- is_jump_target = i in labels
- i = i+1
- arg = None
+ is_jump_target = offset in labels
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
@@ -303,7 +296,7 @@ def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
elif op in hasname:
argval, argrepr = _get_name_info(arg, names)
elif op in hasjrel:
- argval = i + arg
+ argval = offset + 3 + arg
argrepr = "to " + repr(argval)
elif op in haslocal:
argval, argrepr = _get_name_info(arg, varnames)
@@ -313,7 +306,7 @@ def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
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" % (arg%256, arg//256)
yield Instruction(opname[op], op,
arg, argval, argrepr,
offset, starts_line, is_jump_target)
@@ -349,26 +342,37 @@ def _disassemble_str(source, *, file=None):
disco = disassemble # XXX For backwards compatibility
-def findlabels(code):
- """Detect all offsets in a byte code which are jump targets.
-
- Return the list of offsets.
-
- """
- labels = []
+def _unpack_opargs(code):
# enumerate() is not an option, since we sometimes process
# multiple elements on a single pass through the loop
+ extended_arg = 0
n = len(code)
i = 0
while i < n:
op = code[i]
+ offset = i
i = i+1
+ arg = None
if op >= HAVE_ARGUMENT:
- arg = code[i] + code[i+1]*256
+ arg = code[i] + code[i+1]*256 + extended_arg
+ extended_arg = 0
i = i+2
+ if op == EXTENDED_ARG:
+ extended_arg = arg*65536
+ yield (offset, op, arg)
+
+def findlabels(code):
+ """Detect all offsets in a byte code which are jump targets.
+
+ Return the list of offsets.
+
+ """
+ labels = []
+ for offset, op, arg in _unpack_opargs(code):
+ if arg is not None:
label = -1
if op in hasjrel:
- label = i+arg
+ label = offset + 3 + arg
elif op in hasjabs:
label = arg
if label >= 0: