Commits

Maciej Fijalkowski  committed 58d7fbf

Random progress

  • Participants
  • Parent commits da030b8

Comments (0)

Files changed (5)

File baseviewer.py

 from pypy.tool.logparser import parse_log_file, extract_category
 from pypy.jit.metainterp.test.oparser import parse
 from pypy.jit.metainterp.resoperation import rop
+from module_finder import load_code
 
 from pygments import highlight
 from pygments.lexers import PythonLexer
 
     def loop(self):
         no = int(flask.request.args.get('no', '0'))
+        # gather all functions
         loop = self.loops[no]
         startline = loop.lineno - 1
+        import pdb
+        pdb.set_trace()
         code = highlight(open(loop.filename).read(),
-                         PythonLexer(), HtmlFormatter(linenos='table',
-                                                      lineanchors='line'))
+                         PythonLexer(), HtmlFormatter(lineanchors='line'))
+        #mod = import_module
         return flask.render_template('loop.html', code=code,
                                      startline=startline)
 

File disassembler.py

+"""Disassembler of Python byte code into mnemonics.
+
+Comes from standard library, modified for the purpose of having a structured
+view on things
+"""
+
+import sys
+import types
+
+from opcode import *
+from opcode import __all__ as _opcodes_all
+
+__all__ = ["dis","disassemble","distb","disco"] + _opcodes_all
+del _opcodes_all
+
+class Opcode(object):
+    """ An abstract base class for all opcode implementations
+    """
+    def __init__(self, pos, lineno, arg=None):
+        self.pos = pos
+        self.arg = arg
+        self.lineno = lineno
+
+    def __repr__(self):
+        if self.arg is None:
+            return "<%s at %d>" (self.__class__.__name__, self.pos)
+        return "<%s (%s) at %d>" % (self.__class__.__name__, self.arg, self.pos)
+
+class CodeRepresentation(object):
+    """ Representation of opcodes
+    """
+    def __init__(self, opcodes):
+        self.opcodes = opcodes
+        self.map = {}
+        for opcode in opcodes:
+            self.map[opcode.pos] = opcode
+
+def _setup():
+    for opcode in opname:
+        if not opcode.startswith('<'):
+            class O(Opcode):
+                pass
+            opcode = opcode.replace('+', '_')
+            O.__name__ = opcode
+            globals()[opcode] = O
+
+_setup()
+
+def dis(x=None):
+    """Disassemble classes, methods, functions, or code.
+
+    With no argument, disassemble the last traceback.
+
+    """
+    if x is None:
+        distb()
+        return
+    if type(x) is types.InstanceType:
+        x = x.__class__
+    if hasattr(x, 'im_func'):
+        x = x.im_func
+    if hasattr(x, 'func_code'):
+        x = x.func_code
+    if hasattr(x, '__dict__'):
+        xxx
+        items = x.__dict__.items()
+        items.sort()
+        for name, x1 in items:
+            if type(x1) in (types.MethodType,
+                            types.FunctionType,
+                            types.CodeType,
+                            types.ClassType):
+                print "Disassembly of %s:" % name
+                try:
+                    dis(x1)
+                except TypeError, msg:
+                    print "Sorry:", msg
+                print
+    elif hasattr(x, 'co_code'):
+        return disassemble(x)
+    elif isinstance(x, str):
+        return disassemble_string(x)
+    else:
+        raise TypeError, \
+              "don't know how to disassemble %s objects" % \
+              type(x).__name__
+
+def distb(tb=None):
+    """Disassemble a traceback (default: last traceback)."""
+    if tb is None:
+        try:
+            tb = sys.last_traceback
+        except AttributeError:
+            raise RuntimeError, "no last traceback to disassemble"
+        while tb.tb_next: tb = tb.tb_next
+    disassemble(tb.tb_frame.f_code, tb.tb_lasti)
+
+def disassemble(co, lasti=-1):
+    """Disassemble a code object."""
+    code = co.co_code
+    labels = findlabels(code)
+    linestarts = dict(findlinestarts(co))
+    n = len(code)
+    i = 0
+    extended_arg = 0
+    free = None
+    res = []
+    lastline = co.co_firstlineno
+    while i < n:
+        c = code[i]
+        op = ord(c)
+        if i in linestarts:
+            lastline = linestarts[i]
+
+        #if i == lasti:
+        #    xxx
+        #    print '-->',
+        #else:
+        #    xxx
+        #    print '   ',
+        #if i in labels:
+        #    xxx
+        #    print '>>',
+        #else:
+        #    xxx
+        #    print '  ',
+        #xxx
+        pos = i
+        i = i + 1
+        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
+            # if op in hasconst:
+            #     xxx
+            #     print '(' + repr(co.co_consts[oparg]) + ')',
+            # elif op in hasname:
+            #     xxxx
+            #     print '(' + co.co_names[oparg] + ')',
+            # elif op in hasjrel:
+            #     xxx
+            #     print '(to ' + repr(i + oparg) + ')',
+            # elif op in haslocal:
+            #     xxx
+            #     print '(' + co.co_varnames[oparg] + ')',
+            # elif op in hascompare:
+            #     xxx
+            #     print '(' + cmp_op[oparg] + ')',
+            # elif op in hasfree:
+            #     if free is None:
+            #         free = co.co_cellvars + co.co_freevars
+            #     xxx
+            #     print '(' + free[oparg] + ')',
+        else:
+            oparg = None
+        res.append(globals()[opname[op]](pos, lastline, oparg))
+    return CodeRepresentation(res)
+
+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 i == lasti:
+            xxx
+            print '-->',
+        else:
+            xxx
+            print '   ',
+        if i in labels:
+            xxx
+            print '>>',
+        else:
+            xxx
+            print '  ',
+        xxxx
+        print repr(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
+            xxx
+            print repr(oparg).rjust(5),
+            if op in hasconst:
+                if constants:
+                    xxx
+                    print '(' + repr(constants[oparg]) + ')',
+                else:
+                    xxx
+                    print '(%d)'%oparg,
+            elif op in hasname:
+                if names is not None:
+                    xxx
+                    print '(' + names[oparg] + ')',
+                else:
+                    xxx
+                    print '(%d)'%oparg,
+            elif op in hasjrel:
+                xxx
+                print '(to ' + repr(i + oparg) + ')',
+            elif op in haslocal:
+                if varnames:
+                    xxx
+                    print '(' + varnames[oparg] + ')',
+                else:
+                    xxx
+                    print '(%d)' % oparg,
+            elif op in hascompare:
+                xxx
+                print '(' + cmp_op[oparg] + ')',
+        xxx
+        print
+
+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 = []
+    n = len(code)
+    i = 0
+    while i < n:
+        c = code[i]
+        op = ord(c)
+        i = i+1
+        if op >= HAVE_ARGUMENT:
+            oparg = ord(code[i]) + ord(code[i+1])*256
+            i = i+2
+            label = -1
+            if op in hasjrel:
+                label = i+oparg
+            elif op in hasjabs:
+                label = oparg
+            if label >= 0:
+                if label not in labels:
+                    labels.append(label)
+    return labels
+
+def findlinestarts(code):
+    """Find the offsets in a byte code which are start of lines in the source.
+
+    Generate pairs (offset, lineno) as described in Python/compile.c.
+
+    """
+    byte_increments = [ord(c) for c in code.co_lnotab[0::2]]
+    line_increments = [ord(c) for c in code.co_lnotab[1::2]]
+
+    lastlineno = None
+    lineno = code.co_firstlineno
+    addr = 0
+    for byte_incr, line_incr in zip(byte_increments, line_increments):
+        if byte_incr:
+            if lineno != lastlineno:
+                yield (addr, lineno)
+                lastlineno = lineno
+            addr += byte_incr
+        lineno += line_incr
+    if lineno != lastlineno:
+        yield (addr, lineno)
+
+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)

File module_finder.py

 
-import os, sys
+import os, sys, marshal, types, ast
 
-class NotFound(Exception):
-    """ An exception raised when module was not found in sys.path
+def _all_codes_from(code):
+    res = {}
+    more = [code]
+    while more:
+        next = more.pop()
+        res[next.co_firstlineno] = next
+        more += [co for co in next.co_consts
+                 if isinstance(co, types.CodeType)]
+    return res
+
+
+def gather_all_code_objs(fname):
+    """ Gathers all code objects from a give fname and sorts them by
+    starting lineno
     """
+    fname = str(fname)
+    if fname.endswith('.pyc'):
+        code = marshal.loads(open(fname).read()[8:])
+        assert isinstance(code, types.CodeType)
+    elif fname.endswith('.py'):
+        code = compile(ast.parse(open(fname).read()), fname, 'exec')
+    else:
+        raise Exception("Unknown file extension: %s" % fname)
+    return _all_codes_from(code)
 
-def find_module(name, sys_path=sys.path):
-    """ Searches sys.path for possible parent paths for name (which is
-    a filesystem name). Returns a pair (entry in sys.path, name of module)
-    where name of module is a reasonable name to be passed as argument for
-    __import__
+def load_code(fname, name, lineno):
+    """ Loads a module code from a given description. If fname is a pyc file,
+    just unmarshal it and find correct code, otherwise use ast module to
+    get code. Insane hack, but works
     """
-    sys_path_dict = {}
-    for path in sys_path:
-        sys_path_dict[path] = None
-    bases = name.split(os.path.sep)
-    for i in range(len(bases) - 1, -1, -1):
-        prefix = os.path.sep.join(bases[:i])
-        if prefix in sys_path_dict:
-            modname = ".".join(bases[i:])
-            if modname.endswith('.pyc'):
-                modname = modname[:-4]
-            else:
-                assert modname.endswith(".py")
-                modname = modname[:-3]
-            return prefix, modname
-    raise NotFound
-
-def import_module(name):
-    """ Finds a module based on it's name. Looks for all paths above if they're
-    on sys.path. if so, loads the parent sys.path and then module. Might
-    not be 100% proof, but should work in most cases
-    """
-    sys_path_entry, modname = find_module(name)
+    return gather_all_code_objs(fname)[lineno]

File test/test_disassembler.py

+
+import disassembler, sys
+import py
+
+def f(a, b):
+    return a + b
+
+def test_disassembler():
+    res = disassembler.dis(f)
+    if sys.version_info[:2] != (2, 6):
+        py.test.skip("2.6 only test")
+    assert len(res.opcodes) == 4
+    assert [x.__class__.__name__ for x in res.opcodes] == [
+        'LOAD_FAST', 'LOAD_FAST', 'BINARY_ADD', 'RETURN_VALUE']
+    for i in range(4):
+        assert res.opcodes[i].lineno == f.func_code.co_firstlineno + 1

File test/test_module.py

 
-from module_finder import find_module
+import py
+from module_finder import load_code, gather_all_code_objs
+import re
 
-def test_find_module():
-    sys_path = ["/usr/lib/python2.6", '/home/stuff']
-    path, modname = find_module('/usr/lib/python2.6/re.py', sys_path)
-    assert path == sys_path[0]
-    assert modname == 're'
-    path, modname = find_module('/usr/lib/python2.6/stuff/re.py', sys_path)
-    assert path == sys_path[0]
-    assert modname == 'stuff.re'
-    path, modname = find_module('/usr/lib/python2.6/stuff/re.pyc', sys_path)
-    assert path == sys_path[0]
-    assert modname == 'stuff.re'
+def test_gather_code():
+    fname = py.path.local(__file__).join('..', 're.pyc')
+    codes = gather_all_code_objs(fname)
+    assert len(codes) == 21
+    assert sorted(codes.keys()) == [102, 134, 139, 144, 153, 164, 169, 181, 188, 192, 197, 206, 229, 251, 266, 271, 277, 285, 293, 294, 308]
+
+def test_gather_code_py():
+    fname = re.__file__
+    if fname.endswith('.pyc'):
+        fname = fname[:-1]
+    codes = gather_all_code_objs(fname)
+    assert len(codes) == 21
+    assert sorted(codes.keys()) == [102, 134, 139, 144, 153, 164, 169, 181, 188, 192, 197, 206, 229, 251, 266, 271, 277, 285, 293, 294, 308]
+
+def test_load_code():
+    fname = py.path.local(__file__).join('..', 're.pyc')
+    code = load_code(fname, 'name', 144)
+    assert code.co_name == 'sub'
+    assert code.co_filename == '/usr/lib/python2.6/re.py'
+    assert code.co_firstlineno == 144