[pypy-commit] pypy default: Trying out a small hack: setting the oopspec to 'jit.not_in_trace()'

arigo noreply at buildbot.pypy.org
Wed Oct 8 20:55:18 CEST 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r73841:277d77803c7a
Date: 2014-10-08 18:42 +0200
http://bitbucket.org/pypy/pypy/changeset/277d77803c7a/

Log:	Trying out a small hack: setting the oopspec to 'jit.not_in_trace()'
	makes the function call disappear from the jit traces. It is still
	called in interpreted mode, and by the jit tracing and blackholing,
	but not by the final assembler.

diff --git a/rpython/jit/codewriter/effectinfo.py b/rpython/jit/codewriter/effectinfo.py
--- a/rpython/jit/codewriter/effectinfo.py
+++ b/rpython/jit/codewriter/effectinfo.py
@@ -25,6 +25,7 @@
     OS_THREADLOCALREF_GET       = 5    # llop.threadlocalref_get
     OS_GET_ERRNO                = 6    # rposix.get_errno
     OS_SET_ERRNO                = 7    # rposix.set_errno
+    OS_NOT_IN_TRACE             = 8    # for calls not recorded in the jit trace
     #
     OS_STR_CONCAT               = 22   # "stroruni.concat"
     OS_STR_SLICE                = 23   # "stroruni.slice"
@@ -96,6 +97,7 @@
     _OS_CANRAISE = set([
         OS_NONE, OS_STR2UNICODE, OS_LIBFFI_CALL, OS_RAW_MALLOC_VARSIZE_CHAR,
         OS_JIT_FORCE_VIRTUAL, OS_SHRINK_ARRAY, OS_DICT_LOOKUP,
+        OS_NOT_IN_TRACE,
     ])
 
     def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays,
diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -1562,7 +1562,18 @@
             kind = getkind(args[0].concretetype)
             return SpaceOperation('%s_isvirtual' % kind, args, op.result)
         elif oopspec_name == 'jit.force_virtual':
-            return self._handle_oopspec_call(op, args, EffectInfo.OS_JIT_FORCE_VIRTUAL, EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE)
+            return self._handle_oopspec_call(op, args,
+                EffectInfo.OS_JIT_FORCE_VIRTUAL,
+                EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE)
+        elif oopspec_name == 'jit.not_in_trace':
+            # ignore 'args' and use the original 'op.args'
+            if op.result.concretetype is not lltype.Void:
+                raise Exception(
+                    "%r: jit.not_in_trace() function must return None"
+                    % (op.args[0],))
+            return self._handle_oopspec_call(op, op.args[1:],
+                EffectInfo.OS_NOT_IN_TRACE,
+                EffectInfo.EF_CAN_RAISE)
         else:
             raise AssertionError("missing support for %r" % oopspec_name)
 
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
@@ -1427,6 +1427,8 @@
                 if effect == effectinfo.EF_LOOPINVARIANT:
                     return self.execute_varargs(rop.CALL_LOOPINVARIANT, allboxes,
                                                 descr, False, False)
+                if effectinfo.oopspecindex == effectinfo.OS_NOT_IN_TRACE:
+                    return self.metainterp.do_not_in_trace_call(allboxes, descr)
                 exc = effectinfo.check_can_raise()
                 pure = effectinfo.check_is_elidable()
                 return self.execute_varargs(rop.CALL, allboxes, descr, exc, pure)
@@ -2830,6 +2832,19 @@
         if not we_are_translated():       # for llgraph
             descr._original_func_ = op.getarg(0).value
 
+    def do_not_in_trace_call(self, allboxes, descr):
+        self.clear_exception()
+        resbox = executor.execute_varargs(self.cpu, self, rop.CALL,
+                                          allboxes, descr)
+        assert resbox is None
+        if self.last_exc_value_box is not None:
+            # cannot trace this!  it raises, so we have to follow the
+            # exception-catching path, but the trace doesn't contain
+            # the call at all
+            raise SwitchToBlackhole(Counters.ABORT_ESCAPE,
+                                    raising_exception=True)
+        return None
+
 # ____________________________________________________________
 
 class ChangeFrame(jitexc.JitException):
diff --git a/rpython/jit/metainterp/test/test_ajit.py b/rpython/jit/metainterp/test/test_ajit.py
--- a/rpython/jit/metainterp/test/test_ajit.py
+++ b/rpython/jit/metainterp/test/test_ajit.py
@@ -4044,3 +4044,49 @@
         res = self.interp_operations(f, [17])
         assert res == 42
         self.check_operations_history(guard_true=1, guard_false=0)
+
+    def test_not_in_trace(self):
+        class X:
+            n = 0
+        def g(x):
+            if we_are_jitted():
+                raise NotImplementedError
+            x.n += 1
+        g.oopspec = 'jit.not_in_trace()'
+
+        jitdriver = JitDriver(greens=[], reds=['n', 'token', 'x'])
+        def f(n):
+            token = 0
+            x = X()
+            while n >= 0:
+                jitdriver.jit_merge_point(n=n, x=x, token=token)
+                if not we_are_jitted():
+                    token += 1
+                g(x)
+                n -= 1
+            return x.n + token * 1000
+
+        res = self.meta_interp(f, [10])
+        assert res == 2003     # two runs before jitting; then one tracing run
+        self.check_resops(int_add=0, call=0, call_may_force=0)
+
+    def test_not_in_trace_exception(self):
+        def g():
+            if we_are_jitted():
+                raise NotImplementedError
+            raise ValueError
+        g.oopspec = 'jit.not_in_trace()'
+
+        jitdriver = JitDriver(greens=[], reds=['n'])
+        def f(n):
+            while n >= 0:
+                jitdriver.jit_merge_point(n=n)
+                try:
+                    g()
+                except ValueError:
+                    n -= 1
+            return 42
+
+        res = self.meta_interp(f, [10])
+        assert res == 42
+        self.check_aborted_count(3)


More information about the pypy-commit mailing list