[pypy-commit] pypy autoreds: implement @jitdriver.inline() and test that it's correctly recognized by warmspot

antocuni noreply at buildbot.pypy.org
Fri Nov 16 17:18:12 CET 2012


Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: autoreds
Changeset: r58956:010486362e23
Date: 2012-11-16 16:46 +0100
http://bitbucket.org/pypy/pypy/changeset/010486362e23/

Log:	implement @jitdriver.inline() and test that it's correctly
	recognized by warmspot

diff --git a/pypy/jit/metainterp/test/test_warmspot.py b/pypy/jit/metainterp/test/test_warmspot.py
--- a/pypy/jit/metainterp/test/test_warmspot.py
+++ b/pypy/jit/metainterp/test/test_warmspot.py
@@ -387,7 +387,7 @@
         # test that the machinery to inline jit_merge_points in callers
         # works. The final user does not need to mess manually with the
         # _inline_jit_merge_point_ attribute and similar, it is all nicely
-        # handled by @JitDriver.inline()
+        # handled by @JitDriver.inline() (see next tests)
         myjitdriver = JitDriver(greens = ['a'], reds = 'auto')
 
         def jit_merge_point(a, b):
@@ -413,8 +413,7 @@
         self.check_resops(int_add=4)
 
 
-    def test_inline_in_portal(self):
-        py.test.skip('in-progress')
+    def test_jitdriver_inline(self):
         myjitdriver = JitDriver(greens = [], reds = 'auto')
         class MyRange(object):
             def __init__(self, n):
@@ -424,35 +423,27 @@
             def __iter__(self):
                 return self
 
-            @myjitdriver.inline_in_portal
+            def jit_merge_point(self):
+                myjitdriver.jit_merge_point()
+
+            @myjitdriver.inline(jit_merge_point)
             def next(self):
-                myjitdriver.jit_merge_point()
                 if self.cur == self.n:
                     raise StopIteration
                 self.cur += 1
                 return self.cur
 
-        def one():
+        def f(n):
             res = 0
-            for i in MyRange(10):
+            for i in MyRange(n):
                 res += i
             return res
 
-        def two():
-            res = 0
-            for i in MyRange(13):
-                res += i * 2
-            return res
-
-        def f(n, m):
-            res = one() * 100
-            res += two()
-            return res
-        expected = f(21, 5)
-        res = self.meta_interp(f, [21, 5])
+        expected = f(21)
+        res = self.meta_interp(f, [21])
         assert res == expected
-        self.check_resops(int_eq=4, int_add=8)
-        self.check_trace_count(2)
+        self.check_resops(int_eq=2, int_add=4)
+        self.check_trace_count(1)
 
 
 class TestLLWarmspot(WarmspotTests, LLJitMixin):
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -6,6 +6,7 @@
 from pypy.rlib.objectmodel import CDefinedIntSymbolic, keepalive_until_here, specialize
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rpython.extregistry import ExtRegistryEntry
+from pypy.tool.sourcetools import rpython_wrapper
 
 DEBUG_ELIDABLE_FUNCTIONS = False
 
@@ -443,7 +444,7 @@
     active = True          # if set to False, this JitDriver is ignored
     virtualizables = []
     name = 'jitdriver'
-    inlined_in_portal = False
+    inline_jit_merge_point = False
 
     def __init__(self, greens=None, reds=None, virtualizables=None,
                  get_jitcell_at=None, set_jitcell_at=None,
@@ -551,12 +552,23 @@
         # 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
-        func._always_inline_ = True
-        self.inlined_in_portal = True
-        return func
+    def inline(self, call_jit_merge_point):
+        assert self.autoreds, "@inline works only with reds='auto'"
+        self.inline_jit_merge_point = True
+        def decorate(func):
+            template = """
+                def {name}({arglist}):
+                    {call_jit_merge_point}({arglist})
+                    return {original}({arglist})
+            """
+            templateargs = {'call_jit_merge_point': call_jit_merge_point.__name__}
+            globaldict = {call_jit_merge_point.__name__: call_jit_merge_point}
+            result = rpython_wrapper(func, template, templateargs, **globaldict)
+            result._inline_jit_merge_point_ = call_jit_merge_point
+            return result
+
+        return decorate
+        
 
     def clone(self):
         assert self.inline_jit_merge_point, 'JitDriver.clone works only after @inline'
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
@@ -37,17 +37,35 @@
     assert driver.reds == ['a', 'b']
     assert driver.numreds == 2
 
+def test_jitdriver_inline():
+    driver = JitDriver(greens=[], reds='auto')
+    calls = []
+    def foo(a, b):
+        calls.append(('foo', a, b))
+
+    @driver.inline(foo)
+    def bar(a, b):
+        calls.append(('bar', a, b))
+        return a+b
+
+    assert bar._inline_jit_merge_point_ is foo
+    assert driver.inline_jit_merge_point
+    assert bar(40, 2) == 42
+    assert calls == [
+        ('foo', 40, 2),
+        ('bar', 40, 2),
+        ]
+
 def test_jitdriver_clone():
-    def foo():
-        pass
+    def bar(): pass
+    def foo(): pass
     driver = JitDriver(greens=[], reds=[])
-    py.test.raises(AssertionError, "driver.inline_in_portal(foo)")
+    py.test.raises(AssertionError, "driver.inline(bar)(foo)")
     #
     driver = JitDriver(greens=[], reds='auto')
     py.test.raises(AssertionError, "driver.clone()")
-    foo = driver.inline_in_portal(foo)
-    assert foo._inline_in_portal_ == True
-    assert foo._always_inline_ == True
+    foo = driver.inline(bar)(foo)
+    assert foo._inline_jit_merge_point_ == bar
     #
     driver.foo = 'bar'
     driver2 = driver.clone()
diff --git a/pypy/tool/sourcetools.py b/pypy/tool/sourcetools.py
--- a/pypy/tool/sourcetools.py
+++ b/pypy/tool/sourcetools.py
@@ -270,19 +270,23 @@
     return "(%s:%d)%s" % (mod or '?', firstlineno, name or 'UNKNOWN')
 
 
-def rpython_wrapper(f, template, **globaldict):
+def rpython_wrapper(f, template, templateargs=None, **globaldict):
     """  
     We cannot simply wrap the function using *args, **kwds, because it's not
     RPython. Instead, we generate a function from ``template`` with exactly
     the same argument list.
     """
+    if templateargs is None:
+        templateargs = {}
     srcargs, srcvarargs, srckeywords, defaults = inspect.getargspec(f)
     assert not srcvarargs, '*args not supported by enforceargs'
     assert not srckeywords, '**kwargs not supported by enforceargs'
     #
     arglist = ', '.join(srcargs)
-    src = template.format(name=f.func_name, arglist=arglist,
-                          original=f.func_name+'_original')
+    templateargs.update(name=f.func_name,
+                        arglist=arglist,
+                        original=f.func_name+'_original')
+    src = template.format(**templateargs)
     src = py.code.Source(src)
     #
     globaldict[f.func_name + '_original'] = f


More information about the pypy-commit mailing list