[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