[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