[pypy-commit] pypy better-jit-hooks: update and improve the hooks

fijal noreply at buildbot.pypy.org
Sun Jan 8 19:19:30 CET 2012


Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: better-jit-hooks
Changeset: r51137:5ed435c1abb6
Date: 2012-01-08 20:18 +0200
http://bitbucket.org/pypy/pypy/changeset/5ed435c1abb6/

Log:	update and improve the hooks

diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py
--- a/pypy/module/pypyjit/__init__.py
+++ b/pypy/module/pypyjit/__init__.py
@@ -8,6 +8,7 @@
         'set_param':    'interp_jit.set_param',
         'residual_call': 'interp_jit.residual_call',
         'set_compile_hook': 'interp_resop.set_compile_hook',
+        'set_optimize_hook': 'interp_resop.set_optimize_hook',
         'set_abort_hook': 'interp_resop.set_abort_hook',
         'ResOperation': 'interp_resop.WrappedOp',
     }
diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py
--- a/pypy/module/pypyjit/interp_resop.py
+++ b/pypy/module/pypyjit/interp_resop.py
@@ -61,6 +61,37 @@
     cache.in_recursion = NonConstant(False)
     return space.w_None
 
+def set_optimize_hook(space, w_hook):
+    """ set_compile_hook(hook)
+
+    Set a compiling hook that will be called each time a loop is optimized,
+    but before assembler compilation. This allows to add additional
+    optimizations on Python level.
+    
+    The hook will be called with the following signature:
+    hook(jitdriver_name, loop_type, greenkey or guard_number, operations)
+
+    jitdriver_name is the name of this particular jitdriver, 'pypyjit' is
+    the main interpreter loop
+
+    loop_type can be either `loop` `entry_bridge` or `bridge`
+    in case loop is not `bridge`, greenkey will be a tuple of constants
+    or a string describing it.
+
+    for the interpreter loop` it'll be a tuple
+    (code, offset, is_being_profiled)
+
+    Note that jit hook is not reentrant. It means that if the code
+    inside the jit hook is itself jitted, it will get compiled, but the
+    jit hook won't be called for that.
+
+    Result value will be the resulting list of operations, or None
+    """
+    cache = space.fromcache(Cache)
+    cache.w_optimize_hook = w_hook
+    cache.in_recursion = NonConstant(False)
+    return space.w_None
+
 def set_abort_hook(space, w_hook):
     """ set_abort_hook(hook)
 
diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py
--- a/pypy/module/pypyjit/policy.py
+++ b/pypy/module/pypyjit/policy.py
@@ -1,8 +1,10 @@
 from pypy.jit.codewriter.policy import JitPolicy
 from pypy.rlib.jit import JitPortal
+from pypy.rlib import jit_hooks
 from pypy.interpreter.error import OperationError
 from pypy.jit.metainterp.jitprof import counter_names
-from pypy.module.pypyjit.interp_resop import wrap_oplist, Cache, wrap_greenkey
+from pypy.module.pypyjit.interp_resop import wrap_oplist, Cache, wrap_greenkey,\
+     WrappedOp
 
 class PyPyPortal(JitPortal):
     def on_abort(self, reason, jitdriver, greenkey):
@@ -21,18 +23,28 @@
                 e.write_unraisable(space, "jit hook ", cache.w_abort_hook)
             cache.in_recursion = False
 
-    def on_compile(self, jitdriver, logger, looptoken, operations, type,
-                   greenkey, ops_offset, asmstart, asmlen):
+    def after_compile(self, jitdriver, logger, looptoken, operations, type,
+                      greenkey, ops_offset, asmstart, asmlen):
         self._compile_hook(jitdriver, logger, operations, type,
                            ops_offset, asmstart, asmlen,
                            wrap_greenkey(self.space, jitdriver, greenkey))
 
-    def on_compile_bridge(self, jitdriver, logger, orig_looptoken, operations,
-                          n, ops_offset, asmstart, asmlen):
+    def after_compile_bridge(self, jitdriver, logger, orig_looptoken,
+                             operations, n, ops_offset, asmstart, asmlen):
         self._compile_hook(jitdriver, logger, operations, 'bridge',
                            ops_offset, asmstart, asmlen,
                            self.space.wrap(n))
 
+    def before_compile(self, jitdriver, logger, looptoken, operations, type,
+                      greenkey):
+        self._optimize_hook(jitdriver, logger, operations, type,
+                            wrap_greenkey(self.space, jitdriver, greenkey))
+
+    def before_compile_bridge(self, jitdriver, logger, orig_looptoken,
+                              operations, n):
+        self._optimize_hook(jitdriver, logger, operations, 'bridge',
+                           self.space.wrap(n))
+
     def _compile_hook(self, jitdriver, logger, operations, type,
                       ops_offset, asmstart, asmlen, w_arg):
         space = self.space
@@ -55,6 +67,34 @@
                 e.write_unraisable(space, "jit hook ", cache.w_compile_hook)
             cache.in_recursion = False
 
+    def _optimize_hook(self, jitdriver, logger, operations, type, w_arg):
+        space = self.space
+        cache = space.fromcache(Cache)
+        if cache.in_recursion:
+            return
+        if space.is_true(cache.w_optimize_hook):
+            logops = logger._make_log_operations()
+            list_w = wrap_oplist(space, logops, operations, {})
+            cache.in_recursion = True
+            try:
+                w_res = space.call_function(cache.w_optimize_hook,
+                                            space.wrap(jitdriver.name),
+                                            space.wrap(type),
+                                            w_arg,
+                                            space.newlist(list_w))
+                if space.is_w(w_res, space.w_None):
+                    return
+                l = []
+                for w_item in space.listview(w_res):
+                    item = space.interp_w(WrappedOp, w_item)
+                    l.append(jit_hooks._cast_to_resop(item.op))
+                operations[:] = l # modifying operations above is probably not
+                # a great idea since types may not work and we'll end up with
+                # half-working list and a segfault/fatal RPython error
+            except OperationError, e:
+                e.write_unraisable(space, "jit hook ", cache.w_compile_hook)
+            cache.in_recursion = False
+
 pypy_portal = PyPyPortal()
 
 class PyPyJitPolicy(JitPolicy):
diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py
--- a/pypy/module/pypyjit/test/test_jit_hook.py
+++ b/pypy/module/pypyjit/test/test_jit_hook.py
@@ -47,7 +47,7 @@
         code_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, ll_code)
         logger = Logger(MockSD())
 
-        oplist = parse("""
+        cls.origoplist = parse("""
         [i1, i2]
         i3 = int_add(i1, i2)
         debug_merge_point(0, 0, 0, 0, ConstPtr(ptr0))
@@ -55,19 +55,23 @@
         """, namespace={'ptr0': code_gcref}).operations
         greenkey = [ConstInt(0), ConstInt(0), ConstPtr(code_gcref)]
         offset = {}
