Author: Antonio Cuni <[email protected]>
Branch: autoreds
Changeset: r58858:5a4708d22296
Date: 2012-11-13 20:38 +0100
http://bitbucket.org/pypy/pypy/changeset/5a4708d22296/
Log: the test to show the whole point of the excercise, i.e. the
possibility to automatically create jit portals by iterating over a
specially-decorated RPython iterator
diff --git a/pypy/jit/metainterp/test/test_ajit.py
b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -3123,7 +3123,34 @@
res = self.meta_interp(f, [32])
assert res == f(32)
-
+ def test_inline_in_portal(self):
+ myjitdriver = JitDriver(greens = [], reds = 'auto')
+ class MyRange(object):
+ def __init__(self, n):
+ self.cur = 0
+ self.n = n
+
+ def __iter__(self):
+ return self
+
+ @myjitdriver.inline_in_portal
+ def next(self):
+ myjitdriver.jit_merge_point()
+ if self.cur == self.n:
+ raise StopIteration
+ self.cur += 1
+ return self.cur
+
+ def f(n, m):
+ res = 0
+ for i in MyRange(100):
+ res += i
+ return res
+ expected = f(21, 5)
+ res = self.meta_interp(f, [21, 5])
+ assert res == expected
+ self.check_resops(int_eq=2, int_add=4)
+
class XXXDisabledTestOOtype(BasicTests, OOJitMixin):
def test_oohash(self):
diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py
--- a/pypy/jit/metainterp/warmspot.py
+++ b/pypy/jit/metainterp/warmspot.py
@@ -186,6 +186,7 @@
self.set_translator(translator)
self.memory_manager = memmgr.MemoryManager()
self.build_cpu(CPUClass, **kwds)
+ self.inline_inlineable_portals()
self.find_portals()
self.codewriter = codewriter.CodeWriter(self.cpu, self.jitdrivers_sd)
if policy is None:
@@ -241,6 +242,46 @@
self.rtyper = translator.rtyper
self.gcdescr = gc.get_description(translator.config)
+ def inline_inlineable_portals(self):
+ """
+ Find all the graphs which have been decorated with
+ @jitdriver.inline_in_portal and inline them in the callers, making
+ them JIT portals. Then, create a fresh copy of the jitdriver for each
+ of those new portals, because they cannot share the same one. See
+ test_ajit::test_inline_in_portal.
+ """
+ from pypy.translator.backendopt import inline
+ lltype_to_classdef =
self.translator.rtyper.lltype_to_classdef_mapping()
+ raise_analyzer = inline.RaiseAnalyzer(self.translator)
+ callgraph = inline.inlinable_static_callers(self.translator.graphs)
+ new_portals = set()
+ for caller, callee in callgraph:
+ func = getattr(callee, 'func', None)
+ _inline_in_portal_ = getattr(func, '_inline_in_portal_', True)
+ if _inline_in_portal_:
+ count = inline.inline_function(self.translator, callee, caller,
+ lltype_to_classdef,
raise_analyzer)
+ assert count > 0, ('The function has been decorated with '
+ '@inline_in_portal, but it is not possible '
+ 'to inline it')
+ new_portals.add(caller)
+ self.clone_inlined_jit_merge_points(new_portals)
+
+ def clone_inlined_jit_merge_points(self, graphs):
+ """
+ Find all the jit_merge_points in the given graphs, and replace the
+ original JitDriver with a fresh clone.
+ """
+ if not graphs:
+ return
+ for graph, block, pos in find_jit_merge_points(graphs):
+ op = block.operations[pos]
+ v_driver = op.args[1]
+ new_driver = v_driver.value.clone()
+ c_new_driver = Constant(new_driver, v_driver.concretetype)
+ op.args[1] = c_new_driver
+
+
def find_portals(self):
self.jitdrivers_sd = []
graphs = self.translator.graphs
@@ -294,7 +335,13 @@
jd._jit_merge_point_in = graph
args = op.args[2:]
s_binding = self.translator.annotator.binding
- jd._portal_args_s = [s_binding(v) for v in args]
+ if op.args[1].value.autoreds:
+ # _portal_args_s is used only by _make_hook_graph, but for now we
+ # declare the various set_jitcell_at, get_printable_location,
+ # etc. as incompatible with autoreds
+ jd._portal_args_s = None
+ else:
+ jd._portal_args_s = [s_binding(v) for v in args]
graph = copygraph(graph)
[jmpp] = find_jit_merge_points([graph])
graph.startblock = support.split_before_jit_merge_point(*jmpp)
@@ -546,6 +593,7 @@
if func is None:
return None
#
+ assert not jitdriver_sd.jitdriver.autoreds
extra_args_s = []
if s_first_arg is not None:
extra_args_s.append(s_first_arg)
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -443,6 +443,7 @@
active = True # if set to False, this JitDriver is ignored
virtualizables = []
name = 'jitdriver'
+ inlined_in_portal = False
def __init__(self, greens=None, reds=None, virtualizables=None,
get_jitcell_at=None, set_jitcell_at=None,
@@ -547,6 +548,18 @@
# special-cased by ExtRegistryEntry
pass
+ def inline_in_portal(self, func):
+ assert self.autoreds, "inline_in_portal works only with reds='auto'"
+ func._inline_in_portal_ = True
+ self.inlined_in_portal = True
+ return func
+
+ def clone(self):
+ assert self.inlined_in_portal, 'JitDriver.clone works only after
@inline_in_portal'
+ newdriver = object.__new__(self.__class__)
+ newdriver.__dict__ = self.__dict__.copy()
+ return newdriver
+
def _make_extregistryentries(self):
# workaround: we cannot declare ExtRegistryEntries for functions
# used as methods of a frozen object, but we can attach the
diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py
--- a/pypy/rlib/test/test_jit.py
+++ b/pypy/rlib/test/test_jit.py
@@ -23,7 +23,24 @@
py.test.raises(TypeError, "driver.can_enter_jit(foo='something')")
#
py.test.raises(AssertionError, "JitDriver(greens=['foo'], reds='auto',
confirm_enter_jit='something')")
-
+
+def test_jitdriver_clone():
+ def foo():
+ pass
+ driver = JitDriver(greens=[], reds=[])
+ py.test.raises(AssertionError, "driver.inline_in_portal(foo)")
+ #
+ driver = JitDriver(greens=[], reds='auto')
+ py.test.raises(AssertionError, "driver.clone()")
+ foo = driver.inline_in_portal(foo)
+ assert foo._inline_in_portal_ == True
+ #
+ driver.foo = 'bar'
+ driver2 = driver.clone()
+ assert driver is not driver2
+ assert driver2.foo == 'bar'
+ driver.foo = 'xxx'
+ assert driver2.foo == 'bar'
class BaseTestJIT(BaseRtypingTest):
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit