Author: Armin Rigo <ar...@tunes.org> Branch: py3.5 Changeset: r88338:65a37f0d6b93 Date: 2016-11-13 10:47 +0100 http://bitbucket.org/pypy/pypy/changeset/65a37f0d6b93/
Log: hg merge default diff --git a/pypy/doc/release-pypy2.7-v5.6.0.rst b/pypy/doc/release-pypy2.7-v5.6.0.rst --- a/pypy/doc/release-pypy2.7-v5.6.0.rst +++ b/pypy/doc/release-pypy2.7-v5.6.0.rst @@ -72,7 +72,7 @@ * **s390x** running Linux .. _`PyPy and CPython 2.7.x`: http://speed.pypy.org -.. _`dynamic languages`: http://pypyjs.org +.. _`dynamic languages`: http://rpython.readthedocs.io/en/latest/examples.html Other Highlights (since 5.4 released Aug 31, 2016) ========================================================= diff --git a/rpython/doc/examples.rst b/rpython/doc/examples.rst new file mode 100644 --- /dev/null +++ b/rpython/doc/examples.rst @@ -0,0 +1,42 @@ +Projects Using RPython +====================== + +A very time-dependent list of interpreters written in RPython. Corrections welcome, +this list was last curated in +Nov 2016 + +Actively Developed: + + * PyPy, Python, very complete and maintained, http://pypy.org + * Pydgin, CPU emulation framework, supports ARM well, jitted, active development, https://github.com/cornell-brg/pydgin + * RSqueak VM, Smalltalk, core complete, JIT working, graphics etc getting there, in active development https://github.com/HPI-SWA-Lab/RSqueak + * Pixie, 'A small, fast, native lisp with "magical" powers', jitted, maintained, https://github.com/pixie-lang/pixie + * Monte, 'A dynamic language inspired by Python and E.' has an rpython implementation, in active development, https://github.com/monte-language/typhon + * Typhon, 'A virtual machine for Monte', in active development, https://github.com/monte-language/typhon + * Tulip, an untyped functional language, in language design mode, maintained, https://github.com/tulip-lang/tulip/ + * Pycket, a Racket implementation, proof of concept, small language core working, a lot of primitives are missing. Slow development https://github.com/samth/pycket + * Lever, a dynamic language with a modifiable grammar, actively developed, https://github.com/cheery/lever + +Complete, functioning, but inactive + + * Converge 2, complete, last release version 2.1 in Feb 2015, http://convergepl.org/ + * Pyrolog, Prolog, core complete, extensions missing, last commit in Nov 2015, http://bitbucket.org/cfbolz/pyrolog + * PyPy.js, adds a JavaScript backend to pypy, http://pypyjs.org + +Inactive (last reviewed Sept 2015): + + * Topaz, Ruby, major functionality complete, library missing, inactive http://topazruby.com + * Rapydo, R, execution semantics complete, most builtins missing, inactive, http://bitbucket.org/cfbolz/rapydo + * Hippy, PHP, proof of concept, inactive, http://morepypy.blogspot.de/2012/07/hello-everyone.html + * Scheme, no clue about completeness, inactive, http://bitbucket.org/pypy/lang-scheme/ + * PyGirl, Gameboy emulator, works but there is a bug somewhere, does not use JIT, unmaintained, http://bitbucket.org/pypy/lang-gameboy + * Javascript, proof of concept, inactive, http://bitbucket.org/pypy/lang-js + * An implementation of Notch's DCPU-16, https://github.com/AlekSi/dcpu16py/tree/pypy-again + * Haskell, core of the language works, but not many libraries, inactive http://bitbucket.org/cfbolz/haskell-python + * IO, no clue about completeness, inactive https://bitbucket.org/pypy/lang-io + * Qoppy, an implementation Qoppa, which is a scheme without special forms: https://github.com/timfel/qoppy + * XlispX, a toy Lisp: https://bitbucket.org/rxe/xlispx + * RPySOM, an RPython implementation of SOM (Simple Object Model) https://github.com/SOM-st/RPySOM + * SQPyte, really experimental implementation of the SQLite bytecode VM, jitted, probably inactive, https://bitbucket.org/softdevteam/sqpyte + * Icbink, an implementation of Kernel, core complete, naive, no JIT optimizations yet, on hiatus https://github.com/euccastro/icbink + diff --git a/rpython/doc/index.rst b/rpython/doc/index.rst --- a/rpython/doc/index.rst +++ b/rpython/doc/index.rst @@ -25,7 +25,6 @@ architecture faq - User Documentation ------------------ @@ -48,6 +47,7 @@ rpython rlib rffi + examples RPython internals diff --git a/rpython/tool/disassembler.py b/rpython/tool/disassembler.py --- a/rpython/tool/disassembler.py +++ b/rpython/tool/disassembler.py @@ -50,6 +50,9 @@ current_lineno = opcode.lineno self.source = source.split("\n") + def get_opcode_from_info(self, info): + return self.map[info.bytecode_no] + def _setup(): for opcode in opname: if not opcode.startswith('<'): diff --git a/rpython/tool/jitlogparser/parser.py b/rpython/tool/jitlogparser/parser.py --- a/rpython/tool/jitlogparser/parser.py +++ b/rpython/tool/jitlogparser/parser.py @@ -11,15 +11,28 @@ filename = None bytecode_no = 0 bytecode_name = None - m = re.search('<code object ([<>\w]+)[\.,] file \'(.+?)\'[\.,] line (\d+)> #(\d+) (\w+)', - arg) + mask = 0 + # generic format: the numbers are 'startlineno-currentlineno', + # and this function returns currentlineno as the value + # 'bytecode_no = currentlineno ^ -1': i.e. it abuses bytecode_no, + # which doesn't make sense in the generic format, as a negative + # number + m = re.match(r'(.+?);(.+?):(\d+)-(\d+)~(.*)', arg) + if m is not None: + mask = -1 + else: + # PyPy2 format: bytecode_no is really a bytecode index, + # which must be turned into a real line number by parsing the + # source file + m = re.search(r'<code object ([<>\w]+)[\.,] file \'(.+?)\'[\.,] ' + r'line (\d+)> #(\d+) (\w+)', arg) if m is None: # a non-code loop, like StrLiteralSearch or something if arg: bytecode_name = arg else: name, filename, lineno, bytecode_no, bytecode_name = m.groups() - return name, bytecode_name, filename, int(lineno), int(bytecode_no) + return name, bytecode_name, filename, int(lineno), int(bytecode_no) ^ mask class Op(object): bridge = None @@ -195,8 +208,9 @@ self.startlineno, self.bytecode_no) = parsed self.operations = operations self.storage = storage + generic_format = (self.bytecode_no < 0) self.code = storage.disassemble_code(self.filename, self.startlineno, - self.name) + self.name, generic_format) def repr(self): if self.filename is None: @@ -213,7 +227,7 @@ def getopcode(self): if self.code is None: return None - return self.code.map[self.bytecode_no] + return self.code.get_opcode_from_info(self) def getlineno(self): code = self.getopcode() diff --git a/rpython/tool/jitlogparser/storage.py b/rpython/tool/jitlogparser/storage.py --- a/rpython/tool/jitlogparser/storage.py +++ b/rpython/tool/jitlogparser/storage.py @@ -5,6 +5,7 @@ import py import os +import linecache from rpython.tool.disassembler import dis from rpython.tool.jitlogparser.module_finder import gather_all_code_objs @@ -29,7 +30,10 @@ self.codes[fname] = res return res - def disassemble_code(self, fname, startlineno, name): + def disassemble_code(self, fname, startlineno, name, generic_format=False): + # 'generic_format' is False for PyPy2 (returns a + # disassembler.CodeRepresentation) or True otherwise (returns a + # GenericCode, without attempting any disassembly) try: if py.path.local(fname).check(file=False): return None # cannot find source file @@ -39,6 +43,10 @@ try: return self.disassembled_codes[key] except KeyError: + pass + if generic_format: + res = GenericCode(fname, startlineno, name) + else: codeobjs = self.load_code(fname) if (startlineno, name) not in codeobjs: # cannot find the code obj at this line: this can happen for @@ -50,8 +58,8 @@ return None code = codeobjs[(startlineno, name)] res = dis(code) - self.disassembled_codes[key] = res - return res + self.disassembled_codes[key] = res + return res def reconnect_loops(self, loops): """ Re-connect loops in a way that entry bridges are filtered out @@ -80,3 +88,40 @@ res.append(loop) self.loops = res return res + + +class GenericCode(object): + def __init__(self, fname, startlineno, name): + self._fname = fname + self._startlineno = startlineno + self._name = name + self._first_bytecodes = {} # {lineno: info} + self._source = None + + def __repr__(self): + return 'GenericCode(%r, %r, %r)' % ( + self._fname, self._startlineno, self._name) + + def get_opcode_from_info(self, info): + lineno = ~info.bytecode_no + if self._first_bytecodes.setdefault(lineno, info) is info: + # this is the first opcode of the line---or, at least, + # the first time we ask for an Opcode on that line. + line_starts_here = True + else: + line_starts_here = False + return GenericOpcode(lineno, line_starts_here) + + @property + def source(self): + if self._source is None: + src = linecache.getlines(self._fname) + if self._startlineno > 0: + src = src[self._startlineno - 1:] + self._source = [s.rstrip('\n\r') for s in src] + return self._source + +class GenericOpcode(object): + def __init__(self, lineno, line_starts_here): + self.lineno = lineno + self.line_starts_here = line_starts_here diff --git a/rpython/tool/jitlogparser/test/test_parser.py b/rpython/tool/jitlogparser/test/test_parser.py --- a/rpython/tool/jitlogparser/test/test_parser.py +++ b/rpython/tool/jitlogparser/test/test_parser.py @@ -2,7 +2,8 @@ Function, adjust_bridges, import_log, split_trace, Op, parse_log_counts) -from rpython.tool.jitlogparser.storage import LoopStorage +from rpython.tool.jitlogparser.storage import LoopStorage, GenericCode +from rpython.tool.udir import udir import py, sys from rpython.jit.backend.detect_cpu import autodetect from rpython.jit.backend.tool.viewcode import ObjdumpNotFound @@ -381,4 +382,58 @@ """) f = Function.from_operations(loop.operations, LoopStorage()) assert len(f.chunks) == 2 - + +def test_embedded_lineno(): + # debug_merge_point() can have a text that is either: + # + # * the PyPy2's <code object %s. file '%s'. line %d> #%d %s> + # funcname, filename, lineno, bytecode_no, bytecode_name + # + # * a standard text of the form %s;%s:%d-%d-%d %s + # funcname, filename, startlineno, curlineno, endlineno, anything + # + # * or anything else, which is not specially recognized but shouldn't crash + # + sourcefile = str(udir.join('test_embedded_lineno.src')) + with open(sourcefile, 'w') as f: + print >> f, "A#1" + print >> f, "B#2" + print >> f, "C#3" + print >> f, "D#4" + print >> f, "E#5" + print >> f, "F#6" + loop = parse(""" + [] + debug_merge_point(0, 0, 'myfunc;%(filename)s:2-2~one') + debug_merge_point(0, 0, 'myfunc;%(filename)s:2-2~two') + debug_merge_point(0, 0, 'myfunc;%(filename)s:2-4~') + debug_merge_point(0, 0, 'myfunc;%(filename)s:2-4~four') + """ % {'filename': sourcefile}) + f = Function.from_operations(loop.operations, LoopStorage()) + + expect = [(2, 'one', True), + (2, 'two', False), + (4, '', True), + (4, 'four', False)] + assert len(f.chunks) == len(expect) + + code_seen = set() + for chunk, (expected_lineno, + expected_bytecode_name, + expected_line_starts_here) in zip(f.chunks, expect): + assert chunk.name == 'myfunc' + assert chunk.bytecode_name == expected_bytecode_name + assert chunk.filename == sourcefile + assert chunk.startlineno == 2 + assert chunk.bytecode_no == ~expected_lineno # half-abuse + assert chunk.has_valid_code() + assert chunk.lineno == expected_lineno + assert chunk.line_starts_here == expected_line_starts_here + code_seen.add(chunk.code) + + assert len(code_seen) == 1 + code, = code_seen + assert code.source[0] == "B#2" + assert code.source[1] == "C#3" + assert code.source[4] == "F#6" + py.test.raises(IndexError, "code.source[5]") diff --git a/rpython/translator/c/gcc/trackgcroot.py b/rpython/translator/c/gcc/trackgcroot.py --- a/rpython/translator/c/gcc/trackgcroot.py +++ b/rpython/translator/c/gcc/trackgcroot.py @@ -926,6 +926,13 @@ assert lineoffset in (1,2) return [InsnStackAdjust(-4)] + if target.startswith('__x86.get_pc_thunk.'): + # special case, found on x86-32: these static functions + # contain only a simple load of some non-GC pointer to + # a specific register (not necessarily EAX) + reg = '%e' + target.split('.')[-1] + return [InsnSetLocal(reg)] + insns = [InsnCall(target, self.currentlineno), InsnSetLocal(self.EAX)] # the result is there if self.format in ('mingw32', 'msvc'): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit