[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