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

Reply via email to