Author: Richard Plangger <[email protected]>
Branch: s390x-backend
Changeset: r81687:2504ba34aacd
Date: 2016-01-12 18:56 +0100
http://bitbucket.org/pypy/pypy/changeset/2504ba34aacd/
Log: fixed another 3 tests (translated call release gil)
diff --git a/rpython/jit/backend/llsupport/test/zrpy_gc_test.py
b/rpython/jit/backend/llsupport/test/zrpy_gc_test.py
--- a/rpython/jit/backend/llsupport/test/zrpy_gc_test.py
+++ b/rpython/jit/backend/llsupport/test/zrpy_gc_test.py
@@ -84,6 +84,7 @@
#
t = TranslationContext()
t.config.translation.gc = gc
+ t.config.translation.lldebug = True # XXX debug
if gc != 'boehm':
t.config.translation.gcremovetypeptr = True
for name, value in kwds.items():
diff --git a/rpython/jit/backend/zarch/assembler.py
b/rpython/jit/backend/zarch/assembler.py
--- a/rpython/jit/backend/zarch/assembler.py
+++ b/rpython/jit/backend/zarch/assembler.py
@@ -556,14 +556,21 @@
mc = self.mc
mc.load_imm(r.SCRATCH, endaddr) # li r0, endaddr
- mc.load(r.SCRATCH2, r.SCRATCH, 0) # lg r1, [end]
- mc.load(r.SCRATCH, r.SCRATCH, diff)# lg r0, [length]
- mc.SGR(r.SCRATCH2, r.SP) # sub r1, SP
+ mc.load(r.r14, r.SCRATCH, 0) # lg r14, [end]
+ mc.load(r.SCRATCH, r.SCRATCH, diff) # lg r0, [length]
+ mc.LGR(r.SCRATCH2, r.SP)
+ mc.SGR(r.SCRATCH2, r.r14) # sub r1, (SP - r14)
+ jmp_pos = self.mc.currpos()
+ self.mc.reserve_cond_jump()
+
mc.load_imm(r.r14, self.stack_check_slowpath)
- off = l.imm(mc.CLGRJ_byte_count + mc.BASR_byte_count)
- mc.CLGRJ(r.SCRATCH2, r.SCRATCH, c.GT, off)
mc.BASR(r.r14, r.r14)
+ currpos = self.mc.currpos()
+ pmc = OverwritingBuilder(mc, jmp_pos, 1)
+ pmc.CLGRJ(r.SCRATCH2, r.SCRATCH, c.GT, l.imm(currpos - jmp_pos))
+ pmc.overwrite()
+
def _check_frame_depth(self, mc, gcmap):
""" check if the frame is of enough depth to follow this bridge.
Otherwise reallocate the frame in a helper.
diff --git a/rpython/jit/backend/zarch/callbuilder.py
b/rpython/jit/backend/zarch/callbuilder.py
--- a/rpython/jit/backend/zarch/callbuilder.py
+++ b/rpython/jit/backend/zarch/callbuilder.py
@@ -127,7 +127,7 @@
# in this mode, RSHADOWOLD happens to contain the shadowstack
# top at this point, so reuse it instead of loading it again
# RSHADOWOLD is moved to the scratch reg just before restoring
r8
- ssreg = r.SCRATCH
+ ssreg = None # r.SCRATCH
self.asm._reload_frame_if_necessary(self.mc, shadowstack_reg=ssreg)
def emit_raw_call(self):
@@ -135,15 +135,12 @@
# save the SP back chain
self.mc.STG(r.SP, l.addr(-self.subtracted_to_sp, r.SP))
# move the frame pointer
- self.mc.AGHI(r.SP, l.imm(-self.subtracted_to_sp))
+ self.mc.LAY(r.SP, l.addr(-self.subtracted_to_sp, r.SP))
self.mc.raw_call()
- # restore the pool!
- offset = self.asm.pool.pool_start - self.mc.get_relative_pos()
- self.mc.LARL(r.POOL, l.halfword(offset))
def restore_stack_pointer(self):
if self.subtracted_to_sp != 0:
- self.mc.AGHI(r.SP, l.imm(self.subtracted_to_sp))
+ self.mc.LAY(r.SP, l.addr(self.subtracted_to_sp, r.SP))
def load_result(self):
assert (self.resloc is None or
@@ -246,7 +243,7 @@
pmc.BRCL(c.EQ, l.imm(self.mc.currpos() - b1_location))
pmc.overwrite()
- # restore the values that might have been overwritten
+ # restore the values that is void after LMG
if gcrootmap:
if gcrootmap.is_shadow_stack and self.is_call_release_gil:
self.mc.LGR(r.SCRATCH, RSHADOWOLD)
diff --git a/rpython/jit/backend/zarch/test/test_assembler.py
b/rpython/jit/backend/zarch/test/test_assembler.py
--- a/rpython/jit/backend/zarch/test/test_assembler.py
+++ b/rpython/jit/backend/zarch/test/test_assembler.py
@@ -393,6 +393,13 @@
r = reg
+ # 2-6
+ self.pushpop_jitframe([r.r2, r.r3, r.r4, r.r5, r.r6, r.r8, r.r10])
+ assert stored == [(r.r2, r.r6), (r.r8,), (r.r10,)]
+ assert stored == loaded
+ stored = []
+ loaded = []
+
# two sequences 10-11, 13-14
self.pushpop_jitframe([r.r10, r.r11, r.r13, r.r14])
assert stored == [(r.r10, r.r11), (r.r13, r.r14)]
diff --git a/rpython/jit/backend/zarch/tool/__init__.py
b/rpython/jit/backend/zarch/tool/__init__.py
new file mode 100644
diff --git a/rpython/jit/backend/zarch/tool/viewcode.py
b/rpython/jit/backend/zarch/tool/viewcode.py
new file mode 100755
--- /dev/null
+++ b/rpython/jit/backend/zarch/tool/viewcode.py
@@ -0,0 +1,427 @@
+#! /usr/bin/env python
+"""
+Viewer for the output of compiled programs generating code.
+Use on the log files created with 'PYPYLOG=jit-backend-dump:log'.
+
+Try:
+ ./viewcode.py --text log # text only disassembly
+ ./viewcode.py log # also includes a pygame viewer
+"""
+
+import sys
+print(sys.path)
+import new
+import operator
+import py
+import re
+import subprocess
+from bisect import bisect_left
+
+# don't use pypy.tool.udir here to avoid removing old usessions which
+# might still contain interesting executables
+udir = py.path.local.make_numbered_dir(prefix='viewcode-', keep=2)
+tmpfile = str(udir.join('dump.tmp'))
+
+# hack hack
+import rpython.tool
+mod = new.module('rpython.tool.udir')
+mod.udir = udir
+sys.modules['rpython.tool.udir'] = mod
+rpython.tool.udir = mod
+
+# ____________________________________________________________
+# Some support code from Psyco. There is more over there,
+# I am porting it in a lazy fashion... See py-utils/xam.py
+
+def machine_code_dump(data, originaddr, backend_name, label_list=None):
+ objdump = ('objdump -EB --target=binary --architecture=s390:64-bit '
+ '--adjust-vma=%(origin)d -D %(file)s')
+ #
+ f = open(tmpfile, 'wb')
+ f.write(data)
+ f.close()
+ p = subprocess.Popen(objdump % {
+ 'file': tmpfile,
+ 'origin': originaddr,
+ }, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = p.communicate()
+ assert not p.returncode, ('Encountered an error running objdump: %s' %
+ stderr)
+ # drop some objdump cruft
+ lines = stdout.splitlines(True)[6:] # drop some objdump cruft
+ return format_code_dump_with_labels(originaddr, lines, label_list)
+
+def format_code_dump_with_labels(originaddr, lines, label_list):
+ from rpython.rlib.rarithmetic import r_uint
+ if not label_list:
+ label_list = []
+ originaddr = r_uint(originaddr)
+ itlines = iter(lines)
+ yield itlines.next() # don't process the first line
+ for lbl_start, lbl_name in label_list:
+ for line in itlines:
+ addr, _ = line.split(':', 1)
+ addr = int(addr, 16)
+ if addr >= originaddr+lbl_start:
+ yield '\n'
+ if lbl_name is None:
+ yield '--end of the loop--\n'
+ else:
+ yield str(lbl_name) + '\n'
+ yield line
+ break
+ yield line
+ # yield all the remaining lines
+ for line in itlines:
+ yield line
+
+def load_symbols(filename):
+ # the program that lists symbols, and the output it gives
+ symbollister = 'nm %s'
+ re_symbolentry = re.compile(r'([0-9a-fA-F]+)\s\w\s(.*)')
+ #
+ print 'loading symbols from %s...' % (filename,)
+ symbols = {}
+ p = subprocess.Popen(symbollister % filename, shell=True,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = p.communicate()
+ assert not p.returncode, ('Encountered an error running nm: %s' %
+ stderr)
+ for line in stdout.splitlines(True):
+ match = re_symbolentry.match(line)
+ if match:
+ addr = long(match.group(1), 16)
+ name = match.group(2)
+ if name.startswith('pypy_g_'):
+ name = '\xb7' + name[7:]
+ symbols[addr] = name
+ print '%d symbols found' % (len(symbols),)
+ return symbols
+
+re_addr =
re.compile(r'[\s,$]0x([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]+)')
+re_lineaddr = re.compile(r'\s*0?x?([0-9a-fA-F]+)')
+
+def lineaddresses(line):
+ result = []
+ i = 0
+ while 1:
+ match = re_addr.search(line, i)
+ if not match:
+ break
+ i = match.end()
+ addr = long(match.group(1), 16)
+ result.append(addr)
+ return result
+
+# ____________________________________________________________
+
+class CodeRange(object):
+ fallthrough = False
+
+ def __init__(self, world, addr, data):
+ self.world = world
+ self.addr = addr
+ self.data = data
+
+ def __repr__(self):
+ return '<CodeRange %s length %d>' % (hex(self.addr), len(self.data))
+
+ def touches(self, other):
+ return (self .addr < other.addr + len(other.data) and
+ other.addr < self .addr + len(self.data))
+
+ def update_from_old(self, other):
+ if other.addr < self.addr:
+ delta = self.addr - other.addr
+ assert delta <= len(other.data)
+ self.addr -= delta
+ self.data = other.data[:delta] + self.data
+ self_end = self .addr + len(self .data)
+ other_end = other.addr + len(other.data)
+ if other_end > self_end:
+ extra = other_end - self_end
+ assert extra <= len(other.data)
+ self.data += other.data[-extra:]
+
+ def cmpop(op):
+ def _cmp(self, other):
+ if not isinstance(other, CodeRange):
+ return NotImplemented
+ return op((self.addr, self.data), (other.addr, other.data))
+ return _cmp
+ __lt__ = cmpop(operator.lt)
+ __le__ = cmpop(operator.le)
+ __eq__ = cmpop(operator.eq)
+ __ne__ = cmpop(operator.ne)
+ __gt__ = cmpop(operator.gt)
+ __ge__ = cmpop(operator.ge)
+ del cmpop
+
+ def disassemble(self):
+ if not hasattr(self, 'text'):
+ lines = machine_code_dump(self.data, self.addr,
self.world.backend_name)
+ lines = list(lines)
+ # instead of adding symbol names in the dumps we could
+ # also make the 0xNNNNNNNN addresses be red and show the
+ # symbol name when the mouse is over them
+ logentries = self.world.logentries
+ symbols = self.world.symbols
+ for i, line in enumerate(lines):
+ match = re_lineaddr.match(line)
+ if match:
+ addr = long(match.group(1), 16)
+ logentry = logentries.get(addr)
+ if logentry:
+ lines[i] = '\n%s\n%s' % (logentry, lines[i])
+ for addr in lineaddresses(line):
+ sym = symbols.get(addr)
+ if sym:
+ lines[i] = '%s\t%s\n' % (lines[i].rstrip(), sym)
+ self.text = ''.join(lines)
+ return self.text
+
+ def findjumps(self):
+ text = self.disassemble()
+ lines = text.splitlines()
+ line = ''
+ for i, line in enumerate(lines):
+ if '\tj' not in line: # poor heuristic to recognize lines that
+ continue # could be jump instructions
+ addrs = list(lineaddresses(line))
+ if not addrs:
+ continue
+ addr = addrs[-1]
+ final = '\tjmp' in line
+ yield i, addr, final
+ if self.fallthrough and '\tret' not in line:
+ yield len(lines), self.addr + len(self.data), True
+
+
+class World(object):
+
+ def __init__(self):
+ self.ranges = []
+ self.labeltargets = {}
+ self.jumps = {}
+ self.symbols = {}
+ self.logentries = {}
+ self.backend_name = None
+ self.executable_name = None
+
+ def parse(self, f, textonly=True):
+ for line in f:
+ if line.startswith('BACKEND '):
+ self.backend_name = line.split(' ')[1].strip()
+ elif line.startswith('CODE_DUMP '):
+ pieces = line.split()
+ assert pieces[1].startswith('@')
+ assert pieces[2].startswith('+')
+ if len(pieces) == 3:
+ continue # empty line
+ baseaddr = long(pieces[1][1:], 16) & 0xFFFFFFFFL
+ offset = int(pieces[2][1:])
+ addr = baseaddr + offset
+ data = pieces[3].replace(':', '').decode('hex')
+ coderange = CodeRange(self, addr, data)
+ i = bisect_left(self.ranges, coderange)
+ j = i
+ while i>0 and coderange.touches(self.ranges[i-1]):
+ coderange.update_from_old(self.ranges[i-1])
+ i -= 1
+ while j<len(self.ranges) and coderange.touches(self.ranges[j]):
+ coderange.update_from_old(self.ranges[j])
+ j += 1
+ self.ranges[i:j] = [coderange]
+ elif line.startswith('LOG '):
+ pieces = line.split(None, 3)
+ assert pieces[1].startswith('@')
+ assert pieces[2].startswith('+')
+ baseaddr = long(pieces[1][1:], 16) & 0xFFFFFFFFL
+ offset = int(pieces[2][1:])
+ addr = baseaddr + offset
+ self.logentries[addr] = pieces[3]
+ elif line.startswith('SYS_EXECUTABLE '):
+ filename = line[len('SYS_EXECUTABLE '):].strip()
+ if filename != self.executable_name and filename != '??':
+ self.symbols.update(load_symbols(filename))
+ self.executable_name = filename
+
+ def find_cross_references(self):
+ # find cross-references between blocks
+ fnext = 0.1
+ for i, r in enumerate(self.ranges):
+ for lineno, targetaddr, _ in r.findjumps():
+ self.labeltargets[targetaddr] = True
+ if i % 100 == 99:
+ f = float(i) / len(self.ranges)
+ if f >= fnext:
+ sys.stderr.write("%d%%" % int(f*100.0))
+ fnext += 0.1
+ sys.stderr.write(".")
+ sys.stderr.write("100%")
+ # split blocks at labeltargets
+ t = self.labeltargets
+ #print t
+ for r in self.ranges:
+ #print r.addr, r.addr + len(r.data)
+ for i in range(r.addr + 1, r.addr + len(r.data)):
+ if i in t:
+ #print i
+ ofs = i - r.addr
+ self.ranges.append(CodeRange(self, i, r.data[ofs:]))
+ r.data = r.data[:ofs]
+ r.fallthrough = True
+ try:
+ del r.text
+ except AttributeError:
+ pass
+ break
+ # hack hack hacked
+ sys.stderr.write("\n")
+
+ def show(self, showtext=True, showgraph=True):
+ if showgraph:
+ g1 = Graph('codedump')
+ self.ranges.sort()
+ for r in self.ranges:
+ disassembled = r.disassemble()
+ if showtext:
+ print disassembled
+ if showgraph:
+ text, width = tab2columns(disassembled)
+ text = '0x%x\n\n%s' % (r.addr, text)
+ g1.emit_node('N_%x' % r.addr, shape="box", label=text,
+ width=str(width*0.1125))
+ for lineno, targetaddr, final in r.findjumps():
+ if final:
+ color = "black"
+ else:
+ color = "red"
+ g1.emit_edge('N_%x' % r.addr, 'N_%x' % targetaddr,
+ color=color)
+ sys.stdout.flush()
+ if showgraph:
+ g1.display()
+
+ def showtextonly(self):
+ self.ranges.sort()
+ for r in self.ranges:
+ disassembled = r.disassemble()
+ print disassembled
+ del r.text
+
+
+def tab2columns(text):
+ lines = text.split('\n')
+ columnwidth = []
+ for line in lines:
+ columns = line.split('\t')[:-1]
+ while len(columnwidth) < len(columns):
+ columnwidth.append(0)
+ for i, s in enumerate(columns):
+ width = len(s.strip())
+ if not s.endswith(':'):
+ width += 2
+ columnwidth[i] = max(columnwidth[i], width)
+ columnwidth.append(1)
+ result = []
+ for line in lines:
+ columns = line.split('\t')
+ text = []
+ for width, s in zip(columnwidth, columns):
+ text.append(s.strip().ljust(width))
+ result.append(' '.join(text))
+ lengths = [len(line) for line in result]
+ lengths.append(1)
+ totalwidth = max(lengths)
+ return '\\l'.join(result), totalwidth
+
+# ____________________________________________________________
+# XXX pasted from
+# http://codespeak.net/svn/user/arigo/hack/misc/graphlib.py
+# but needs to be a bit more subtle later
+
+from rpython.translator.tool.make_dot import DotGen
+from dotviewer.graphclient import display_page
+
+class Graph(DotGen):
+
+ def highlight(self, word, text, linked_to=None):
+ if not hasattr(self, '_links'):
+ self._links = {}
+ self._links_to = {}
+ self._links[word] = text
+ if linked_to:
+ self._links_to[word] = linked_to
+
+ def display(self):
+ "Display a graph page locally."
+ display_page(_Page(self))
+
+
+class NoGraph(Exception):
+ pass
+
+class _Page:
+ def __init__(self, graph_builder):
+ if callable(graph_builder):
+ graph = graph_builder()
+ else:
+ graph = graph_builder
+ if graph is None:
+ raise NoGraph
+ self.graph_builder = graph_builder
+
+ def content(self):
+ return _PageContent(self.graph_builder)
+
+class _PageContent:
+ fixedfont = True
+
+ def __init__(self, graph_builder):
+ if callable(graph_builder):
+ graph = graph_builder()
+ else:
+ graph = graph_builder
+ assert graph is not None
+ self.graph_builder = graph_builder
+ self.graph = graph
+ self.links = getattr(graph, '_links', {})
+ if not hasattr(graph, '_source'):
+ graph._source = graph.generate(target=None)
+ self.source = graph._source
+
+ def followlink(self, link):
+ try:
+ return _Page(self.graph._links_to[link])
+ except NoGraph:
+ return _Page(self.graph_builder)
+
+# ____________________________________________________________
+
+if __name__ == '__main__':
+ if '--text' in sys.argv:
+ sys.argv.remove('--text')
+ showgraph = False
+ else:
+ showgraph = True
+ if len(sys.argv) != 2:
+ print >> sys.stderr, __doc__
+ sys.exit(2)
+ #
+ import cStringIO
+ from rpython.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:
+ world.find_cross_references()
+ world.show(showtext=True)
+ else:
+ world.showtextonly()
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit