[pypy-svn] r51854 - in pypy/branch/jit-refactoring/pypy/jit/rainbow: . test

arigo at codespeak.net arigo at codespeak.net
Mon Feb 25 17:43:37 CET 2008


Author: arigo
Date: Mon Feb 25 17:43:35 2008
New Revision: 51854

Added:
   pypy/branch/jit-refactoring/pypy/jit/rainbow/dump.py   (contents, props changed)
Modified:
   pypy/branch/jit-refactoring/pypy/jit/rainbow/codewriter.py
   pypy/branch/jit-refactoring/pypy/jit/rainbow/interpreter.py
   pypy/branch/jit-refactoring/pypy/jit/rainbow/test/test_serializegraph.py
Log:
A (hackish) pretty-printer for JitCode objects created by codewriter.py.
This is not really a disassembler, as it is based on the source list.


Modified: pypy/branch/jit-refactoring/pypy/jit/rainbow/codewriter.py
==============================================================================
--- pypy/branch/jit-refactoring/pypy/jit/rainbow/codewriter.py	(original)
+++ pypy/branch/jit-refactoring/pypy/jit/rainbow/codewriter.py	Mon Feb 25 17:43:35 2008
@@ -134,8 +134,10 @@
         self.make_bytecode_block(graph.startblock)
         assert self.current_block is None
         bytecode = self.all_graphs[graph]
+        labelpos = {}
+        code = assemble_labelpos(labelpos, self.interpreter, *self.assembler)
         bytecode.__init__(graph.name,
-                          assemble(self.interpreter, *self.assembler),
+                          code,
                           self.constants,
                           self.typekinds,
                           self.redboxclasses,
@@ -151,6 +153,9 @@
                           self.graph_color,
                           self.calldescs,
                           self.is_portal)
+        bytecode._source = self.assembler
+        bytecode._interpreter = self.interpreter
+        bytecode._labelpos = labelpos
         if is_portal:
             self.finish_all_graphs()
             self.interpreter.set_num_global_mergepoints(
@@ -1033,9 +1038,8 @@
     def __repr__(self):
         return "tlabel(%r)" % (self.name, )
 
-def assemble(interpreter, *args):
+def assemble_labelpos(labelpos, interpreter, *args):
     result = []
-    labelpos = {}
     def emit_2byte(index):
         result.append(chr((index >> 8) & 0xff))
         result.append(chr(index & 0xff))
@@ -1065,3 +1069,6 @@
             result[i + 2] = chr((index >>  8) & 0xff)
             result[i + 3] = chr(index & 0xff)
     return "".join(result)
+
+def assemble(interpreter, *args):
+    return assemble_labelpos({}, interpreter, *args)

Added: pypy/branch/jit-refactoring/pypy/jit/rainbow/dump.py
==============================================================================
--- (empty file)
+++ pypy/branch/jit-refactoring/pypy/jit/rainbow/dump.py	Mon Feb 25 17:43:35 2008
@@ -0,0 +1,166 @@
+from pypy.jit.rainbow import codewriter
+
+
+class SourceIterator:
+
+    def __init__(self, jitcode, source, interpreter, labelpos):
+        self.jitcode = jitcode
+        self.source = source
+        self.interpreter = interpreter
+        self.labelpos = labelpos
+        self.index = 0
+        self.pc = 0
+
+    def finished(self):
+        return self.index == len(self.source)
+
+    def peek(self):
+        return self.source[self.index]
+
+    def get(self, expected_type, bytes_count):
+        arg = self.source[self.index]
+        assert isinstance(arg, expected_type)
+        self.index += 1
+        self.pc += bytes_count
+        return arg
+
+    def get_opname(self):
+        return self.get(str, 2)
+
+    def load_2byte(self):
+        return self.get(int, 2)
+
+    def load_bool(self):
+        return self.get(bool, 1)
+
+    def get_greenarg(self):
+        i = self.load_2byte()
+        if i < 0:
+            return self.jitcode.constants[~i]
+        return CustomRepr('g%d' % i)
+
+    def get_green_varargs(self):
+        greenargs = []
+        num = self.load_2byte()
+        for i in range(num):
+            greenargs.append(self.get_greenarg())
+        return greenargs
+
+    def get_red_varargs(self):
+        redargs = []
+        num = self.load_2byte()
+        for i in range(num):
+            redargs.append(self.get_redarg())
+        return redargs
+
+    def get_redarg(self):
+        return CustomRepr('r%d' % self.get(int, 2))
+
+    def get_greenkey(self):
+        keydescnum = self.load_2byte()
+        if keydescnum == -1:
+            return None
+        else:
+            keydesc = self.jitcode.keydescs[keydescnum]
+            return keydesc
+
+    def load_jumptarget(self):
+        tlbl = self.get(codewriter.tlabel, 4)
+        return self.labelpos[tlbl.name]
+
+
+class CustomRepr:
+    def __init__(self, s):
+        self.s = s
+    def __repr__(self):
+        return self.s
+
+
+def dump_bytecode(jitcode, file=None):
+    # XXX this is not really a disassembler, but just a pretty-printer
+    # for the '_source' attribute that codewriter.py attaches
+    source = jitcode._source
+    interpreter = jitcode._interpreter
+    labelpos = jitcode._labelpos
+    print >> file, 'JITCODE %r' % (jitcode.name,)
+
+    src = SourceIterator(jitcode, source, interpreter, labelpos)
+    noblankline = {0: True}
+    while not src.finished():
+        arg = src.peek()
+        if isinstance(arg, str):
+            startpc = src.pc
+            opname = src.get_opname()
+            opcode = interpreter.find_opcode(opname)
+            opimpl = interpreter.opcode_implementations[opcode]
+            argtypes = opimpl.argspec
+            resulttype = opimpl.resultspec
+            args = []
+
+            for argspec in argtypes:
+                if argspec == "red":
+                    args.append(src.get_redarg())
+                elif argspec == "green":
+                    args.append(src.get_greenarg())
+                elif argspec == "kind":
+                    args.append(jitcode.typekinds[src.load_2byte()])
+                elif argspec == "jumptarget":
+                    args.append(src.load_jumptarget())
+                elif argspec == "bool":
+                    args.append(src.load_bool())
+                elif argspec == "redboxcls":
+                    args.append(jitcode.redboxclasses[src.load_2byte()])
+                elif argspec == "2byte":
+                    args.append(src.load_2byte())
+                elif argspec == "greenkey":
+                    args.append(src.get_greenkey())
+                elif argspec == "promotiondesc":
+                    promotiondescnum = src.load_2byte()
+                    promotiondesc = jitcode.promotiondescs[promotiondescnum]
+                    args.append(promotiondesc)
+                elif argspec == "green_varargs":
+                    args.append(src.get_green_varargs())
+                elif argspec == "red_varargs":
+                    args.append(src.get_red_varargs())
+                elif argspec == "bytecode":
+                    bytecodenum = src.load_2byte()
+                    called_bytecode = jitcode.called_bytecodes[bytecodenum]
+                    args.append(called_bytecode.name)
+                elif argspec == "calldesc":
+                    index = src.load_2byte()
+                    function = jitcode.calldescs[index]
+                    args.append(function)
+                elif argspec == "oopspec":
+                    oopspecindex = src.load_2byte()
+                    oopspec = jitcode.oopspecdescs[oopspecindex]
+                    args.append(oopspec)
+                elif argspec == "structtypedesc":
+                    td = jitcode.structtypedescs[src.load_2byte()]
+                    args.append(td)
+                elif argspec == "arraydesc":
+                    td = jitcode.arrayfielddescs[src.load_2byte()]
+                    args.append(td)
+                elif argspec == "fielddesc":
+                    d = jitcode.fielddescs[src.load_2byte()]
+                    args.append(d)
+                elif argspec == "interiordesc":
+                    d = jitcode.interiordescs[src.load_2byte()]
+                    args.append(d)
+                else:
+                    assert 0, "unknown argtype declaration"
+
+            args = map(str, args)
+            # XXX we should print the result from resultspec too,
+            # but it's not obvious how to do that
+            line = '%5d |  %-20s %s' % (startpc, opname, ', '.join(args))
+            print >> file, line.rstrip()
+        elif isinstance(arg, codewriter.label):
+            if src.pc not in noblankline:    # no duplicate blank lines
+                print >> file, '%5s |' % ''
+                noblankline[src.pc] = True
+            src.index += 1
+        else:
+            assert 0, "unexpected object: %r" % (arg,)
+
+    if src.pc != len(jitcode.code):
+        print >> file, 'WARNING: the pc column is bogus! fix dump.py!'

Modified: pypy/branch/jit-refactoring/pypy/jit/rainbow/interpreter.py
==============================================================================
--- pypy/branch/jit-refactoring/pypy/jit/rainbow/interpreter.py	(original)
+++ pypy/branch/jit-refactoring/pypy/jit/rainbow/interpreter.py	Mon Feb 25 17:43:35 2008
@@ -43,6 +43,10 @@
     def _freeze_(self):
         return True
 
+    def dump(self, file=None):
+        from pypy.jit.rainbow import dump
+        dump.dump_bytecode(self, file=file)
+
 SIGN_EXTEND2 = 1 << 15
 
 class STOP(object):
@@ -141,6 +145,8 @@
                 return
             return val
         wrapped.func_name = "wrap_" + func.func_name
+        wrapped.argspec = argtypes
+        wrapped.resultspec = result
         return wrapped
     return decorator
 
@@ -379,22 +385,26 @@
         return rtimeshift.genptreq(self.jitstate, ptrbox1,
                                    ptrbox2, True)
 
+    @arguments()
     def opimpl_red_return(self):
         rtimeshift.save_return(self.jitstate)
         return self.dispatch()
 
+    @arguments()
     def opimpl_gray_return(self):
         rtimeshift.save_return(self.jitstate)
         return self.dispatch()
 
+    @arguments()
     def opimpl_yellow_return(self):
         # save the greens to make the return value findable by collect_split
         rtimeshift.save_greens(self.jitstate, self.frame.local_green)
         rtimeshift.save_return(self.jitstate)
         return self.dispatch()
 
-    def opimpl_make_new_redvars(self):
-        self.frame.local_boxes = self.get_red_varargs()
+    @arguments("red_varargs")
+    def opimpl_make_new_redvars(self, local_boxes):
+        self.frame.local_boxes = local_boxes
 
     def opimpl_make_new_greenvars(self):
         # an opcode with a variable number of args
@@ -407,6 +417,8 @@
         for i in range(num):
             newgreens.append(self.get_greenarg())
         self.frame.local_green = newgreens
+    opimpl_make_new_greenvars.argspec = ("green_varargs",)  # for dump.py
+    opimpl_make_new_greenvars.resultspec = None
 
     @arguments("2byte", "greenkey")
     def opimpl_local_merge(self, mergepointnum, key):
@@ -425,6 +437,7 @@
         if done:
             return self.dispatch()
 
+    @arguments()
     def opimpl_guard_global_merge(self):
         rtimeshift.guard_global_merge(self.jitstate, self.frame.pc)
         return self.dispatch()
@@ -438,6 +451,7 @@
         assert gv_switchvar.is_const
         self.green_result(gv_switchvar)
 
+    @arguments()
     def opimpl_reverse_split_queue(self):
         rtimeshift.reverse_split_queue(self.frame.dispatchqueue)
 
@@ -448,6 +462,7 @@
         # this frame will be resumed later in the next bytecode, which is
         # red_after_direct_call
 
+    @arguments()
     def opimpl_red_after_direct_call(self):
         newjitstate = rtimeshift.collect_split(
             self.jitstate, self.frame.pc,
@@ -465,6 +480,7 @@
         # this frame will be resumed later in the next bytecode, which is
         # yellow_after_direct_call
 
+    @arguments()
     def opimpl_yellow_after_direct_call(self):
         newjitstate = rtimeshift.collect_split(
             self.jitstate, self.frame.pc,
@@ -640,6 +656,8 @@
                     args += (arg, )
                 result = self.rgenop.genconst(opdesc.llop(*args))
                 self.green_result(result)
+            implementation.argspec = ("green",) * len(list(numargs))
+            implementation.resultspec = "green"
         elif color == "red":
             if opdesc.nb_args == 1:
                 impl = rtimeshift.ll_gen1
@@ -653,6 +671,8 @@
                     args += (self.get_redarg(), )
                 result = impl(*args)
                 self.red_result(result)
+            implementation.argspec = ("red",) * len(list(numargs))
+            implementation.resultspec = "red"
         else:
             assert 0, "unknown color"
         implementation.func_name = "opimpl_%s_%s" % (color, opdesc.opname)

Modified: pypy/branch/jit-refactoring/pypy/jit/rainbow/test/test_serializegraph.py
==============================================================================
--- pypy/branch/jit-refactoring/pypy/jit/rainbow/test/test_serializegraph.py	(original)
+++ pypy/branch/jit-refactoring/pypy/jit/rainbow/test/test_serializegraph.py	Mon Feb 25 17:43:35 2008
@@ -1,3 +1,4 @@
+import py
 from pypy.translator.translator import TranslationContext, graphof
 from pypy.jit.hintannotator.annotator import HintAnnotator
 from pypy.jit.hintannotator.policy import StopAtXPolicy, HintAnnotatorPolicy
@@ -210,6 +211,48 @@
         assert jitcode.is_portal
         assert len(jitcode.called_bytecodes) == 0
 
+    def test_dump_loop(self):
+        def f(x):
+            r = 0
+            while x:
+                r += x
+                x -= 1
+            return r
+        writer, jitcode = self.serialize(f, [int])
+        import StringIO
+        output = StringIO.StringIO()
+        jitcode.dump(file=output)
+        result = output.getvalue().rstrip()
+        print '-' * 40
+        print result
+        print '-' * 40
+        # xxx slightly fragile test, it will break whenever we tweak dump.py
+        expected = """\
+JITCODE 'f'
+    0 |  make_redbox          (0), 0
+    6 |  make_new_redvars     [r0, r1]
+   14 |  make_new_greenvars   []
+      |
+   18 |  local_merge          0, None
+   24 |  red_int_is_true      r0
+   28 |  red_goto_iftrue      r2, 48
+   36 |  make_new_redvars     [r1]
+   42 |  make_new_greenvars   []
+      |
+   46 |  red_return
+      |
+   48 |  make_new_redvars     [r0, r1]
+   56 |  make_new_greenvars   []
+      |
+   60 |  red_int_add          r1, r0
+   66 |  make_redbox          (1), 0
+   72 |  red_int_sub          r0, r3
+   78 |  make_new_redvars     [r4, r2]
+   86 |  make_new_greenvars   []
+   90 |  goto                 18
+        """.rstrip()
+        assert result == expected
+
     def test_call(self):
         def g(x):
             return x + 1



More information about the Pypy-commit mailing list