Commits

Armin Rigo committed 9775e2a

Reintroduce the possibility to dump machine code: it goes now
to the standard log file. Use PYPYLOG=jit-backend-dump:log.
Load it with jit/backend/x86/tool/viewcode.py, by calling
it with the 'log' filename.

Comments (0)

Files changed (4)

pypy/jit/backend/llsupport/asmmemmgr.py

 from pypy.rlib.rarithmetic import intmask, r_uint, LONG_BIT
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib import rmmap
+from pypy.rlib.debug import debug_start, debug_print, debug_stop
+from pypy.rlib.debug import have_debug_prints
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 
 
             targetindex -= self.SUBBLOCK_SIZE
         assert not block
 
+    def _dump(self, addr, logname, backend=None):
+        debug_start(logname)
+        if have_debug_prints():
+            #
+            if backend is not None:
+                debug_print('BACKEND', backend)
+            #
+            from pypy.jit.backend.hlinfo import highleveljitinfo
+            if highleveljitinfo.sys_executable:
+                debug_print('SYS_EXECUTABLE', highleveljitinfo.sys_executable)
+            #
+            HEX = '0123456789ABCDEF'
+            dump = []
+            src = rffi.cast(rffi.CCHARP, addr)
+            for p in range(self.get_relative_pos()):
+                o = ord(src[p])
+                dump.append(HEX[o >> 4])
+                dump.append(HEX[o & 15])
+            debug_print('CODE_DUMP',
+                        '@%x' % addr,
+                        '+0 ',     # backwards compatibility
+                        ''.join(dump))
+            #
+        debug_stop(logname)
+
     def materialize(self, asmmemmgr, allblocks, gcrootmap=None):
         size = self.get_relative_pos()
         malloced = asmmemmgr.malloc(size, size)

pypy/jit/backend/llsupport/test/test_asmmemmgr.py

 from pypy.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper
 from pypy.jit.backend.llsupport.asmmemmgr import BlockBuilderMixin
 from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib import debug
 
 
 def test_get_index():
 
 def test_blockbuildermixin(translated=True):
     mc = BlockBuilderMixin(translated)
+    writtencode = []
     for i in range(mc.SUBBLOCK_SIZE * 2 + 3):
         assert mc.get_relative_pos() == i
         mc.writechar(chr(i % 255))
+        writtencode.append(chr(i % 255))
     if translated:
         assert mc._cursubindex == 3
         assert mc._cursubblock
     #
     for i in range(0, mc.SUBBLOCK_SIZE * 2 + 3, 2):
         mc.overwrite(i, chr((i + 63) % 255))
+        writtencode[i] = chr((i + 63) % 255)
     #
     p = lltype.malloc(rffi.CCHARP.TO, mc.SUBBLOCK_SIZE * 2 + 3, flavor='raw')
     addr = rffi.cast(lltype.Signed, p)
     mc.copy_to_raw_memory(addr)
     #
     for i in range(mc.SUBBLOCK_SIZE * 2 + 3):
-        if i & 1:
-            assert p[i] == chr(i % 255)
-        else:
-            assert p[i] == chr((i + 63) % 255)
+        assert p[i] == writtencode[i]
+    #
+    debug._log = debug.DebugLog()
+    try:
+        mc._dump(addr, 'test-logname-section')
+        log = list(debug._log)
+    finally:
+        debug._log = None
+    encoded = ''.join(writtencode).encode('hex').upper()
+    ataddr = '@%x' % addr
+    assert log == [('test-logname-section',
+                    [('debug_print', 'CODE_DUMP', ataddr, '+0 ', encoded)])]
+    #
     lltype.free(p, flavor='raw')
 
 def test_blockbuildermixin2():

pypy/jit/backend/x86/codebuf.py

 # like this
 if IS_X86_32:
     codebuilder_cls = X86_32_CodeBuilder
+    backend_name = 'x86'
 elif IS_X86_64:
     codebuilder_cls = X86_64_CodeBuilder
+    backend_name = 'x86_64'
 
 
 class MachineCodeBlockWrapper(BlockBuilderMixin,
             adr = rffi.cast(rffi.LONGP, p - WORD)
             adr[0] = intmask(adr[0] - p)
         valgrind.discard_translations(addr, self.get_relative_pos())
+        self._dump(addr, "jit-backend-dump", backend_name)

pypy/jit/backend/x86/tool/viewcode.py

 #! /usr/bin/env python
 """
-Viewer for the CODE_DUMP output of compiled programs generating code.
+Viewer for the output of compiled programs generating code.
+Use on the log files created with 'PYPYLOG=jit-backend-dump:log'.
 
 Try:
-    ./viewcode.py dumpfile.txt
-or
-    /tmp/usession-xxx/testing_1/testing_1 -var 4  2>&1  |  ./viewcode.py
+    ./viewcode.py --text log        # text only disassembly
+    ./viewcode.py log               # also includes a pygame viewer
 """
 
 import autopath
         self.symbols = {}
         self.logentries = {}
         self.backend_name = None
+        self.executable_name = None
 
     def parse(self, f, textonly=True):
         for line in f:
                 self.logentries[addr] = pieces[3]
             elif line.startswith('SYS_EXECUTABLE '):
                 filename = line[len('SYS_EXECUTABLE '):].strip()
-                self.symbols.update(load_symbols(filename))
+                if filename != self.executable_name:
+                    self.symbols.update(load_symbols(filename))
+                    self.executable_name = filename
 
     def find_cross_references(self):
         # find cross-references between blocks
         showgraph = False
     else:
         showgraph = True
-    if len(sys.argv) == 1:
-        f = sys.stdin
-    else:
-        f = open(sys.argv[1], 'r')
+    if len(sys.argv) != 2:
+        print >> sys.stderr, __doc__
+        sys.exit(2)
+    #
+    import cStringIO
+    from pypy.tool import logparser
+    log1 = logparser.parse_log_file(sys.argv[1])
+    text1 = logparser.extract_category(log1, catprefix='jit-backend-dump')
+    f = cStringIO.StringIO()
+    f.writelines(text1)
+    f.seek(0)
+    del log1, text1
+    #
     world = World()
     world.parse(f)
     if showgraph: