[pypy-svn] rev 2497 - pypy/trunk/src/pypy/tool
hpk at codespeak.net
hpk at codespeak.net
Thu Dec 18 14:27:59 CET 2003
Author: hpk
Date: Thu Dec 18 14:27:59 2003
New Revision: 2497
Added:
pypy/trunk/src/pypy/tool/opcode.py
- copied unchanged from rev 2312, xpython/trunk/dist/src/Lib/opcode.py
pypy/trunk/src/pypy/tool/pydis.py
- copied, changed from rev 2312, xpython/trunk/dist/src/Lib/dis.py
Log:
rewrote the python-2.3 dis.dis module, which is now in
pypy/tool/pydis.py
and will return a DisResult instance on invoking "pydis.pydis(object)"
This allows to programmatically access the results of dissassembled
byte code and will be used from the trace object space.
(Holger, Richard)
Copied: pypy/trunk/src/pypy/tool/pydis.py (from rev 2312, xpython/trunk/dist/src/Lib/dis.py)
==============================================================================
--- xpython/trunk/dist/src/Lib/dis.py (original)
+++ pypy/trunk/src/pypy/tool/pydis.py Thu Dec 18 14:27:59 2003
@@ -1,18 +1,91 @@
-"""Disassembler of Python byte code into mnemonics."""
+"""disassembler of Python byte code into mnemonics.
+XXX this only works for python-2.3 because of the linenumber
+ optimization
+
+"""
+
+import autopath
import sys
import types
-from opcode import *
-from opcode import __all__ as _opcodes_all
+from pypy.tool.opcode import *
+from pypy.tool.opcode import __all__ as _opcodes_all
-__all__ = ["dis","disassemble","distb","disco"] + _opcodes_all
+__all__ = ["dis","pydisassemble","distb","disco"] + _opcodes_all
del _opcodes_all
-def dis(x=None):
- """Disassemble classes, methods, functions, or code.
+class Bytecode:
+ def __init__(self, disresult, bytecodeindex, oparg, lineno):
+ self.disresult = disresult
+ self.index = bytecodeindex
+ self.op = ord(disresult.code.co_code[self.index])
+ self.name = opname[self.op]
+ self.oparg = oparg
+ self.lineno = lineno
+
+ def reprargstring(self):
+ """ return a string representation of any arguments. (empty for no args)"""
+ oparg = self.oparg
+ if oparg is None:
+ return ''
+ co = self.disresult.code
+ op = self.op
+
+ s = repr(oparg).rjust(5) + " "
+ if op in hasconst:
+ s += '(' + `co.co_consts[oparg]` + ')'
+ elif op in hasname:
+ s += '(' + co.co_names[oparg] + ')'
+ elif op in hasjrel:
+ s += '(to ' + repr(self.index + oparg) + ')'
+ elif op in haslocal:
+ s += '(' + co.co_varnames[oparg] + ')'
+ elif op in hascompare:
+ s += '(' + cmp_op[oparg] + ')'
+ elif op in hasfree:
+ if free is None:
+ free = co.co_cellvars + co.co_freevars
+ s += '(' + free[oparg] + ')'
+ return s
+
+class DisResult:
+ """ an instance of this class gets returned for disassembling
+ objects/functions/code objects whatever.
+ """
+ def __init__(self, code):
+ self.code = code
+ self._bytecodes = []
+
+ def append(self, bytecodeindex, oparg, lineno):
+ """ append bytecode anaylsis information ..."""
+ bc = Bytecode(self, bytecodeindex, oparg, lineno)
+ self._bytecodes.append(bc)
+
+ def format(self):
+ lastlineno = -1
+ labels = findlabels(self.code.co_code)
+ lines = []
+ for bc in self._bytecodes:
+ l = []
+ if bc.lineno != lastlineno:
+ lastlineno = bc.lineno
+ l.append("%3d" % bc.lineno)
+ else:
+ l.append(" ")
+ l.append(bc.index in labels and ">>" or " ")
+ l.append(repr(bc.index).rjust(4))
+ l.append(bc.name.ljust(20))
+ l.append(bc.reprargstring())
+ lines.append(" ".join(l))
+ return "\n".join(lines)
+
+ __repr__ = format
+
+def pydis(x=None):
+ """pydisassemble classes, methods, functions, or code.
- With no argument, disassemble the last traceback.
+ With no argument, pydisassemble the last traceback.
"""
if x is None:
@@ -39,26 +112,28 @@
print "Sorry:", msg
print
elif hasattr(x, 'co_code'):
- disassemble(x)
- elif isinstance(x, str):
- disassemble_string(x)
+ return pydisassemble(x)
+ #elif isinstance(x, str):
+ # return pydisassemble_string(x)
else:
raise TypeError, \
- "don't know how to disassemble %s objects" % \
+ "don't know how to pydisassemble %s objects" % \
type(x).__name__
def distb(tb=None):
- """Disassemble a traceback (default: last traceback)."""
+ """pydisassemble a traceback (default: last traceback)."""
if tb is None:
try:
tb = sys.last_traceback
except AttributeError:
- raise RuntimeError, "no last traceback to disassemble"
+ raise RuntimeError, "no last traceback to pydisassemble"
while tb.tb_next: tb = tb.tb_next
- disassemble(tb.tb_frame.f_code, tb.tb_lasti)
+ pydisassemble(tb.tb_frame.f_code, tb.tb_lasti)
-def disassemble(co, lasti=-1):
- """Disassemble a code object."""
+def pydisassemble(co):
+ """return result of dissassembling a code object. """
+
+ disresult = DisResult(co)
code = co.co_code
byte_increments = [ord(c) for c in co.co_lnotab[0::2]]
@@ -74,7 +149,6 @@
addr = 0
line_incr = 0
- labels = findlabels(code)
n = len(code)
i = 0
extended_arg = 0
@@ -93,85 +167,18 @@
break
else:
addr = sys.maxint
- if i > 0:
- print
- print "%3d"%lineno,
- else:
- print ' ',
-
- if i == lasti: print '-->',
- else: print ' ',
- if i in labels: print '>>',
- else: print ' ',
- print `i`.rjust(4),
- print opname[op].ljust(20),
+ current_bytecodeindex = i
i = i+1
+ oparg = None
if op >= HAVE_ARGUMENT:
oparg = ord(code[i]) + ord(code[i+1])*256 + extended_arg
extended_arg = 0
i = i+2
if op == EXTENDED_ARG:
extended_arg = oparg*65536L
- print `oparg`.rjust(5),
- if op in hasconst:
- print '(' + `co.co_consts[oparg]` + ')',
- elif op in hasname:
- print '(' + co.co_names[oparg] + ')',
- elif op in hasjrel:
- print '(to ' + `i + oparg` + ')',
- elif op in haslocal:
- print '(' + co.co_varnames[oparg] + ')',
- elif op in hascompare:
- print '(' + cmp_op[oparg] + ')',
- elif op in hasfree:
- if free is None:
- free = co.co_cellvars + co.co_freevars
- print '(' + free[oparg] + ')',
- print
-
-def disassemble_string(code, lasti=-1, varnames=None, names=None,
- constants=None):
- labels = findlabels(code)
- n = len(code)
- i = 0
- while i < n:
- c = code[i]
- op = ord(c)
- if op == opmap['SET_LINENO'] and i > 0:
- print # Extra blank line
- if i == lasti: print '-->',
- else: print ' ',
- if i in labels: print '>>',
- else: print ' ',
- print `i`.rjust(4),
- print opname[op].ljust(15),
- i = i+1
- if op >= HAVE_ARGUMENT:
- oparg = ord(code[i]) + ord(code[i+1])*256
- i = i+2
- print `oparg`.rjust(5),
- if op in hasconst:
- if constants:
- print '(' + `constants[oparg]` + ')',
- else:
- print '(%d)'%oparg,
- elif op in hasname:
- if names is not None:
- print '(' + names[oparg] + ')',
- else:
- print '(%d)'%oparg,
- elif op in hasjrel:
- print '(to ' + `i + oparg` + ')',
- elif op in haslocal:
- if varnames:
- print '(' + varnames[oparg] + ')',
- else:
- print '(%d)' % oparg,
- elif op in hascompare:
- print '(' + cmp_op[oparg] + ')',
- print
-
-disco = disassemble # XXX For backwards compatibility
+
+ disresult.append(current_bytecodeindex, oparg, lineno)
+ return disresult
def findlabels(code):
"""Detect all offsets in a byte code which are jump targets.
@@ -198,30 +205,3 @@
if label not in labels:
labels.append(label)
return labels
-
-
-def _test():
- """Simple test program to disassemble a file."""
- if sys.argv[1:]:
- if sys.argv[2:]:
- sys.stderr.write("usage: python dis.py [-|file]\n")
- sys.exit(2)
- fn = sys.argv[1]
- if not fn or fn == "-":
- fn = None
- else:
- fn = None
- if fn is None:
- f = sys.stdin
- else:
- f = open(fn)
- source = f.read()
- if fn is not None:
- f.close()
- else:
- fn = "<stdin>"
- code = compile(source, fn, "exec")
- dis(code)
-
-if __name__ == "__main__":
- _test()
More information about the Pypy-commit
mailing list