Author: Richard Plangger <planri...@gmail.com>
Branch: ppc-vsx-support
Changeset: r85872:dd5d6c50f5bd
Date: 2016-07-27 12:43 +0200
http://bitbucket.org/pypy/pypy/changeset/dd5d6c50f5bd/

Log:    merge default (pull in new-jit-log)

diff too long, truncating to 2000 out of 2870 lines

diff --git a/lib-python/2.7/test/test_hash.py b/lib-python/2.7/test/test_hash.py
--- a/lib-python/2.7/test/test_hash.py
+++ b/lib-python/2.7/test/test_hash.py
@@ -174,7 +174,7 @@
 
 class StringlikeHashRandomizationTests(HashRandomizationTests):
     if check_impl_detail(pypy=True):
-        EMPTY_STRING_HASH = -1
+        EMPTY_STRING_HASH = -2
     else:
         EMPTY_STRING_HASH = 0
 
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -36,7 +36,7 @@
     "cStringIO", "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array",
     "binascii", "_multiprocessing", '_warnings', "_collections",
     "_multibytecodec", "micronumpy", "_continuation", "_cffi_backend",
-    "_csv", "cppyy", "_pypyjson",
+    "_csv", "cppyy", "_pypyjson", "_jitlog"
 ])
 
 from rpython.jit.backend import detect_cpu
diff --git a/pypy/doc/build.rst b/pypy/doc/build.rst
--- a/pypy/doc/build.rst
+++ b/pypy/doc/build.rst
@@ -104,27 +104,24 @@
 
     apt-get install gcc make libffi-dev pkg-config libz-dev libbz2-dev \
     libsqlite3-dev libncurses-dev libexpat1-dev libssl-dev libgdbm-dev \
-    tk-dev libgc-dev liblzma-dev
-
-For the optional lzma module on PyPy3 you will also need ``liblzma-dev``.
+    tk-dev libgc-dev \
+    liblzma-dev  # For lzma on PyPy3.
 
 On Fedora::
 
     dnf install gcc make libffi-devel pkgconfig zlib-devel bzip2-devel \
     lib-sqlite3-devel ncurses-devel expat-devel openssl-devel tk-devel \
-    gdbm-devel
-
-For the optional lzma module on PyPy3 you will also need ``xz-devel``.
+    gdbm-devel \
+    xz-devel  # For lzma on PyPy3.
 
 On SLES11::
 
     zypper install gcc make python-devel pkg-config \
     zlib-devel libopenssl-devel libbz2-devel sqlite3-devel \
-    libexpat-devel libffi-devel python-curses
+    libexpat-devel libffi-devel python-curses \
+    xz-devel  # For lzma on PyPy3.
     (XXX plus the SLES11 version of libgdbm-dev and tk-dev)
 
-For the optional lzma module on PyPy3 you will also need ``xz-devel``.
-
 On Mac OS X, most of these build-time dependencies are installed alongside
 the Developer Tools. However, note that in order for the installation to
 find them you may need to run::
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -93,3 +93,11 @@
 of ctypes. This avoids importing ctypes in many small programs and
 scripts, which in turn avoids enabling threads (because ctypes
 creates callbacks at import time, and callbacks need threads).
+
+.. branch: new-jit-log
+
+The new logging facility that integrates with and adds features to vmprof.com.
+
+.. branch: jitlog-32bit
+
+Resolve issues to use the new logging facility on a 32bit system
diff --git a/pypy/module/_jitlog/__init__.py b/pypy/module/_jitlog/__init__.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_jitlog/__init__.py
@@ -0,0 +1,13 @@
+from pypy.interpreter.mixedmodule import MixedModule
+from rpython.rlib.rvmprof import VMProfPlatformUnsupported
+
+class Module(MixedModule):
+    """ JitLog the new logging facility """
+    appleveldefs = {
+    }
+
+    interpleveldefs = {
+        'enable': 'interp_jitlog.enable',
+        'disable': 'interp_jitlog.disable',
+        'JitlogError': 'space.fromcache(interp_jitlog.Cache).w_JitlogError',
+    }
diff --git a/pypy/module/_jitlog/interp_jitlog.py 
b/pypy/module/_jitlog/interp_jitlog.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_jitlog/interp_jitlog.py
@@ -0,0 +1,28 @@
+from pypy.interpreter.error import OperationError
+from pypy.interpreter.gateway import unwrap_spec
+from pypy.interpreter.pyframe import PyFrame
+from pypy.interpreter.pycode import PyCode
+from pypy.interpreter.baseobjspace import W_Root
+from rpython.rlib.rjitlog import rjitlog
+from rpython.rlib import jit
+
+class Cache:
+    def __init__(self, space):
+        self.w_JitlogError = space.new_exception_class("_jitlog.JitlogError")
+
+def JitlogError(space, e):
+    w_JitlogError = space.fromcache(Cache).w_JitlogError
+    return OperationError(w_JitlogError, space.wrap(e.msg))
+
+@unwrap_spec(fileno=int)
+def enable(space, fileno):
+    """ Enable PyPy's logging facility. """
+    try:
+        rjitlog.enable_jitlog(fileno)
+    except rjitlog.JitlogError, e:
+        raise JitlogError(space, e)
+
+@jit.dont_look_inside
+def disable(space):
+    """ Disable PyPy's logging facility. """
+    rjitlog.disable_jitlog()
diff --git a/pypy/module/_jitlog/test/__init__.py 
b/pypy/module/_jitlog/test/__init__.py
new file mode 100644
diff --git a/pypy/module/_jitlog/test/test__jitlog.py 
b/pypy/module/_jitlog/test/test__jitlog.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_jitlog/test/test__jitlog.py
@@ -0,0 +1,32 @@
+
+import sys
+from rpython.tool.udir import udir
+from pypy.tool.pytest.objspace import gettestobjspace
+from rpython.rlib.rjitlog import rjitlog as jl
+
+class AppTestJitLog(object):
+    spaceconfig = {'usemodules': ['_jitlog', 'struct']}
+
+    def setup_class(cls):
+        cls.w_tmpfilename = cls.space.wrap(str(udir.join('test__jitlog.1')))
+        cls.w_mark_header = cls.space.wrap(jl.MARK_JITLOG_HEADER)
+        cls.w_version = cls.space.wrap(jl.JITLOG_VERSION_16BIT_LE)
+        cls.w_is_32bit = cls.space.wrap(sys.maxint == 2**31-1)
+
+    def test_enable(self):
+        import _jitlog, struct
+        tmpfile = open(self.tmpfilename, 'wb')
+        fileno = tmpfile.fileno()
+        _jitlog.enable(fileno)
+        _jitlog.disable()
+        # no need to clsoe tmpfile, it is done by jitlog
+
+        with open(self.tmpfilename, 'rb') as fd:
+            assert fd.read(1) == self.mark_header
+            assert fd.read(2) == self.version
+            assert bool(ord(fd.read(1))) == self.is_32bit
+            count, = struct.unpack('<h', fd.read(2))
+            for i in range(count):
+                opnum = struct.unpack('<h', fd.read(2))
+                strcount = struct.unpack('<i', fd.read(4))
+                fd.read(strcount)
diff --git a/pypy/module/_vmprof/interp_vmprof.py 
b/pypy/module/_vmprof/interp_vmprof.py
--- a/pypy/module/_vmprof/interp_vmprof.py
+++ b/pypy/module/_vmprof/interp_vmprof.py
@@ -3,7 +3,7 @@
 from pypy.interpreter.pyframe import PyFrame
 from pypy.interpreter.pycode import PyCode
 from pypy.interpreter.baseobjspace import W_Root
-from rpython.rlib import rvmprof
+from rpython.rlib import rvmprof, jit
 
 # ____________________________________________________________
 
diff --git a/pypy/module/cpyext/test/test_cpyext.py 
b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -126,7 +126,14 @@
             source_strings=source_strings,
             compile_extra=compile_extra,
             link_extra=link_extra)
-    return str(soname)
+    from imp import get_suffixes, C_EXTENSION
+    pydname = soname
+    for suffix, mode, typ in get_suffixes():
+        if typ == C_EXTENSION:
+            pydname = soname.new(purebasename=modname, ext=suffix)
+            soname.rename(pydname)
+            break
+    return str(pydname)
 
 def freeze_refcnts(self):
     rawrefcount._dont_free_any_more()
@@ -359,7 +366,11 @@
                         space.sys.get('modules'),
                         space.wrap(name))
             else:
-                return os.path.dirname(mod)
+                path = os.path.dirname(mod)
+                if self.runappdirect:
+                    return path
+                else:
+                    return space.wrap(path)
 
         @gateway.unwrap_spec(mod=str, name=str)
         def reimport_module(space, mod, name):
diff --git a/pypy/module/cpyext/test/test_import.py 
b/pypy/module/cpyext/test/test_import.py
--- a/pypy/module/cpyext/test/test_import.py
+++ b/pypy/module/cpyext/test/test_import.py
@@ -39,7 +39,6 @@
 
 class AppTestImportLogic(AppTestCpythonExtensionBase):
     def test_import_logic(self):
-        skip("leak?")
         path = self.import_module(name='test_import_module', load_it=False)
         import sys
         sys.path.append(path)
diff --git a/pypy/module/cpyext/test/test_number.py 
b/pypy/module/cpyext/test/test_number.py
--- a/pypy/module/cpyext/test/test_number.py
+++ b/pypy/module/cpyext/test/test_number.py
@@ -144,3 +144,15 @@
         assert tupl[0] == 3.
         assert tupl[1] == 1.
         assert isinstance(tupl[0], float)'''
+
+    def test_PyNumber_Check(self):        
+        mod = self.import_extension('foo', [
+            ("test_PyNumber_Check", "METH_VARARGS",
+             '''
+                PyObject *obj = PyTuple_GET_ITEM(args, 0);
+                int val = PyNumber_Check(obj);
+                Py_DECREF(obj);
+                return PyInt_FromLong(val);
+            ''')])
+        val = mod.test_PyNumber_Check(10)
+        assert val == 1
diff --git a/pypy/module/cpyext/test/test_object.py 
b/pypy/module/cpyext/test/test_object.py
--- a/pypy/module/cpyext/test/test_object.py
+++ b/pypy/module/cpyext/test/test_object.py
@@ -168,7 +168,7 @@
 
     def test_hash(self, space, api):
         assert api.PyObject_Hash(space.wrap(72)) == 72
-        assert api.PyObject_Hash(space.wrap(-1)) == -1
+        assert api.PyObject_Hash(space.wrap(-1)) == -2
         assert (api.PyObject_Hash(space.wrap([])) == -1 and
             api.PyErr_Occurred() is space.w_TypeError)
         api.PyErr_Clear()
diff --git a/pypy/module/cpyext/test/test_typeobject.py 
b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -729,7 +729,7 @@
         x = list(it)
         assert x == [1]
 
-    def test_bool(self):
+    def test_intlike(self):
         module = self.import_extension('foo', [
             ("newInt", "METH_VARARGS",
              """
@@ -739,10 +739,6 @@
                 if (!PyArg_ParseTuple(args, "i", &intval))
                     return NULL;
 
-                IntLike_Type.tp_flags |= Py_TPFLAGS_DEFAULT;
-                IntLike_Type.tp_as_number = &intlike_as_number;
-                intlike_as_number.nb_nonzero = intlike_nb_nonzero;
-                if (PyType_Ready(&IntLike_Type) < 0) return NULL;
                 intObj = PyObject_New(IntLikeObject, &IntLike_Type);
                 if (!intObj) {
                     return NULL;
@@ -750,8 +746,23 @@
 
                 intObj->value = intval;
                 return (PyObject *)intObj;
-             """)],
-            """
+             """),
+            ("check", "METH_VARARGS", """
+                IntLikeObject *intObj;
+                int intval, isint;
+
+                if (!PyArg_ParseTuple(args, "i", &intval))
+                    return NULL;
+                intObj = PyObject_New(IntLikeObject, &IntLike_Type);
+                if (!intObj) {
+                    return NULL;
+                }
+                intObj->value = intval;
+                isint = PyNumber_Check((PyObject*)intObj);
+                Py_DECREF((PyObject*)intObj);
+                return PyInt_FromLong(isint);
+            """),
+            ], prologue= """
             typedef struct
             {
                 PyObject_HEAD
@@ -770,6 +781,13 @@
                 return v->value;
             }
 
+            static PyObject*
+            intlike_nb_int(PyObject* o)
+            {
+                IntLikeObject *v = (IntLikeObject*)o;
+                return PyInt_FromLong(v->value);
+            }
+
             PyTypeObject IntLike_Type = {
                 PyObject_HEAD_INIT(0)
                 /*ob_size*/             0,
@@ -777,11 +795,19 @@
                 /*tp_basicsize*/        sizeof(IntLikeObject),
             };
             static PyNumberMethods intlike_as_number;
+            """, more_init="""
+            IntLike_Type.tp_flags |= Py_TPFLAGS_DEFAULT;
+            IntLike_Type.tp_as_number = &intlike_as_number;
+            intlike_as_number.nb_nonzero = intlike_nb_nonzero;
+            intlike_as_number.nb_int = intlike_nb_int;
+            if (PyType_Ready(&IntLike_Type) < 0) return NULL;
             """)
         assert not bool(module.newInt(0))
         assert bool(module.newInt(1))
         raises(SystemError, bool, module.newInt(-1))
         raises(ValueError, bool, module.newInt(-42))
+        val = module.check(10);
+        assert val == 1
 
     def test_mathfunc(self):
         module = self.import_extension('foo', [
diff --git a/pypy/module/pypyjit/interp_jit.py 
b/pypy/module/pypyjit/interp_jit.py
--- a/pypy/module/pypyjit/interp_jit.py
+++ b/pypy/module/pypyjit/interp_jit.py
@@ -6,6 +6,7 @@
 from rpython.rlib.rarithmetic import r_uint, intmask
 from rpython.rlib.jit import JitDriver, hint, we_are_jitted, dont_look_inside
 from rpython.rlib import jit, jit_hooks
+from rpython.rlib.rjitlog import rjitlog as jl
 from rpython.rlib.jit import current_trace_length, unroll_parameters,\
      JitHookInterface
 from rpython.rtyper.annlowlevel import cast_instance_to_gcref
@@ -41,6 +42,19 @@
     from rpython.rlib import rvmprof
     return rvmprof.get_unique_id(bytecode)
 
+@jl.returns(jl.MP_FILENAME, jl.MP_LINENO,
+            jl.MP_SCOPE, jl.MP_INDEX, jl.MP_OPCODE)
+def get_location(next_instr, is_being_profiled, bytecode):
+    from pypy.tool.stdlib_opcode import opcode_method_names
+    bcindex = ord(bytecode.co_code[next_instr])
+    opname = ""
+    if 0 <= bcindex < len(opcode_method_names):
+        opname = opcode_method_names[bcindex]
+    name = bytecode.co_name
+    if not name:
+        name = ""
+    return (bytecode.co_filename, bytecode.co_firstlineno,
+            name, intmask(next_instr), opname)
 
 def should_unroll_one_iteration(next_instr, is_being_profiled, bytecode):
     return (bytecode.co_flags & CO_GENERATOR) != 0
@@ -51,6 +65,7 @@
     virtualizables = ['frame']
 
 pypyjitdriver = PyPyJitDriver(get_printable_location = get_printable_location,
+                              get_location = get_location,
                               get_unique_id = get_unique_id,
                               should_unroll_one_iteration =
                               should_unroll_one_iteration,
diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py 
b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
--- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
@@ -57,7 +57,10 @@
         cmdline.append(str(self.filepath))
         #
         env = os.environ.copy()
+        # TODO old logging system
         env['PYPYLOG'] = self.log_string + ':' + str(logfile)
+        jitlogfile = str(logfile) + '.jlog'
+        env['JITLOG'] = str(jitlogfile)
         pipe = subprocess.Popen(cmdline,
                                 env=env,
                                 stdout=subprocess.PIPE,
@@ -84,6 +87,7 @@
         log = Log(rawtraces)
         log.result = eval(stdout)
         log.logfile = str(logfile)
+        log.jitlogfile = jitlogfile
         #
         summaries  = logparser.extract_category(rawlog, 'jit-summary')
         if len(summaries) > 0:
diff --git a/pypy/module/pypyjit/test_pypy_c/test_jitlogparser.py 
b/pypy/module/pypyjit/test_pypy_c/test_jitlogparser.py
--- a/pypy/module/pypyjit/test_pypy_c/test_jitlogparser.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_jitlogparser.py
@@ -8,7 +8,6 @@
         mangle_descr)
 from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC
 
-
 class TestLogParser(BaseTestPyPyC):
     log_string = 'jit-log-opt,jit-backend'
 
diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -409,7 +409,7 @@
                 if not e.match(space, space.w_StopIteration):
                     raise
                 return space.w_False
-            if space.eq_w(w_next, w_item):
+            if space.eq_w(w_item, w_next):
                 return space.w_True
 
     def hash(space, w_obj):
@@ -425,17 +425,25 @@
                         "'%T' objects are unhashable", w_obj)
         w_result = space.get_and_call_function(w_hash, w_obj)
         w_resulttype = space.type(w_result)
+
+        # issue 2346 : returns now -2 for hashing -1 like cpython
         if space.is_w(w_resulttype, space.w_int):
+            if space.int_w(w_result) == -1:
+                return space.wrap(-2)
             return w_result
-        elif space.is_w(w_resulttype, space.w_long):
-            return space.hash(w_result)
         elif space.isinstance_w(w_result, space.w_int):
             # be careful about subclasses of 'int'...
-            return space.wrap(space.int_w(w_result))
+            int_result = space.int_w(w_result)
+            if int_result == -1:
+                int_result == -2
+            return space.wrap(int_result)
         elif space.isinstance_w(w_result, space.w_long):
             # be careful about subclasses of 'long'...
             bigint = space.bigint_w(w_result)
-            return space.wrap(bigint.hash())
+            h = bigint.hash()
+            if h == -1:
+                h = -2
+            return space.wrap(h)
         else:
             raise oefmt(space.w_TypeError,
                         "__hash__() should return an int or long")
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -795,7 +795,7 @@
         tp = space.type(w_item)
         while i < stop and i < w_list.length():
             find_jmp.jit_merge_point(tp=tp)
-            if space.eq_w(w_list.getitem(i), w_item):
+            if space.eq_w(w_item, w_list.getitem(i)):
                 return i
             i += 1
         raise ValueError
diff --git a/pypy/objspace/std/specialisedtupleobject.py 
b/pypy/objspace/std/specialisedtupleobject.py
--- a/pypy/objspace/std/specialisedtupleobject.py
+++ b/pypy/objspace/std/specialisedtupleobject.py
@@ -62,6 +62,11 @@
                 value = getattr(self, 'value%s' % i)
                 if typetuple[i] == object:
                     y = space.int_w(space.hash(value))
+                elif typetuple[i] == int:
+                    # mimic cpythons behavior of a hash value of -2 for -1
+                    y = value
+                    if y == -1:
+                        y = -2
                 elif typetuple[i] == float:
                     # get the correct hash for float which is an
                     # integer & other less frequent cases
diff --git a/pypy/objspace/std/test/test_dictmultiobject.py 
b/pypy/objspace/std/test/test_dictmultiobject.py
--- a/pypy/objspace/std/test/test_dictmultiobject.py
+++ b/pypy/objspace/std/test/test_dictmultiobject.py
@@ -948,6 +948,41 @@
         helper(lambda x: x.viewkeys())
         helper(lambda x: x.viewitems())
 
+    def test_contains(self):
+        logger = []
+
+        class Foo(object):
+
+            def __init__(self, value, name=None):
+                self.value = value
+                self.name = name or value
+
+            def __repr__(self):
+                return '<Foo %s>' % self.name
+
+            def __eq__(self, other):
+                logger.append((self, other))
+                return self.value == other.value
+
+            def __hash__(self):
+                return 42  # __eq__ will be used given all objects' hashes 
clash
+
+        foo1, foo2, foo3 = Foo(1), Foo(2), Foo(3)
+        foo42 = Foo(42)
+        foo_dict = {foo1: 1, foo2: 1, foo3: 1}
+        del logger[:]
+        foo42 in foo_dict
+        logger_copy = set(logger[:])  # prevent re-evaluation during pytest 
error print
+        assert logger_copy == {(foo3, foo42), (foo2, foo42), (foo1, foo42)}
+
+        del logger[:]
+        foo2_bis = Foo(2, '2 bis')
+        foo2_bis in foo_dict
+        logger_copy = set(logger[:])  # prevent re-evaluation during pytest 
error print
+        assert (foo2, foo2_bis) in logger_copy
+        assert logger_copy.issubset({(foo1, foo2_bis), (foo2, foo2_bis), 
(foo3, foo2_bis)})
+
+
 class AppTestStrategies(object):
     def setup_class(cls):
         if cls.runappdirect:
diff --git a/pypy/objspace/std/test/test_iterobject.py 
b/pypy/objspace/std/test/test_iterobject.py
--- a/pypy/objspace/std/test/test_iterobject.py
+++ b/pypy/objspace/std/test/test_iterobject.py
@@ -97,3 +97,32 @@
     def test_no_len_on_xrange(self):
         iterable = xrange(10)
         raises(TypeError, len, iter(iterable))
+
+    def test_contains(self):
+        logger = []
+
+        class Foo(object):
+
+            def __init__(self, value, name=None):
+                self.value = value
+                self.name = name or value
+
+            def __repr__(self):
+                return '<Foo %s>' % self.name
+
+            def __eq__(self, other):
+                logger.append((self, other))
+                return self.value == other.value
+
+        foo1, foo2, foo3 = Foo(1), Foo(2), Foo(3)
+        foo42 = Foo(42)
+        foo_list = [foo1, foo2, foo3]
+        foo42 in (x for x in foo_list)
+        logger_copy = logger[:]  # prevent re-evaluation during pytest error 
print
+        assert logger_copy == [(foo42, foo1), (foo42, foo2), (foo42, foo3)]
+
+        del logger[:]
+        foo2_bis = Foo(2, '2 bis')
+        foo2_bis in (x for x in foo_list)
+        logger_copy = logger[:]  # prevent re-evaluation during pytest error 
print
+        assert logger_copy == [(foo2_bis, foo1), (foo2_bis, foo2)]
diff --git a/pypy/objspace/std/test/test_listobject.py 
b/pypy/objspace/std/test/test_listobject.py
--- a/pypy/objspace/std/test/test_listobject.py
+++ b/pypy/objspace/std/test/test_listobject.py
@@ -503,6 +503,34 @@
         assert not l.__contains__(-20)
         assert not l.__contains__(-21)
 
+        logger = []
+
+        class Foo(object):
+
+            def __init__(self, value, name=None):
+                self.value = value
+                self.name = name or value
+
+            def __repr__(self):
+                return '<Foo %s>' % self.name
+
+            def __eq__(self, other):
+                logger.append((self, other))
+                return self.value == other.value
+
+        foo1, foo2, foo3 = Foo(1), Foo(2), Foo(3)
+        foo42 = Foo(42)
+        foo_list = [foo1, foo2, foo3]
+        foo42 in foo_list
+        logger_copy = logger[:]  # prevent re-evaluation during pytest error 
print
+        assert logger_copy == [(foo42, foo1), (foo42, foo2), (foo42, foo3)]
+
+        del logger[:]
+        foo2_bis = Foo(2, '2 bis')
+        foo2_bis in foo_list
+        logger_copy = logger[:]  # prevent re-evaluation during pytest error 
print
+        assert logger_copy == [(foo2_bis, foo1), (foo2_bis, foo2)]
+
     def test_call_list(self):
         assert list('') == []
         assert list('abc') == ['a', 'b', 'c']
diff --git a/pypy/objspace/std/test/test_setobject.py 
b/pypy/objspace/std/test/test_setobject.py
--- a/pypy/objspace/std/test/test_setobject.py
+++ b/pypy/objspace/std/test/test_setobject.py
@@ -532,6 +532,39 @@
             assert (c in s) == (c in word)
         raises(TypeError, s.__contains__, [])
 
+        logger = []
+
+        class Foo(object):
+
+            def __init__(self, value, name=None):
+                self.value = value
+                self.name = name or value
+
+            def __repr__(self):
+                return '<Foo %s>' % self.name
+
+            def __eq__(self, other):
+                logger.append((self, other))
+                return self.value == other.value
+
+            def __hash__(self):
+                return 42  # __eq__ will be used given all objects' hashes 
clash
+
+        foo1, foo2, foo3 = Foo(1), Foo(2), Foo(3)
+        foo42 = Foo(42)
+        foo_set = {foo1, foo2, foo3}
+        del logger[:]
+        foo42 in foo_set
+        logger_copy = set(logger[:])  # prevent re-evaluation during pytest 
error print
+        assert logger_copy == {(foo3, foo42), (foo2, foo42), (foo1, foo42)}
+
+        del logger[:]
+        foo2_bis = Foo(2, '2 bis')
+        foo2_bis in foo_set
+        logger_copy = set(logger[:])  # prevent re-evaluation during pytest 
error print
+        assert (foo2, foo2_bis) in logger_copy
+        assert logger_copy.issubset({(foo1, foo2_bis), (foo2, foo2_bis), 
(foo3, foo2_bis)})
+
     def test_remove(self):
         s = set('abc')
         s.remove('a')
diff --git a/pypy/objspace/std/test/test_specialisedtupleobject.py 
b/pypy/objspace/std/test/test_specialisedtupleobject.py
--- a/pypy/objspace/std/test/test_specialisedtupleobject.py
+++ b/pypy/objspace/std/test/test_specialisedtupleobject.py
@@ -177,6 +177,10 @@
 
         assert hash(a) == hash((1L, 2L)) == hash((1.0, 2.0)) == hash((1.0, 2L))
 
+        x = (-1, -1)
+        y = tuple([-1, -1])
+        assert hash(x) == hash(y)
+
     def test_getitem(self):
         t = (5, 3)
         assert (t)[0] == 5
diff --git a/pypy/objspace/std/test/test_tupleobject.py 
b/pypy/objspace/std/test/test_tupleobject.py
--- a/pypy/objspace/std/test/test_tupleobject.py
+++ b/pypy/objspace/std/test/test_tupleobject.py
@@ -269,6 +269,34 @@
         assert not 11 in t
         assert not t in t
 
+        logger = []
+
+        class Foo(object):
+
+            def __init__(self, value, name=None):
+                self.value = value
+                self.name = name or value
+
+            def __repr__(self):
+                return '<Foo %s>' % self.name
+
+            def __eq__(self, other):
+                logger.append((self, other))
+                return self.value == other.value
+
+        foo1, foo2, foo3 = Foo(1), Foo(2), Foo(3)
+        foo42 = Foo(42)
+        foo_tuple = (foo1, foo2, foo3)
+        foo42 in foo_tuple
+        logger_copy = logger[:]  # prevent re-evaluation during pytest error 
print
+        assert logger_copy == [(foo42, foo1), (foo42, foo2), (foo42, foo3)]
+
+        del logger[:]
+        foo2_bis = Foo(2, '2 bis')
+        foo2_bis in foo_tuple
+        logger_copy = logger[:]  # prevent re-evaluation during pytest error 
print
+        assert logger_copy == [(foo2_bis, foo1), (foo2_bis, foo2)]
+
     def test_add(self):
         t0 = ()
         t1 = (5, 3, 99)
diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py
--- a/pypy/objspace/std/tupleobject.py
+++ b/pypy/objspace/std/tupleobject.py
@@ -153,7 +153,7 @@
     @jit.unroll_safe
     def _descr_contains_unroll_safe(self, space, w_obj):
         for w_item in self.tolist():
-            if space.eq_w(w_item, w_obj):
+            if space.eq_w(w_obj, w_item):
                 return space.w_True
         return space.w_False
 
@@ -161,7 +161,7 @@
         tp = space.type(w_obj)
         for w_item in self.tolist():
             contains_jmp.jit_merge_point(tp=tp)
-            if space.eq_w(w_item, w_obj):
+            if space.eq_w(w_obj, w_item):
                 return space.w_True
         return space.w_False
 
diff --git a/pypy/objspace/test/test_descriptor.py 
b/pypy/objspace/test/test_descriptor.py
--- a/pypy/objspace/test/test_descriptor.py
+++ b/pypy/objspace/test/test_descriptor.py
@@ -141,3 +141,31 @@
                 return myint(15)
         assert hash(I()) == 15
         assert type(hash(I())) is int
+        
+        # check hashing of -1 to -2
+        class myint(int):
+            pass
+        class mylong(long):
+            pass
+        class myfloat(float):
+            pass
+        class myHashClass(object):
+            def __hash__(self):
+                return -1
+        class myHashClass2(object):
+            def __hash__(self):
+                return -1L
+        class myHashClass3(object):
+            def __hash__(self):
+                return -10**100
+
+        assert hash(-1) == -2
+        assert hash(-1L) == -2
+        assert hash(-1.0) == -2
+        assert hash(-1 + 0j) == -2
+        assert hash(myint(-1)) == -2
+        assert hash(mylong(-1)) == -2
+        assert hash(myfloat(-1.0)) == -2
+        assert hash(myHashClass()) == -2
+        assert hash(myHashClass2()) == -2
+        assert hash(myHashClass3()) == hash(-10**100)
diff --git a/rpython/jit/backend/arm/assembler.py 
b/rpython/jit/backend/arm/assembler.py
--- a/rpython/jit/backend/arm/assembler.py
+++ b/rpython/jit/backend/arm/assembler.py
@@ -14,7 +14,7 @@
     CoreRegisterManager, check_imm_arg, VFPRegisterManager,
     operations as regalloc_operations)
 from rpython.jit.backend.llsupport import jitframe, rewrite
-from rpython.jit.backend.llsupport.assembler import DEBUG_COUNTER, 
BaseAssembler
+from rpython.jit.backend.llsupport.assembler import BaseAssembler
 from rpython.jit.backend.llsupport.regalloc import get_scale, 
valid_addressing_size
 from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper
 from rpython.jit.backend.model import CompiledLoopToken
@@ -29,6 +29,7 @@
 from rpython.rtyper.lltypesystem import lltype, rffi
 from rpython.jit.backend.arm import callbuilder
 from rpython.rtyper.lltypesystem.lloperation import llop
+from rpython.rlib.rjitlog import rjitlog as jl
 
 class AssemblerARM(ResOpAssembler):
 
@@ -633,9 +634,17 @@
                     'loop.asm')
 
         ops_offset = self.mc.ops_offset
-        if logger is not None:
-            logger.log_loop(inputargs, operations, 0, "rewritten",
-                            name=loopname, ops_offset=ops_offset)
+
+        if logger:
+            log = logger.log_trace(jl.MARK_TRACE_ASM, None, self.mc)
+            log.write(inputargs, operations, ops_offset=ops_offset)
+
+            # legacy
+            if logger.logger_ops:
+                logger.logger_ops.log_loop(inputargs, operations, 0,
+                                           "rewritten", name=loopname,
+                                           ops_offset=ops_offset)
+
         self.teardown()
 
         debug_start("jit-backend-addr")
@@ -735,9 +744,18 @@
                           frame_depth_no_fixed_size + JITFRAME_FIXED_SIZE)
         self.fixup_target_tokens(rawstart)
         self.update_frame_depth(frame_depth)
+
         if logger:
-            logger.log_bridge(inputargs, operations, "rewritten", faildescr,
-                              ops_offset=ops_offset)
+            log = logger.log_trace(jl.MARK_TRACE_ASM, None, self.mc)
+            log.write(inputargs, operations, ops_offset)
+            # log that the already written bridge is stitched to a descr!
+            logger.log_patch_guard(descr_number, rawstart)
+
+            # legacy
+            if logger.logger_ops:
+                logger.logger_ops.log_bridge(inputargs, operations, 
"rewritten",
+                                          faildescr, ops_offset=ops_offset)
+
         self.teardown()
 
         return AsmInfo(ops_offset, startpos + rawstart, codeendpos - startpos)
diff --git a/rpython/jit/backend/llsupport/asmmemmgr.py 
b/rpython/jit/backend/llsupport/asmmemmgr.py
--- a/rpython/jit/backend/llsupport/asmmemmgr.py
+++ b/rpython/jit/backend/llsupport/asmmemmgr.py
@@ -223,6 +223,7 @@
             self.init_block_builder()
         else:
             self._become_a_plain_block_builder()
+        self.rawstart = 0
 
     def init_block_builder(self):
         self._cursubblock = lltype.nullptr(self.SUBBLOCK)
@@ -245,6 +246,9 @@
         self._cursubblock.data[index] = char
         self._cursubindex = index + 1
 
+    def absolute_addr(self):
+        return self.rawstart
+
     def overwrite(self, index, char):
         assert 0 <= index < self.get_relative_pos()
         block = self._cursubblock
@@ -280,6 +284,19 @@
             targetindex -= self.SUBBLOCK_SIZE
         assert not block
 
+    def copy_core_dump(self, addr, offset=0, count=-1):
+        HEX = '0123456789ABCDEF'
+        dump = []
+        src = rffi.cast(rffi.CCHARP, addr)
+        end = self.get_relative_pos()
+        if count != -1:
+            end = offset + count
+        for p in range(offset, end):
+            o = ord(src[p])
+            dump.append(HEX[o >> 4])
+            dump.append(HEX[o & 15])
+        return ''.join(dump)
+
     def _dump(self, addr, logname, backend=None):
         debug_start(logname)
         if have_debug_prints():
@@ -293,17 +310,11 @@
             else:
                 debug_print('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])
+            dump = self.copy_core_dump(addr)
             debug_print('CODE_DUMP',
                         '@%x' % addr,
                         '+0 ',     # backwards compatibility
-                        ''.join(dump))
+                        dump)
             #
         debug_stop(logname)
 
@@ -315,6 +326,7 @@
         allblocks.append(malloced)
         rawstart = malloced[0]
         rawstart = (rawstart + align - 1) & (-align)
+        self.rawstart = rawstart
         self.copy_to_raw_memory(rawstart)
         if self.gcroot_markers is not None:
             assert gcrootmap is not None
diff --git a/rpython/jit/backend/llsupport/assembler.py 
b/rpython/jit/backend/llsupport/assembler.py
--- a/rpython/jit/backend/llsupport/assembler.py
+++ b/rpython/jit/backend/llsupport/assembler.py
@@ -12,7 +12,7 @@
 from rpython.rlib.objectmodel import specialize, compute_unique_id
 from rpython.rtyper.annlowlevel import cast_instance_to_gcref, llhelper
 from rpython.rtyper.lltypesystem import rffi, lltype
-
+from rpython.rlib.rjitlog import rjitlog as jl
 
 DEBUG_COUNTER = lltype.Struct('DEBUG_COUNTER',
     # 'b'ridge, 'l'abel or # 'e'ntry point
@@ -73,7 +73,9 @@
         self.memcpy_addr = 0
         self.memset_addr = 0
         self.rtyper = cpu.rtyper
+        # do not rely on this attribute if you test for jitlog
         self._debug = False
+        self.loop_run_counters = []
 
     def stitch_bridge(self, faildescr, target):
         raise NotImplementedError
@@ -129,11 +131,13 @@
 
         self._build_stack_check_slowpath()
         self._build_release_gil(gc_ll_descr.gcrootmap)
+        # do not rely on the attribute _debug for jitlog
         if not self._debug:
             # if self._debug is already set it means that someone called
             # set_debug by hand before initializing the assembler. Leave it
             # as it is
-            self.set_debug(have_debug_prints_for('jit-backend-counts'))
+            should_debug = have_debug_prints_for('jit-backend-counts')
+            self.set_debug(should_debug)
         # when finishing, we only have one value at [0], the rest dies
         self.gcmap_for_finish = lltype.malloc(jitframe.GCMAP, 1,
                                               flavor='raw',
@@ -337,16 +341,14 @@
         # Here we join Path A and Path B again
         self._call_assembler_patch_jmp(jmp_location)
 
+    def get_loop_run_counters(self, index):
+        return self.loop_run_counters[index]
+
     @specialize.argtype(1)
     def _inject_debugging_code(self, looptoken, operations, tp, number):
-        if self._debug:
-            s = 0
-            for op in operations:
-                s += op.getopnum()
-
+        if self._debug or jl.jitlog_enabled():
             newoperations = []
-            self._append_debugging_code(newoperations, tp, number,
-                                        None)
+            self._append_debugging_code(newoperations, tp, number, None)
             for op in operations:
                 newoperations.append(op)
                 if op.getopnum() == rop.LABEL:
@@ -362,10 +364,6 @@
             ResOperation(rop.INCREMENT_DEBUG_COUNTER, [c_adr]))
 
     def _register_counter(self, tp, number, token):
-        # YYY very minor leak -- we need the counters to stay alive
-        # forever, just because we want to report them at the end
-        # of the process
-
         # XXX the numbers here are ALMOST unique, but not quite, use a counter
         #     or something
         struct = lltype.malloc(DEBUG_COUNTER, flavor='raw',
@@ -377,13 +375,18 @@
         else:
             assert token
             struct.number = compute_unique_id(token)
+        # YYY very minor leak -- we need the counters to stay alive
+        # forever, just because we want to report them at the end
+        # of the process
         self.loop_run_counters.append(struct)
         return struct
 
     def finish_once(self):
         if self._debug:
+            # TODO remove the old logging system when jitlog is complete
             debug_start('jit-backend-counts')
-            for i in range(len(self.loop_run_counters)):
+            length = len(self.loop_run_counters)
+            for i in range(length):
                 struct = self.loop_run_counters[i]
                 if struct.type == 'l':
                     prefix = 'TargetToken(%d)' % struct.number
@@ -400,6 +403,23 @@
                 debug_print(prefix + ':' + str(struct.i))
             debug_stop('jit-backend-counts')
 
+        self.flush_trace_counters()
+
+    def flush_trace_counters(self):
+        # this is always called, the jitlog knows if it is enabled
+        length = len(self.loop_run_counters)
+        for i in range(length):
+            struct = self.loop_run_counters[i]
+            # only log if it has been executed
+            if struct.i > 0:
+                jl._log_jit_counter(struct)
+            # reset the counter, flush in a later point in time will
+            # add up the counters!
+            struct.i = 0
+        # here would be the point to free some counters
+        # see YYY comment above! but first we should run this every once in a 
while
+        # not just when jitlog_disable is called
+
     @staticmethod
     @rgc.no_collect
     def _reacquire_gil_asmgcc(css, old_rpy_fastgil):
diff --git a/rpython/jit/backend/llsupport/llmodel.py 
b/rpython/jit/backend/llsupport/llmodel.py
--- a/rpython/jit/backend/llsupport/llmodel.py
+++ b/rpython/jit/backend/llsupport/llmodel.py
@@ -110,7 +110,7 @@
                      unique_id=0, log=True, name='', logger=None):
         return self.assembler.assemble_loop(jd_id, unique_id, logger, name,
                                             inputargs, operations,
-                                            looptoken, log=log)
+                                            looptoken, log)
 
     def stitch_bridge(self, faildescr, target):
         self.assembler.stitch_bridge(faildescr, target)
diff --git a/rpython/jit/backend/llsupport/test/ztranslation_test.py 
b/rpython/jit/backend/llsupport/test/ztranslation_test.py
--- a/rpython/jit/backend/llsupport/test/ztranslation_test.py
+++ b/rpython/jit/backend/llsupport/test/ztranslation_test.py
@@ -12,6 +12,7 @@
 from rpython.config.config import ConfigError
 from rpython.translator.tool.cbuild import ExternalCompilationInfo
 from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.rlib.rjitlog import rjitlog as jl
 
 
 class TranslationTest(CCompiledMixin):
@@ -48,9 +49,16 @@
                                  lltype.Float, macro=True, releasegil=True,
                                  compilation_info=eci)
 
+        @jl.returns(jl.MP_FILENAME,
+                    jl.MP_LINENO,
+                    jl.MP_INDEX)
+        def get_location():
+            return ("/home.py",0,0)
+
         jitdriver = JitDriver(greens = [],
                               reds = ['total', 'frame', 'j'],
-                              virtualizables = ['frame'])
+                              virtualizables = ['frame'],
+                              get_location = get_location)
         def f(i, j):
             for param, _ in unroll_parameters:
                 defl = PARAMETERS[param]
@@ -233,6 +241,23 @@
         assert res == 2
         # one for loop and one for the prologue, no unrolling
 
+    def test_flush_trace_counts(self):
+        driver = JitDriver(greens = [], reds = ['i'])
+
+        def f():
+            i = 0
+            while i < 100000:
+                driver.jit_merge_point(i=i)
+                i += 1
+
+        def main():
+            jit_hooks.stats_set_debug(None, True)
+            f()
+            jl.stats_flush_trace_counts(None)
+            return 0
+
+        res = self.meta_interp(main, [])
+        assert res == 0
 
 class TranslationRemoveTypePtrTest(CCompiledMixin):
     CPUClass = getcpuclass()
diff --git a/rpython/jit/backend/ppc/ppc_assembler.py 
b/rpython/jit/backend/ppc/ppc_assembler.py
--- a/rpython/jit/backend/ppc/ppc_assembler.py
+++ b/rpython/jit/backend/ppc/ppc_assembler.py
@@ -37,6 +37,7 @@
 from rpython.rlib.jit import AsmInfo
 from rpython.rlib.objectmodel import compute_unique_id
 from rpython.rlib.rarithmetic import r_uint
+from rpython.rlib.rjitlog import rjitlog as jl
 
 memcpy_fn = rffi.llexternal('memcpy', [llmemory.Address, llmemory.Address,
                                        rffi.SIZE_T], lltype.Void,
@@ -795,9 +796,16 @@
             looptoken._ppc_fullsize = full_size
             looptoken._ppc_ops_offset = ops_offset
         looptoken._ll_function_addr = rawstart
+
         if logger:
-            logger.log_loop(inputargs, operations, 0, "rewritten",
-                            name=loopname, ops_offset=ops_offset)
+            log = logger.log_trace(jl.MARK_TRACE_ASM, None, self.mc)
+            log.write(inputargs, operations, ops_offset=ops_offset)
+
+            # legacy
+            if logger.logger_ops:
+                logger.logger_ops.log_loop(inputargs, operations, 0,
+                                           "rewritten", name=loopname,
+                                           ops_offset=ops_offset)
 
         self.fixup_target_tokens(rawstart)
         self.teardown()
@@ -868,9 +876,18 @@
         ops_offset = self.mc.ops_offset
         frame_depth = max(self.current_clt.frame_info.jfi_frame_depth,
                           frame_depth_no_fixed_size + JITFRAME_FIXED_SIZE)
+
         if logger:
-            logger.log_bridge(inputargs, operations, "rewritten",
-                              ops_offset=ops_offset)
+            log = logger.log_trace(jl.MARK_TRACE_ASM, None, self.mc)
+            log.write(inputargs, operations, ops_offset)
+            # log that the already written bridge is stitched to a descr!
+            logger.log_patch_guard(descr_number, rawstart)
+
+            # legacy
+            if logger.logger_ops:
+                logger.logger_ops.log_bridge(inputargs, operations, 
"rewritten",
+                                          faildescr, ops_offset=ops_offset)
+
         self.fixup_target_tokens(rawstart)
         self.update_frame_depth(frame_depth)
         self.teardown()
diff --git a/rpython/jit/backend/test/jitlog_test.py 
b/rpython/jit/backend/test/jitlog_test.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/test/jitlog_test.py
@@ -0,0 +1,80 @@
+import re
+import os
+from rpython.rlib import debug
+from rpython.jit.tool.oparser import pure_parse
+from rpython.jit.metainterp import logger
+from rpython.jit.metainterp.typesystem import llhelper
+from rpython.rlib.rjitlog import rjitlog as jl
+from StringIO import StringIO
+from rpython.jit.metainterp.optimizeopt.util import equaloplists
+from rpython.jit.metainterp.history import AbstractDescr, JitCellToken, 
BasicFailDescr, BasicFinalDescr
+from rpython.jit.backend.model import AbstractCPU
+from rpython.rlib.jit import JitDriver
+from rpython.rlib.objectmodel import always_inline
+from rpython.jit.metainterp.test.support import LLJitMixin
+from rpython.rlib.rjitlog import rjitlog
+import tempfile
+
+class LoggerTest(LLJitMixin):
+
+    def test_explicit_enable(self, tmpdir):
+        file = tmpdir.join('jitlog')
+        fileno = os.open(file.strpath, os.O_WRONLY | os.O_CREAT)
+        enable_jitlog = lambda: rjitlog.enable_jitlog(fileno)
+        f = self.run_sample_loop(enable_jitlog)
+        self.meta_interp(f, [10, 0])
+
+        assert os.path.exists(file.strpath)
+        with file.open('rb') as f:
+            # check the file header
+            assert f.read(3) == jl.MARK_JITLOG_HEADER + 
jl.JITLOG_VERSION_16BIT_LE
+            assert len(f.read()) > 0
+
+    def test_env(self, monkeypatch, tmpdir):
+        file = tmpdir.join('jitlog')
+        monkeypatch.setenv("JITLOG", file.strpath)
+        f = self.run_sample_loop(None)
+        self.meta_interp(f, [10,0])
+        assert os.path.exists(file.strpath)
+        with file.open('rb') as fd:
+            # check the file header
+            assert fd.read(3) == jl.MARK_JITLOG_HEADER + 
jl.JITLOG_VERSION_16BIT_LE
+            assert len(fd.read()) > 0
+
+    def test_version(self, monkeypatch, tmpdir):
+        file = tmpdir.join('jitlog')
+        monkeypatch.setattr(jl, 'JITLOG_VERSION_16BIT_LE', '\xff\xfe')
+        monkeypatch.setenv("JITLOG", file.strpath)
+        f = self.run_sample_loop(None)
+        self.meta_interp(f, [10,0])
+        assert os.path.exists(file.strpath)
+        with file.open('rb') as fd:
+            # check the file header
+            assert fd.read(3) == jl.MARK_JITLOG_HEADER + '\xff\xfe'
+            assert len(fd.read()) > 0
+
+    def test_version(self, monkeypatch, tmpdir):
+        file = tmpdir.join('jitlog')
+        monkeypatch.setattr(jl, 'JITLOG_VERSION_16BIT_LE', '\xff\xfe')
+        monkeypatch.setenv("JITLOG", file.strpath)
+        f = self.run_sample_loop(None)
+        self.meta_interp(f, [10,0])
+        assert os.path.exists(file.strpath)
+        with file.open('rb') as fd:
+            # check the file header
+            assert fd.read(3) == jl.MARK_JITLOG_HEADER + '\xff\xfe'
+            assert len(fd.read()) > 0
+
+    def run_sample_loop(self, func, myjitdriver = None):
+        if not myjitdriver:
+            myjitdriver = JitDriver(greens = [], reds = 'auto')
+        def f(y, x):
+            res = 0
+            if func:
+                func()
+            while y > 0:
+                myjitdriver.jit_merge_point()
+                res += x
+                y -= 1
+            return res
+        return f
diff --git a/rpython/jit/backend/x86/assembler.py 
b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -3,13 +3,13 @@
 import py
 
 from rpython.jit.backend.llsupport import symbolic, jitframe, rewrite
-from rpython.jit.backend.llsupport.assembler import (GuardToken, BaseAssembler,
-                                                DEBUG_COUNTER)
+from rpython.jit.backend.llsupport.assembler import (GuardToken, 
BaseAssembler, debug_bridge)
 from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper
 from rpython.jit.backend.llsupport.gcmap import allocate_gcmap
 from rpython.jit.metainterp.history import (Const, VOID, ConstInt)
 from rpython.jit.metainterp.history import AbstractFailDescr, INT, REF, FLOAT
 from rpython.jit.metainterp.compile import ResumeGuardDescr
+from rpython.rlib.rjitlog import rjitlog as jl
 from rpython.rtyper.lltypesystem import lltype, rffi, rstr, llmemory
 from rpython.rtyper.lltypesystem.lloperation import llop
 from rpython.rtyper.annlowlevel import cast_instance_to_gcref
@@ -490,8 +490,9 @@
         clt.frame_info.clear() # for now
 
         if log:
+            number = looptoken.number
             operations = self._inject_debugging_code(looptoken, operations,
-                                                     'e', looptoken.number)
+                                                     'e', number)
 
         regalloc = RegAlloc(self, self.cpu.translate_support_code)
         #
@@ -538,9 +539,16 @@
             looptoken._x86_fullsize = full_size
             looptoken._x86_ops_offset = ops_offset
         looptoken._ll_function_addr = rawstart + functionpos
+
         if logger:
-            logger.log_loop(inputargs, operations, 0, "rewritten",
-                            name=loopname, ops_offset=ops_offset)
+            log = logger.log_trace(jl.MARK_TRACE_ASM, None, self.mc)
+            log.write(inputargs, operations, ops_offset=ops_offset)
+
+            # legacy
+            if logger.logger_ops:
+                logger.logger_ops.log_loop(inputargs, operations, 0,
+                                           "rewritten", name=loopname,
+                                           ops_offset=ops_offset)
 
         self.fixup_target_tokens(rawstart)
         self.teardown()
@@ -605,9 +613,18 @@
         ops_offset = self.mc.ops_offset
         frame_depth = max(self.current_clt.frame_info.jfi_frame_depth,
                           frame_depth_no_fixed_size + JITFRAME_FIXED_SIZE)
+
         if logger:
-            logger.log_bridge(inputargs, operations, "rewritten", faildescr,
-                              ops_offset=ops_offset)
+            log = logger.log_trace(jl.MARK_TRACE_ASM, None, self.mc)
+            log.write(inputargs, operations, ops_offset)
+            # log that the already written bridge is stitched to a descr!
+            logger.log_patch_guard(descr_number, rawstart)
+
+            # legacy
+            if logger.logger_ops:
+                logger.logger_ops.log_bridge(inputargs, operations, 
"rewritten",
+                                          faildescr, ops_offset=ops_offset)
+
         self.fixup_target_tokens(rawstart)
         self.update_frame_depth(frame_depth)
         self.teardown()
diff --git a/rpython/jit/backend/x86/runner.py 
b/rpython/jit/backend/x86/runner.py
--- a/rpython/jit/backend/x86/runner.py
+++ b/rpython/jit/backend/x86/runner.py
@@ -119,9 +119,10 @@
         looptoken.compiled_loop_token.invalidate_positions = []
 
     def get_all_loop_runs(self):
+        asm = self.assembler
         l = lltype.malloc(LOOP_RUN_CONTAINER,
-                          len(self.assembler.loop_run_counters))
-        for i, ll_s in enumerate(self.assembler.loop_run_counters):
+                          len(asm.loop_run_counters))
+        for i, ll_s in enumerate(asm.loop_run_counters):
             l[i].type = ll_s.type
             l[i].number = ll_s.number
             l[i].counter = ll_s.i
diff --git a/rpython/jit/backend/x86/test/test_jitlog.py 
b/rpython/jit/backend/x86/test/test_jitlog.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/x86/test/test_jitlog.py
@@ -0,0 +1,8 @@
+
+from rpython.jit.backend.x86.test.test_basic import Jit386Mixin
+from rpython.jit.backend.test.jitlog_test import LoggerTest
+
+class TestJitlog(Jit386Mixin, LoggerTest):
+    # for the individual tests see
+    # ====> ../../../test/jitlog_test.py
+    pass
diff --git a/rpython/jit/backend/x86/test/test_runner.py 
b/rpython/jit/backend/x86/test/test_runner.py
--- a/rpython/jit/backend/x86/test/test_runner.py
+++ b/rpython/jit/backend/x86/test/test_runner.py
@@ -590,11 +590,11 @@
             self.cpu.compile_loop(ops.inputargs, ops.operations, looptoken)
             self.cpu.execute_token(looptoken, 0)
             # check debugging info
-            struct = self.cpu.assembler.loop_run_counters[0]
+            struct = self.cpu.assembler.get_loop_run_counters(0)
             assert struct.i == 1
-            struct = self.cpu.assembler.loop_run_counters[1]
+            struct = self.cpu.assembler.get_loop_run_counters(1)
             assert struct.i == 1
-            struct = self.cpu.assembler.loop_run_counters[2]
+            struct = self.cpu.assembler.get_loop_run_counters(2)
             assert struct.i == 9
             self.cpu.finish_once()
         finally:
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
@@ -32,6 +32,7 @@
 from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
 from rpython.rtyper.annlowlevel import llhelper, cast_instance_to_gcref
 from rpython.rlib.jit import AsmInfo
+from rpython.rlib.rjitlog import rjitlog as jl
 
 class JitFrameTooDeep(Exception):
     pass
@@ -669,9 +670,16 @@
             looptoken._zarch_rawstart = rawstart
             looptoken._zarch_fullsize = full_size
             looptoken._zarch_ops_offset = ops_offset
+
         if logger:
-            logger.log_loop(inputargs, operations, 0, "rewritten",
-                            name=loopname, ops_offset=ops_offset)
+            log = logger.log_trace(jl.MARK_TRACE_ASM, None, self.mc)
+            log.write(inputargs, operations, ops_offset=ops_offset)
+
+            # legacy
+            if logger.logger_ops:
+                logger.logger_ops.log_loop(inputargs, operations, 0,
+                                           "rewritten", name=loopname,
+                                           ops_offset=ops_offset)
 
         self.fixup_target_tokens(rawstart)
         self.teardown()
@@ -736,9 +744,18 @@
         ops_offset = self.mc.ops_offset
         frame_depth = max(self.current_clt.frame_info.jfi_frame_depth,
                           frame_depth_no_fixed_size + JITFRAME_FIXED_SIZE)
+
         if logger:
-            logger.log_bridge(inputargs, operations, "rewritten",
-                              ops_offset=ops_offset)
+            log = logger.log_trace(jl.MARK_TRACE_ASM, None, self.mc)
+            log.write(inputargs, operations, ops_offset)
+            # log that the already written bridge is stitched to a descr!
+            logger.log_patch_guard(descr_number, rawstart)
+
+            # legacy
+            if logger.logger_ops:
+                logger.logger_ops.log_bridge(inputargs, operations, 
"rewritten",
+                                          faildescr, ops_offset=ops_offset)
+
         self.fixup_target_tokens(rawstart)
         self.update_frame_depth(frame_depth)
         self.teardown()
diff --git a/rpython/jit/backend/zarch/test/test_jitlog.py 
b/rpython/jit/backend/zarch/test/test_jitlog.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/zarch/test/test_jitlog.py
@@ -0,0 +1,8 @@
+
+from rpython.jit.backend.zarch.test.support import JitZARCHMixin
+from rpython.jit.backend.test.jitlog_test import LoggerTest
+
+class TestJitlog(JitZARCHMixin, LoggerTest):
+    # for the individual tests see
+    # ====> ../../../test/jitlog_test.py
+    pass
diff --git a/rpython/jit/backend/zarch/test/test_pool.py 
b/rpython/jit/backend/zarch/test/test_pool.py
--- a/rpython/jit/backend/zarch/test/test_pool.py
+++ b/rpython/jit/backend/zarch/test/test_pool.py
@@ -40,7 +40,7 @@
 
     def test_constant_in_call_malloc(self):
         c = ConstPtr(rffi.cast(llmemory.GCREF, 0xdeadbeef1234))
-        self.ensure_can_hold(rop.CALL_MALLOC_GC, [c], descr=self.calldescr)
+        self.ensure_can_hold(rop.COND_CALL, [c], descr=self.calldescr)
         assert self.const_in_pool(c)
         assert self.const_in_pool(ConstPtr(rffi.cast(llmemory.GCREF, 
0xdeadbeef1234)))
 
diff --git a/rpython/jit/metainterp/compile.py 
b/rpython/jit/metainterp/compile.py
--- a/rpython/jit/metainterp/compile.py
+++ b/rpython/jit/metainterp/compile.py
@@ -6,6 +6,7 @@
 from rpython.rlib.rarithmetic import r_uint, intmask
 from rpython.rlib import rstack
 from rpython.rlib.jit import JitDebugInfo, Counters, dont_look_inside
+from rpython.rlib.rjitlog import rjitlog as jl
 from rpython.conftest import option
 
 from rpython.jit.metainterp.resoperation import ResOperation, rop,\
@@ -217,6 +218,7 @@
         loop_info, ops = optimize_trace(metainterp_sd, jitdriver_sd,
                                         data, metainterp.box_names_memo)
     except InvalidLoop:
+        metainterp_sd.jitlog.trace_aborted()
         trace.cut_at(cut_at)
         return None
     loop = create_empty_loop(metainterp)
@@ -250,7 +252,10 @@
     history = metainterp.history
     trace = history.trace
     warmstate = jitdriver_sd.warmstate
-
+    #
+    metainterp_sd.jitlog.start_new_trace(metainterp_sd,
+            faildescr=None, entry_bridge=False)
+    #
     enable_opts = jitdriver_sd.warmstate.enable_opts
     if try_disabling_unroll:
         if 'unroll' not in enable_opts:
@@ -275,6 +280,7 @@
                                                    preamble_data,
                                                    metainterp.box_names_memo)
     except InvalidLoop:
+        metainterp_sd.jitlog.trace_aborted()
         history.cut(cut_at)
         return None
 
@@ -291,6 +297,7 @@
                                              loop_data,
                                              metainterp.box_names_memo)
     except InvalidLoop:
+        metainterp_sd.jitlog.trace_aborted()
         history.cut(cut_at)
         return None
 
@@ -340,7 +347,10 @@
     metainterp_sd = metainterp.staticdata
     jitdriver_sd = metainterp.jitdriver_sd
     history = metainterp.history
-
+    #
+    metainterp_sd.jitlog.start_new_trace(metainterp_sd,
+            faildescr=resumekey, entry_bridge=False)
+    #
     loop_jitcell_token = metainterp.get_procedure_token(greenkey)
     assert loop_jitcell_token
 
@@ -368,6 +378,7 @@
                                                  loop_data,
                                                  metainterp.box_names_memo)
         except InvalidLoop:
+            metainterp_sd.jitlog.trace_aborted()
             history.cut(cut)
             return None
 
@@ -476,22 +487,28 @@
 
 def do_compile_loop(jd_id, unique_id, metainterp_sd, inputargs, operations,
                     looptoken, log=True, name='', memo=None):
+    # legacy
     metainterp_sd.logger_ops.log_loop(inputargs, operations, -2,
                                       'compiling', None, name, memo)
+    _log = metainterp_sd.jitlog.log_trace(jl.MARK_TRACE_OPT, metainterp_sd, 
None)
+    _log.write(inputargs, operations)
     return metainterp_sd.cpu.compile_loop(inputargs,
                                           operations, looptoken,
                                           jd_id=jd_id, unique_id=unique_id,
                                           log=log, name=name,
-                                          logger=metainterp_sd.logger_ops)
+                                          logger=metainterp_sd.jitlog)
 
 def do_compile_bridge(metainterp_sd, faildescr, inputargs, operations,
                       original_loop_token, log=True, memo=None):
+    # legacy
     metainterp_sd.logger_ops.log_bridge(inputargs, operations, "compiling",
                                         memo=memo)
+    _log = metainterp_sd.jitlog.log_trace(jl.MARK_TRACE_OPT, metainterp_sd, 
None)
+    _log.write(inputargs, operations)
     assert isinstance(faildescr, AbstractFailDescr)
     return metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations,
                                             original_loop_token, log=log,
-                                            logger=metainterp_sd.logger_ops)
+                                            logger=metainterp_sd.jitlog)
 
 def forget_optimization_info(lst, reset_values=False):
     for item in lst:
@@ -511,9 +528,7 @@
         patch_new_loop_to_load_virtualizable_fields(loop, jitdriver_sd, vable)
 
     original_jitcell_token = loop.original_jitcell_token
-    globaldata = metainterp_sd.globaldata
-    original_jitcell_token.number = n = globaldata.loopnumbering
-    globaldata.loopnumbering += 1
+    original_jitcell_token.number = n = metainterp_sd.jitlog.trace_id
 
     if not we_are_translated():
         show_procedures(metainterp_sd, loop)
@@ -531,6 +546,7 @@
     operations = get_deep_immutable_oplist(loop.operations)
     metainterp_sd.profiler.start_backend()
     debug_start("jit-backend")
+    log = have_debug_prints() or jl.jitlog_enabled()
     try:
         loopname = jitdriver_sd.warmstate.get_location_str(greenkey)
         unique_id = jitdriver_sd.warmstate.get_unique_id(greenkey)
@@ -538,7 +554,7 @@
                                   loop.inputargs,
                                   operations, original_jitcell_token,
                                   name=loopname,
-                                  log=have_debug_prints(),
+                                  log=log,
                                   memo=memo)
     finally:
         debug_stop("jit-backend")
@@ -582,10 +598,11 @@
     operations = get_deep_immutable_oplist(operations)
     metainterp_sd.profiler.start_backend()
     debug_start("jit-backend")
+    log = have_debug_prints() or jl.jitlog_enabled()
     try:
         asminfo = do_compile_bridge(metainterp_sd, faildescr, inputargs,
                                     operations,
-                                    original_loop_token, have_debug_prints(),
+                                    original_loop_token, log,
                                     memo)
     finally:
         debug_stop("jit-backend")
@@ -1020,7 +1037,7 @@
 
 def compile_trace(metainterp, resumekey, runtime_boxes):
     """Try to compile a new bridge leading from the beginning of the history
-    to some existging place.
+    to some existing place.
     """
 
     from rpython.jit.metainterp.optimizeopt import optimize_trace
@@ -1033,6 +1050,10 @@
 
     metainterp_sd = metainterp.staticdata
     jitdriver_sd = metainterp.jitdriver_sd
+    #
+    metainterp_sd.jitlog.start_new_trace(metainterp_sd,
+            faildescr=resumekey, entry_bridge=False)
+    #
     if isinstance(resumekey, ResumeAtPositionDescr):
         inline_short_preamble = False
     else:
@@ -1057,6 +1078,7 @@
         info, newops = optimize_trace(metainterp_sd, jitdriver_sd,
                                       data, metainterp.box_names_memo)
     except InvalidLoop:
+        metainterp_sd.jitlog.trace_aborted()
         #pdb.post_mortem(sys.exc_info()[2])
         debug_print("compile_new_bridge: got an InvalidLoop")
         # XXX I am fairly convinced that optimize_bridge cannot actually raise
diff --git a/rpython/jit/metainterp/optimizeopt/__init__.py 
b/rpython/jit/metainterp/optimizeopt/__init__.py
--- a/rpython/jit/metainterp/optimizeopt/__init__.py
+++ b/rpython/jit/metainterp/optimizeopt/__init__.py
@@ -7,6 +7,7 @@
 from rpython.jit.metainterp.optimizeopt.simplify import OptSimplify
 from rpython.jit.metainterp.optimizeopt.pure import OptPure
 from rpython.jit.metainterp.optimizeopt.earlyforce import OptEarlyForce
+from rpython.rlib.rjitlog import rjitlog as jl
 from rpython.rlib.jit import PARAMETERS, ENABLE_ALL_OPTS
 from rpython.rlib.unroll import unrolling_iterable
 from rpython.rlib.debug import debug_start, debug_stop, debug_print
@@ -57,6 +58,9 @@
     """
     debug_start("jit-optimize")
     try:
+        # mark that a new trace has been started
+        log = metainterp_sd.jitlog.log_trace(jl.MARK_TRACE, metainterp_sd, 
None)
+        log.write_trace(compile_data.trace)
         if compile_data.log_noopt:
             metainterp_sd.logger_noopt.log_loop_from_trace(compile_data.trace, 
memo=memo)
         if memo is None:
diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py 
b/rpython/jit/metainterp/optimizeopt/dependency.py
--- a/rpython/jit/metainterp/optimizeopt/dependency.py
+++ b/rpython/jit/metainterp/optimizeopt/dependency.py
@@ -22,6 +22,8 @@
                      , (rop.UNICODESETITEM, 0, -1)
                      ]
 
+UNROLLED_MODIFY_COMPLEX_OBJ = unrolling_iterable(MODIFY_COMPLEX_OBJ)
+
 LOAD_COMPLEX_OBJ = [ (rop.GETARRAYITEM_GC_I, 0, 1)
                    , (rop.GETARRAYITEM_GC_F, 0, 1)
                    , (rop.GETARRAYITEM_GC_R, 0, 1)
@@ -40,6 +42,8 @@
                    , (rop.GETFIELD_RAW_R, 0, -1)
                    ]
 
+UNROLLED_LOAD_COMPLEX_OBJ = unrolling_iterable(LOAD_COMPLEX_OBJ)
+
 class Path(object):
     def __init__(self,path):
         self.path = path
@@ -202,7 +206,7 @@
         args = []
         op = self.op
         if self.modifies_complex_object():
-            for opnum, i, j in unrolling_iterable(MODIFY_COMPLEX_OBJ):
+            for opnum, i, j in UNROLLED_MODIFY_COMPLEX_OBJ: 
#unrolling_iterable(MODIFY_COMPLEX_OBJ):
                 if op.getopnum() == opnum:
                     op_args = op.getarglist()
                     if j == -1:
@@ -723,7 +727,7 @@
         if node.loads_from_complex_object():
             # If this complex object load operation loads an index that has 
been
             # modified, the last modification should be used to put a def-use 
edge.
-            for opnum, i, j in unrolling_iterable(LOAD_COMPLEX_OBJ):
+            for opnum, i, j in UNROLLED_LOAD_COMPLEX_OBJ:
                 if opnum == op.getopnum():
                     cobj = op.getarg(i)
                     if j != -1:
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py 
b/rpython/jit/metainterp/optimizeopt/test/test_util.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_util.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py
@@ -21,6 +21,7 @@
 from rpython.jit.metainterp.resoperation import (rop, ResOperation,
         InputArgRef, AbstractValue, OpHelpers)
 from rpython.jit.metainterp.optimizeopt.util import args_dict
+from rpython.rlib.rjitlog import rjitlog as jl
 
 
 def test_sort_descrs():
@@ -484,6 +485,7 @@
         self.options = Fake()
         self.globaldata = Fake()
         self.config = get_combined_translation_config(translating=True)
+        self.jitlog = jl.JitLogger()
 
     class logger_noopt:
         @classmethod
diff --git a/rpython/jit/metainterp/pyjitpl.py 
b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -13,6 +13,7 @@
 from rpython.jit.metainterp.logger import Logger
 from rpython.jit.metainterp.optimizeopt.util import args_dict
 from rpython.jit.metainterp.resoperation import rop, OpHelpers, GuardResOp
+from rpython.rlib.rjitlog import rjitlog as jl
 from rpython.rlib import nonconst, rstack
 from rpython.rlib.debug import debug_start, debug_stop, debug_print
 from rpython.rlib.debug import have_debug_prints, make_sure_not_resized
@@ -1760,8 +1761,12 @@
         self.cpu = cpu
         self.stats = self.cpu.stats
         self.options = options
+        self.jitlog = jl.JitLogger(self.cpu)
         self.logger_noopt = Logger(self)
         self.logger_ops = Logger(self, guard_number=True)
+        # legacy loggers
+        self.jitlog.logger_noopt = self.logger_noopt
+        self.jitlog.logger_ops = self.logger_ops
 
         self.profiler = ProfilerClass()
         self.profiler.cpu = cpu
@@ -1849,6 +1854,7 @@
     def _setup_once(self):
         """Runtime setup needed by the various components of the JIT."""
         if not self.globaldata.initialized:
+            self.jitlog.setup_once()
             debug_print(self.jit_starting_line)
             self.cpu.setup_once()
             if not self.profiler.initialized:
@@ -1925,7 +1931,6 @@
         self.initialized = False
         self.indirectcall_dict = None
         self.addr2name = None
-        self.loopnumbering = 0
 
 # ____________________________________________________________
 
diff --git a/rpython/jit/metainterp/test/test_compile.py 
b/rpython/jit/metainterp/test/test_compile.py
--- a/rpython/jit/metainterp/test/test_compile.py
+++ b/rpython/jit/metainterp/test/test_compile.py
@@ -4,6 +4,7 @@
 from rpython.jit.metainterp.compile import compile_loop
 from rpython.jit.metainterp.compile import compile_tmp_callback
 from rpython.jit.metainterp import jitexc
+from rpython.rlib.rjitlog import rjitlog as jl
 from rpython.jit.metainterp import jitprof, typesystem, compile
 from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin
 from rpython.jit.tool.oparser import parse, convert_loop_to_trace
@@ -51,13 +52,14 @@
         return 'location'
 
 class FakeGlobalData(object):
-    loopnumbering = 0
+    pass
 
 class FakeMetaInterpStaticData(object):
     all_descrs = []
     logger_noopt = FakeLogger()
     logger_ops = FakeLogger()
     config = get_combined_translation_config(translating=True)
+    jitlog = jl.JitLogger()
 
     stats = Stats(None)
     profiler = jitprof.EmptyProfiler()
@@ -78,8 +80,8 @@
     cpu = FakeCPU()
     staticdata = FakeMetaInterpStaticData()
     staticdata.cpu = cpu
-    staticdata.globaldata = FakeGlobalData()
-    staticdata.globaldata.loopnumbering = 1
+    staticdata.jitlog = jl.JitLogger(cpu)
+    staticdata.jitlog.trace_id = 1
     #
     loop = parse('''
     [p1]
@@ -106,8 +108,7 @@
     jitcell_token = target_token.targeting_jitcell_token
     assert jitcell_token == target_token.original_jitcell_token
     assert jitcell_token.target_tokens == [target_token]
-    assert jitcell_token.number == 1
-    assert staticdata.globaldata.loopnumbering == 2
+    assert jitcell_token.number == 2
     #
     assert len(cpu.seen) == 1
     assert cpu.seen[0][2] == jitcell_token
diff --git a/rpython/jit/metainterp/warmspot.py 
b/rpython/jit/metainterp/warmspot.py
--- a/rpython/jit/metainterp/warmspot.py
+++ b/rpython/jit/metainterp/warmspot.py
@@ -6,6 +6,7 @@
     cast_base_ptr_to_instance, hlstr, cast_instance_to_gcref)
 from rpython.rtyper.llannotation import lltype_to_annotation
 from rpython.annotator import model as annmodel
+from rpython.annotator.dictdef import DictDef
 from rpython.rtyper.llinterp import LLException
 from rpython.rtyper.test.test_llinterp import get_interpreter, clear_tcache
 from rpython.flowspace.model import SpaceOperation, Variable, Constant
@@ -119,6 +120,7 @@
         return interp, graph
     res = interp.eval_graph(graph, args)
     if not kwds.get('translate_support_code', False):
+        warmrunnerdesc.metainterp_sd.jitlog.finish()
         warmrunnerdesc.metainterp_sd.profiler.finish()
         warmrunnerdesc.metainterp_sd.cpu.finish_once()
     print '~~~ return value:', repr(res)
@@ -563,12 +565,12 @@
         jd._EnterJitAssembler = EnterJitAssembler
 
     def make_driverhook_graphs(self):
-        s_Str = annmodel.SomeString()
         #
         annhelper = MixLevelHelperAnnotator(self.translator.rtyper)
         for jd in self.jitdrivers_sd:
             jd._get_printable_location_ptr = self._make_hook_graph(jd,
-                annhelper, jd.jitdriver.get_printable_location, s_Str)
+                annhelper, jd.jitdriver.get_printable_location,
+                annmodel.SomeString())
             jd._get_unique_id_ptr = self._make_hook_graph(jd,
                 annhelper, jd.jitdriver.get_unique_id, annmodel.SomeInteger())
             jd._confirm_enter_jit_ptr = self._make_hook_graph(jd,
@@ -579,6 +581,34 @@
             jd._should_unroll_one_iteration_ptr = self._make_hook_graph(jd,
                 annhelper, jd.jitdriver.should_unroll_one_iteration,
                 annmodel.s_Bool)
+            #
+            items = []
+            types = ()
+            pos = ()
+            if jd.jitdriver.get_location:
+                assert hasattr(jd.jitdriver.get_location, '_loc_types'), """
+                You must decorate your get_location function:
+
+                from rpython.rlib.rjitlog import rjitlog as jl
+                @jl.returns(jl.MP_FILENAME, jl.MP_XXX, ...)
+                def get_loc(your, green, keys):
+                    name = "x.txt" # extract it from your green keys
+                    return (name, ...)
+                """
+                types = jd.jitdriver.get_location._loc_types
+                del jd.jitdriver.get_location._loc_types
+                #
+                for _,type in types:
+                    if type == 's':
+                        items.append(annmodel.SomeString())
+                    elif type == 'i':
+                        items.append(annmodel.SomeInteger())
+                    else:
+                        raise NotImplementedError
+            s_Tuple = annmodel.SomeTuple(items)
+            jd._get_location_ptr = self._make_hook_graph(jd,
+                annhelper, jd.jitdriver.get_location, s_Tuple)
+            jd._get_loc_types = types
         annhelper.finish()
 
     def _make_hook_graph(self, jitdriver_sd, annhelper, func,
diff --git a/rpython/jit/metainterp/warmstate.py 
b/rpython/jit/metainterp/warmstate.py
--- a/rpython/jit/metainterp/warmstate.py
+++ b/rpython/jit/metainterp/warmstate.py
@@ -6,6 +6,7 @@
 from rpython.rlib.debug import debug_start, debug_stop, debug_print
 from rpython.rlib.debug import have_debug_prints_for
 from rpython.rlib.jit import PARAMETERS
+from rpython.rlib.rjitlog import rjitlog as jl
 from rpython.rlib.nonconst import NonConstant
 from rpython.rlib.objectmodel import specialize, we_are_translated, r_dict
 from rpython.rlib.rarithmetic import intmask, r_uint
@@ -703,8 +704,35 @@
             drivername = jitdriver.name
         else:
             drivername = '<unknown jitdriver>'
-        get_location_ptr = self.jitdriver_sd._get_printable_location_ptr
-        if get_location_ptr is None:
+        # get_location returns 
+        get_location_ptr = getattr(self.jitdriver_sd, '_get_location_ptr', 
None)
+        if get_location_ptr is not None:
+            types = self.jitdriver_sd._get_loc_types
+            unwrap_greenkey = self.make_unwrap_greenkey()
+            unrolled_types = unrolling_iterable(enumerate(types))
+            def get_location(greenkey):
+                greenargs = unwrap_greenkey(greenkey)
+                fn = support.maybe_on_top_of_llinterp(rtyper, get_location_ptr)
+                value_tuple = fn(*greenargs)
+                values = []
+                for i, (sem_type,gen_type) in unrolled_types:
+                    if gen_type == "s":
+                        value = getattr(value_tuple, 'item' + str(i))
+                        values.append(jl.wrap(sem_type,gen_type,hlstr(value)))
+                    elif gen_type == "i":
+                        value = getattr(value_tuple, 'item' + str(i))
+                        
values.append(jl.wrap(sem_type,gen_type,intmask(value)))
+                    else:
+                        raise NotImplementedError
+                return values
+            self.get_location_types = list(types)
+            self.get_location = get_location
+        else:
+            self.get_location_types = None
+            self.get_location = None
+        #
+        printable_loc_ptr = self.jitdriver_sd._get_printable_location_ptr
+        if printable_loc_ptr is None:
             missing = '(%s: no get_printable_location)' % drivername
             def get_location_str(greenkey):
                 return missing
@@ -720,7 +748,7 @@
                 if not have_debug_prints_for("jit-"):
                     return missing
                 greenargs = unwrap_greenkey(greenkey)
-                fn = support.maybe_on_top_of_llinterp(rtyper, get_location_ptr)
+                fn = support.maybe_on_top_of_llinterp(rtyper, 
printable_loc_ptr)
                 llres = fn(*greenargs)
                 if not we_are_translated() and isinstance(llres, str):
                     return llres
diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py
--- a/rpython/rlib/jit.py
+++ b/rpython/rlib/jit.py
@@ -605,8 +605,27 @@
                  get_printable_location=None, confirm_enter_jit=None,
                  can_never_inline=None, should_unroll_one_iteration=None,
                  name='jitdriver', check_untranslated=True, vectorize=False,
-                 get_unique_id=None, is_recursive=False):
-        "NOT_RPYTHON"
+                 get_unique_id=None, is_recursive=False, get_location=None):
+        """ NOT_RPYTHON
+            get_location:
+              The return value is designed to provide enough information to 
express the
+              state of an interpreter when invoking jit_merge_point.
+              For a bytecode interperter such as PyPy this includes, filename, 
line number,
+              function name, and more information. However, it should also be 
able to express
+              the same state for an interpreter that evaluates an AST.
+              return paremter:
+                0 -> filename. An absolute path specifying the file the 
interpreter invoked.
+                               If the input source is no file it should start 
with the
+                               prefix: "string://<name>"
+                1 -> line number. The line number in filename. This should at 
least point to
+                                  the enclosing name. It can however point to 
the specific
+                                  source line of the instruction executed by 
the interpreter.
+                2 -> enclosing name. E.g. the function name.
+                3 -> index. 64 bit number indicating the execution progress. 
It can either be
+                     an offset to byte code, or an index to the node in an AST
+                4 -> operation name. a name further describing the current 
program counter.
+                     this can be either a byte code name or the name of an AST 
node
+        """
         if greens is not None:
             self.greens = greens
         self.name = name
@@ -640,6 +659,7 @@
         assert get_jitcell_at is None, "get_jitcell_at no longer used"
         assert set_jitcell_at is None, "set_jitcell_at no longer used"
         self.get_printable_location = get_printable_location
+        self.get_location = get_location
         if get_unique_id is None:
             get_unique_id = lambda *args: 0
         self.get_unique_id = get_unique_id
@@ -880,6 +900,7 @@
         driver = self.instance.im_self
         h = self.annotate_hook
         h(driver.get_printable_location, driver.greens, **kwds_s)
+        h(driver.get_location, driver.greens, **kwds_s)
 
     def annotate_hook(self, func, variables, args_s=[], **kwds_s):
         if func is None:
diff --git a/rpython/rlib/rjitlog/__init__.py b/rpython/rlib/rjitlog/__init__.py
new file mode 100644
diff --git a/rpython/rlib/rjitlog/rjitlog.py b/rpython/rlib/rjitlog/rjitlog.py
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/rjitlog/rjitlog.py
@@ -0,0 +1,614 @@
+import py
+import sys
+import weakref
+import struct
+import os
+from rpython.rlib import jit
+from rpython.tool.udir import udir
+from rpython.tool.version import rpythonroot
+from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.translator.tool.cbuild import ExternalCompilationInfo
+from rpython.jit.metainterp import resoperation as resoperations
+from rpython.jit.metainterp.resoperation import rop
+from rpython.jit.metainterp.history import ConstInt, ConstFloat
+from rpython.rlib.objectmodel import we_are_translated
+from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
+from rpython.rlib.objectmodel import compute_unique_id, always_inline
+from rpython.rlib.objectmodel import we_are_translated, specialize
+from rpython.rlib.unroll import unrolling_iterable
+from rpython.rlib.jit_hooks import register_helper
+from rpython.annotator import model as annmodel
+
+
+ROOT = py.path.local(rpythonroot).join('rpython', 'rlib', 'rjitlog')
+SRC = ROOT.join('src')
+
+_libs = []
+if sys.platform.startswith('linux'):
+    _libs = ['dl']
+eci_kwds = dict(
+    include_dirs = [SRC],
+    includes = ['rjitlog.h'],
+    libraries = _libs,
+    separate_module_files = [SRC.join('rjitlog.c')],
+    post_include_bits=['#define RPYTHON_JITLOG\n'],
+    )
+eci = ExternalCompilationInfo(**eci_kwds)
+
+# jit log functions
+jitlog_init = rffi.llexternal("jitlog_init", [rffi.INT],
+                              rffi.CCHARP, compilation_info=eci)
+jitlog_try_init_using_env = rffi.llexternal("jitlog_try_init_using_env",
+                              [], lltype.Void, compilation_info=eci)
+jitlog_write_marked = rffi.llexternal("jitlog_write_marked",
+                              [rffi.CCHARP, rffi.INT],
+                              lltype.Void, compilation_info=eci,
+                              releasegil=False)
+jitlog_enabled = rffi.llexternal("jitlog_enabled", [], rffi.INT,
+                                 compilation_info=eci,
+                                 releasegil=False)
+jitlog_teardown = rffi.llexternal("jitlog_teardown", [], lltype.Void,
+                                  compilation_info=eci)
+
+class JitlogError(Exception):
+    def __init__(self, msg):
+        self.msg = msg
+    def __str__(self):
+        return self.msg
+
+@register_helper(None)
+def stats_flush_trace_counts(warmrunnerdesc):
+    if not we_are_translated():
+        return # first param is None untranslated
+    warmrunnerdesc.metainterp_sd.cpu.assembler.flush_trace_counters()
+
+@jit.dont_look_inside
+def enable_jitlog(fileno):
+    # initialize the jit log
+    p_error = jitlog_init(fileno)
+    if p_error:
+        raise JitlogError(rffi.charp2str(p_error))
+    blob = assemble_header()
+    jitlog_write_marked(MARK_JITLOG_HEADER + blob, len(blob) + 1)
+
+def disable_jitlog():
+    stats_flush_trace_counts(None)
+    jitlog_teardown()
+
+
+def commonprefix(a,b):
+    "Given a list of pathnames, returns the longest common leading component"
+    assert a is not None
+    assert b is not None
+    la = len(a)
+    lb = len(b)
+    c = min(la,lb)
+    if c == 0:
+        return ""
+    for i in range(c):
+        if a[i] != b[i]:
+            return a[:i] # partly matching
+    return a # full match
+
+@always_inline
+def encode_str(string):
+    val = len(string)
+    return ''.join([chr((val >> 0) & 0xff),
+                    chr((val >> 8) & 0xff),
+                    chr((val >> 16) & 0xff),
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to