-        for i, op in enumerate(oplist):
+        for i, op in enumerate(cls.origoplist):
             if i != 1:
                offset[op] = i
 
         def interp_on_compile():
-            pypy_portal.on_compile(pypyjitdriver, logger, JitCellToken(),
-                                   oplist, 'loop', greenkey, offset,
-                                   0, 0)
+            pypy_portal.after_compile(pypyjitdriver, logger, JitCellToken(),
+                                      cls.oplist, 'loop', greenkey, offset,
+                                      0, 0)
 
         def interp_on_compile_bridge():
-            pypy_portal.on_compile_bridge(pypyjitdriver, logger,
-                                          JitCellToken(), oplist, 0,
-                                          offset, 0, 0)
+            pypy_portal.after_compile_bridge(pypyjitdriver, logger,
+                                             JitCellToken(), cls.oplist, 0,
+                                             offset, 0, 0)
+
+        def interp_on_optimize():
+            pypy_portal.before_compile(pypyjitdriver, logger, JitCellToken(),
+                                       cls.oplist, 'loop', greenkey)
 
         def interp_on_abort():
             pypy_portal.on_abort(ABORT_TOO_LONG, pypyjitdriver, greenkey)
@@ -76,6 +80,10 @@
         cls.w_on_compile_bridge = space.wrap(interp2app(interp_on_compile_bridge))
         cls.w_on_abort = space.wrap(interp2app(interp_on_abort))
         cls.w_int_add_num = space.wrap(rop.INT_ADD)
+        cls.w_on_optimize = space.wrap(interp2app(interp_on_optimize))
+
+    def setup_method(self, meth):
+        self.__class__.oplist = self.origoplist
 
     def test_on_compile(self):
         import pypyjit
@@ -160,6 +168,22 @@
         self.on_abort()
         assert l == [('pypyjit', 'ABORT_TOO_LONG')]
 
+    def test_on_optimize(self):
+        import pypyjit
+        l = []
+
+        def hook(name, looptype, tuple_or_guard_no, ops, *args):
+            l.append(ops)
+
+        def optimize_hook(name, looptype, tuple_or_guard_no, ops):
+            return []
+
+        pypyjit.set_compile_hook(hook)
+        pypyjit.set_optimize_hook(optimize_hook)
+        self.on_optimize()
+        self.on_compile()
+        assert l == [[]]
+
     def test_creation(self):
         import pypyjit
 


More information about the pypy-commit mailing list