[pypy-commit] pypy default: merge heads

bdkearns noreply at buildbot.pypy.org
Thu Oct 9 05:59:55 CEST 2014


Author: Brian Kearns <bdkearns at gmail.com>
Branch: 
Changeset: r73856:256a62fffbed
Date: 2014-10-08 23:59 -0400
http://bitbucket.org/pypy/pypy/changeset/256a62fffbed/

Log:	merge heads

diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -12,3 +12,6 @@
 Allocate by 4-byte chunks in rffi_platform,
 Skip testing objdump if it does not exist,
 and other small adjustments in own tests
+
+.. branch: rtyper-stuff
+Small internal refactorings in the rtyper.
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
@@ -7,6 +7,7 @@
     interpleveldefs = {
         'set_param':    'interp_jit.set_param',
         'residual_call': 'interp_jit.residual_call',
+        'not_from_assembler': 'interp_jit.W_NotFromAssembler',
         'set_compile_hook': 'interp_resop.set_compile_hook',
         'set_optimize_hook': 'interp_resop.set_optimize_hook',
         'set_abort_hook': 'interp_resop.set_abort_hook',
diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py
--- a/pypy/module/pypyjit/interp_jit.py
+++ b/pypy/module/pypyjit/interp_jit.py
@@ -12,6 +12,9 @@
 from pypy.interpreter.pycode import CO_GENERATOR
 from pypy.interpreter.pyframe import PyFrame
 from pypy.interpreter.pyopcode import ExitFrame, Yield
+from pypy.interpreter.baseobjspace import W_Root
+from pypy.interpreter.typedef import TypeDef
+from pypy.interpreter.gateway import interp2app
 from opcode import opmap
 
 
@@ -144,3 +147,40 @@
     '''For testing.  Invokes callable(...), but without letting
     the JIT follow the call.'''
     return space.call_args(w_callable, __args__)
+
+
+class W_NotFromAssembler(W_Root):
+    def __init__(self, space, w_callable):
+        self.space = space
+        self.w_callable = w_callable
+    def descr_call(self, __args__):
+        _call_not_in_trace(self.space, self.w_callable, __args__)
+        return self
+
+ at jit.not_in_trace
+def _call_not_in_trace(space, w_callable, __args__):
+    # this _call_not_in_trace() must return None
+    space.call_args(w_callable, __args__)
+
+def not_from_assembler_new(space, w_subtype, w_callable):
+    return W_NotFromAssembler(space, w_callable)
+
+W_NotFromAssembler.typedef = TypeDef("not_from_assembler",
+    __doc__ = """\
+A decorator that returns a callable that invokes the original
+callable, but not from the JIT-produced assembler.  It is called
+from the interpreted mode, and from the JIT creation (pyjitpl) or
+exiting (blackhole) steps, but just not from the final assembler.
+
+Note that the return value of the callable is ignored, because
+there is no reasonable way to guess what it sound be in case the
+function is not called.
+
+This is meant to be used notably in sys.settrace() for coverage-
+like tools.  For that purpose, if g = not_from_assembler(f), then
+'g(*args)' may call 'f(*args)' but it always return g itself.
+""",
+    __new__ = interp2app(not_from_assembler_new),
+    __call__ = interp2app(W_NotFromAssembler.descr_call),
+)
+W_NotFromAssembler.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/pypyjit/test/test_jit_not_in_trace.py b/pypy/module/pypyjit/test/test_jit_not_in_trace.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/pypyjit/test/test_jit_not_in_trace.py
@@ -0,0 +1,19 @@
+
+class AppTestJitNotInTrace(object):
+    spaceconfig = dict(usemodules=('pypyjit',))
+
+    def test_not_from_assembler(self):
+        import pypyjit
+        @pypyjit.not_from_assembler
+        def f(x, y):
+            return 42
+        r = f(3, 4)
+        assert r is f
+
+    def test_not_from_assembler_exception(self):
+        import pypyjit
+        @pypyjit.not_from_assembler
+        def f(x, y):
+            raise ValueError(y, x)
+        e = raises(ValueError, f, 3, 4)
+        assert e.value.args == (4, 3)
diff --git a/rpython/jit/codewriter/effectinfo.py b/rpython/jit/codewriter/effectinfo.py
--- a/rpython/jit/codewriter/effectinfo.py
+++ b/rpython/jit/codewriter/effectinfo.py
@@ -25,6 +25,7 @@
     OS_THREADLOCALREF_GET       = 5    # llop.threadlocalref_get
     OS_GET_ERRNO                = 6    # rposix.get_errno
     OS_SET_ERRNO                = 7    # rposix.set_errno
+    OS_NOT_IN_TRACE             = 8    # for calls not recorded in the jit trace
     #
     OS_STR_CONCAT               = 22   # "stroruni.concat"
     OS_STR_SLICE                = 23   # "stroruni.slice"
@@ -96,6 +97,7 @@
     _OS_CANRAISE = set([
         OS_NONE, OS_STR2UNICODE, OS_LIBFFI_CALL, OS_RAW_MALLOC_VARSIZE_CHAR,
         OS_JIT_FORCE_VIRTUAL, OS_SHRINK_ARRAY, OS_DICT_LOOKUP,
+        OS_NOT_IN_TRACE,
     ])
 
     def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays,
diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -1562,7 +1562,17 @@
             kind = getkind(args[0].concretetype)
             return SpaceOperation('%s_isvirtual' % kind, args, op.result)
         elif oopspec_name == 'jit.force_virtual':
-            return self._handle_oopspec_call(op, args, EffectInfo.OS_JIT_FORCE_VIRTUAL, EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE)
+            return self._handle_oopspec_call(op, args,
+                EffectInfo.OS_JIT_FORCE_VIRTUAL,
+                EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE)
+        elif oopspec_name == 'jit.not_in_trace':
+            # ignore 'args' and use the original 'op.args'
+            if op.result.concretetype is not lltype.Void:
+                raise Exception(
+                    "%r: jit.not_in_trace() function must return None"
+                    % (op.args[0],))
+            return self._handle_oopspec_call(op, op.args[1:],
+                EffectInfo.OS_NOT_IN_TRACE)
         else:
             raise AssertionError("missing support for %r" % oopspec_name)
 
diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -1393,6 +1393,9 @@
             #
             allboxes = self._build_allboxes(funcbox, argboxes, descr)
             effectinfo = descr.get_extra_info()
+            if effectinfo.oopspecindex == effectinfo.OS_NOT_IN_TRACE:
+                return self.metainterp.do_not_in_trace_call(allboxes, descr)
+
             if (assembler_call or
                     effectinfo.check_forces_virtual_or_virtualizable()):
                 # residual calls require attention to keep virtualizables in-sync
@@ -2830,6 +2833,19 @@
         if not we_are_translated():       # for llgraph
             descr._original_func_ = op.getarg(0).value
 
+    def do_not_in_trace_call(self, allboxes, descr):
+        self.clear_exception()
+        resbox = executor.execute_varargs(self.cpu, self, rop.CALL,
+                                          allboxes, descr)
+        assert resbox is None
+        if self.last_exc_value_box is not None:
+            # cannot trace this!  it raises, so we have to follow the
+            # exception-catching path, but the trace doesn't contain
+            # the call at all
+            raise SwitchToBlackhole(Counters.ABORT_ESCAPE,
+                                    raising_exception=True)
+        return None
+
 # ____________________________________________________________
 
 class ChangeFrame(jitexc.JitException):
diff --git a/rpython/jit/metainterp/test/test_ajit.py b/rpython/jit/metainterp/test/test_ajit.py
--- a/rpython/jit/metainterp/test/test_ajit.py
+++ b/rpython/jit/metainterp/test/test_ajit.py
@@ -4044,3 +4044,70 @@
         res = self.interp_operations(f, [17])
         assert res == 42
         self.check_operations_history(guard_true=1, guard_false=0)
+
+    def test_not_in_trace(self):
+        class X:
+            n = 0
+        def g(x):
+            if we_are_jitted():
+                raise NotImplementedError
+            x.n += 1
+        g.oopspec = 'jit.not_in_trace()'
+
+        jitdriver = JitDriver(greens=[], reds=['n', 'token', 'x'])
+        def f(n):
+            token = 0
+            x = X()
+            while n >= 0:
+                jitdriver.jit_merge_point(n=n, x=x, token=token)
+                if not we_are_jitted():
+                    token += 1
+                g(x)
+                n -= 1
+            return x.n + token * 1000
+
+        res = self.meta_interp(f, [10])
+        assert res == 2003     # two runs before jitting; then one tracing run
+        self.check_resops(int_add=0, call=0, call_may_force=0)
+
+    def test_not_in_trace_exception(self):
+        def g():
+            if we_are_jitted():
+                raise NotImplementedError
+            raise ValueError
+        g.oopspec = 'jit.not_in_trace()'
+
+        jitdriver = JitDriver(greens=[], reds=['n'])
+        def f(n):
+            while n >= 0:
+                jitdriver.jit_merge_point(n=n)
+                try:
+                    g()
+                except ValueError:
+                    n -= 1
+            return 42
+
+        res = self.meta_interp(f, [10])
+        assert res == 42
+        self.check_aborted_count(3)
+
+    def test_not_in_trace_blackhole(self):
+        class X:
+            seen = 0
+        def g(x):
+            if we_are_jitted():
+                raise NotImplementedError
+            x.seen = 42
+        g.oopspec = 'jit.not_in_trace()'
+
+        jitdriver = JitDriver(greens=[], reds=['n'])
+        def f(n):
+            while n >= 0:
+                jitdriver.jit_merge_point(n=n)
+                n -= 1
+            x = X()
+            g(x)
+            return x.seen
+
+        res = self.meta_interp(f, [10])
+        assert res == 42
diff --git a/rpython/rlib/_stacklet_n_a.py b/rpython/rlib/_stacklet_n_a.py
--- a/rpython/rlib/_stacklet_n_a.py
+++ b/rpython/rlib/_stacklet_n_a.py
@@ -1,33 +1,35 @@
 from rpython.rlib import _rffi_stacklet as _c
-from rpython.rlib import objectmodel, debug
+from rpython.rlib import debug
+from rpython.rlib.objectmodel import we_are_translated, specialize
 from rpython.rtyper.annlowlevel import llhelper
-from rpython.tool.staticmethods import StaticMethods
 
 
-class StackletGcRootFinder:
-    __metaclass__ = StaticMethods
-
+class StackletGcRootFinder(object):
+    @staticmethod
+    @specialize.arg(1)
     def new(thrd, callback, arg):
         h = _c.new(thrd._thrd, llhelper(_c.run_fn, callback), arg)
         if not h:
             raise MemoryError
         return h
-    new._annspecialcase_ = 'specialize:arg(1)'
 
+    @staticmethod
     def switch(h):
         h = _c.switch(h)
         if not h:
             raise MemoryError
         return h
 
+    @staticmethod
     def destroy(thrd, h):
         _c.destroy(thrd._thrd, h)
-        if objectmodel.we_are_translated():
+        if we_are_translated():
             debug.debug_print("not using a framework GC: "
                               "stacklet_destroy() may leak")
 
-    is_empty_handle = _c.is_empty_handle
+    is_empty_handle = staticmethod(_c.is_empty_handle)
 
+    @staticmethod
     def get_null_handle():
         return _c.null_handle
 
diff --git a/rpython/rlib/_stacklet_shadowstack.py b/rpython/rlib/_stacklet_shadowstack.py
--- a/rpython/rlib/_stacklet_shadowstack.py
+++ b/rpython/rlib/_stacklet_shadowstack.py
@@ -3,7 +3,6 @@
 from rpython.rtyper.annlowlevel import llhelper
 from rpython.rtyper.lltypesystem import lltype, llmemory
 from rpython.rtyper.lltypesystem.lloperation import llop
-from rpython.tool.staticmethods import StaticMethods
 
 
 NULL_SUSPSTACK = lltype.nullptr(llmemory.GCREF.TO)
@@ -68,9 +67,7 @@
     return oldsuspstack
 
 
-class StackletGcRootFinder:
-    __metaclass__ = StaticMethods
-
+class StackletGcRootFinder(object):
     def new(thrd, callback, arg):
         gcrootfinder.callback = callback
         thread_handle = thrd._thrd
@@ -78,6 +75,7 @@
         h = _c.new(thread_handle, llhelper(_c.run_fn, _new_callback), arg)
         return get_result_suspstack(h)
     new._dont_inline_ = True
+    new = staticmethod(new)
 
     def switch(suspstack):
         # suspstack has a handle to target, i.e. where to switch to
@@ -90,10 +88,13 @@
         h = _c.switch(h)
         return get_result_suspstack(h)
     switch._dont_inline_ = True
+    switch = staticmethod(switch)
 
+    @staticmethod
     def is_empty_handle(suspstack):
         return not suspstack
 
+    @staticmethod
     def get_null_handle():
         return NULL_SUSPSTACK
 
diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py
--- a/rpython/rlib/jit.py
+++ b/rpython/rlib/jit.py
@@ -194,6 +194,14 @@
         return func
     return decorator
 
+def not_in_trace(func):
+    """A decorator for a function with no return value.  It makes the
+    function call disappear from the jit traces. It is still called in
+    interpreted mode, and by the jit tracing and blackholing, but not
+    by the final assembler."""
+    func.oopspec = "jit.not_in_trace()"   # note that 'func' may take arguments
+    return func
+
 @oopspec("jit.isconstant(value)")
 def isconstant(value):
     """
diff --git a/rpython/rtyper/lltypesystem/lltype.py b/rpython/rtyper/lltypesystem/lltype.py
--- a/rpython/rtyper/lltypesystem/lltype.py
+++ b/rpython/rtyper/lltypesystem/lltype.py
@@ -191,6 +191,11 @@
     def _is_varsize(self):
         return False
 
+    def _contains_value(self, value):
+        if self is Void:
+            return True
+        return isCompatibleType(typeOf(value), self)
+
 NFOUND = object()
 
 class ContainerType(LowLevelType):
diff --git a/rpython/rtyper/lltypesystem/rbytearray.py b/rpython/rtyper/lltypesystem/rbytearray.py
--- a/rpython/rtyper/lltypesystem/rbytearray.py
+++ b/rpython/rtyper/lltypesystem/rbytearray.py
@@ -38,12 +38,14 @@
             i += s.length()
         cls.ll_strsetitem_nonneg(s, i, item)
 
+    @staticmethod
     def ll_strsetitem_nonneg(s, i, item):
         chars = s.chars
         ll_assert(i >= 0, "negative str getitem index")
         ll_assert(i < len(chars), "str getitem index out of bound")
         chars[i] = chr(item)
 
+    @staticmethod
     def ll_stritem_nonneg(s, i):
         return ord(rstr.LLHelpers.ll_stritem_nonneg(s, i))
 
diff --git a/rpython/rtyper/lltypesystem/rstr.py b/rpython/rtyper/lltypesystem/rstr.py
--- a/rpython/rtyper/lltypesystem/rstr.py
+++ b/rpython/rtyper/lltypesystem/rstr.py
@@ -270,6 +270,7 @@
 class LLHelpers(AbstractLLHelpers):
     from rpython.rtyper.annlowlevel import llstr, llunicode
 
+    @staticmethod
     @jit.elidable
     def ll_str_mul(s, times):
         if times < 0:
@@ -292,6 +293,7 @@
             i += j
         return newstr
 
+    @staticmethod
     @jit.elidable
     def ll_char_mul(ch, times):
         if typeOf(ch) is Char:
@@ -308,9 +310,11 @@
             j += 1
         return newstr
 
+    @staticmethod
     def ll_strlen(s):
         return len(s.chars)
 
+    @staticmethod
     @signature(types.any(), types.int(), returns=types.any())
     def ll_stritem_nonneg(s, i):
         chars = s.chars
@@ -318,6 +322,7 @@
         ll_assert(i < len(chars), "str getitem index out of bound")
         return chars[i]
 
+    @staticmethod
     def ll_chr2str(ch):
         if typeOf(ch) is Char:
             malloc = mallocstr
@@ -328,6 +333,7 @@
         return s
 
     # @jit.look_inside_iff(lambda str: jit.isconstant(len(str.chars)) and len(str.chars) == 1)
+    @staticmethod
     @jit.oopspec("str.str2unicode(str)")
     def ll_str2unicode(str):
         lgt = len(str.chars)
@@ -338,6 +344,7 @@
             s.chars[i] = cast_primitive(UniChar, str.chars[i])
         return s
 
+    @staticmethod
     def ll_str2bytearray(str):
         from rpython.rtyper.lltypesystem.rbytearray import BYTEARRAY
 
@@ -347,6 +354,7 @@
             b.chars[i] = str.chars[i]
         return b
 
+    @staticmethod
     @jit.elidable
     def ll_strhash(s):
         # unlike CPython, there is no reason to avoid to return -1
@@ -362,13 +370,17 @@
             s.hash = x
         return x
 
+    @staticmethod
     def ll_length(s):
         return len(s.chars)
 
+    @staticmethod
     def ll_strfasthash(s):
         return s.hash     # assumes that the hash is already computed
 
+    @staticmethod
     @jit.elidable
+    @jit.oopspec('stroruni.concat(s1, s2)')
     def ll_strconcat(s1, s2):
         len1 = s1.length()
         len2 = s2.length()
@@ -386,8 +398,8 @@
         else:
             newstr.copy_contents(s2, newstr, 0, len1, len2)
         return newstr
-    ll_strconcat.oopspec = 'stroruni.concat(s1, s2)'
 
+    @staticmethod
     @jit.elidable
     def ll_strip(s, ch, left, right):
         s_len = len(s.chars)
@@ -408,6 +420,7 @@
         s.copy_contents(s, result, lpos, 0, r_len)
         return result
 
+    @staticmethod
     @jit.elidable
     def ll_strip_default(s, left, right):
         s_len = len(s.chars)
@@ -428,6 +441,7 @@
         s.copy_contents(s, result, lpos, 0, r_len)
         return result
 
+    @staticmethod
     @jit.elidable
     def ll_strip_multiple(s, s2, left, right):
         s_len = len(s.chars)
@@ -448,6 +462,7 @@
         s.copy_contents(s, result, lpos, 0, r_len)
         return result
 
+    @staticmethod
     @jit.elidable
     def ll_upper(s):
         s_chars = s.chars
@@ -462,6 +477,7 @@
             i += 1
         return result
 
+    @staticmethod
     @jit.elidable
     def ll_lower(s):
         s_chars = s.chars
@@ -476,6 +492,7 @@
             i += 1
         return result
 
+    @staticmethod
     def ll_join(s, length, items):
         s_chars = s.chars
         s_len = len(s_chars)
@@ -509,7 +526,9 @@
             i += 1
         return result
 
+    @staticmethod
     @jit.elidable
+    @jit.oopspec('stroruni.cmp(s1, s2)')
     def ll_strcmp(s1, s2):
         if not s1 and not s2:
             return True
@@ -531,9 +550,10 @@
                 return diff
             i += 1
         return len1 - len2
-    ll_strcmp.oopspec = 'stroruni.cmp(s1, s2)'
 
+    @staticmethod
     @jit.elidable
+    @jit.oopspec('stroruni.equal(s1, s2)')
     def ll_streq(s1, s2):
         if s1 == s2:       # also if both are NULLs
             return True
@@ -551,8 +571,8 @@
                 return False
             j += 1
         return True
-    ll_streq.oopspec = 'stroruni.equal(s1, s2)'
 
+    @staticmethod
     @jit.elidable
     def ll_startswith(s1, s2):
         len1 = len(s1.chars)
@@ -569,11 +589,13 @@
 
         return True
 
+    @staticmethod
     def ll_startswith_char(s, ch):
         if not len(s.chars):
             return False
         return s.chars[0] == ch
 
+    @staticmethod
     @jit.elidable
     def ll_endswith(s1, s2):
         len1 = len(s1.chars)
@@ -591,11 +613,13 @@
 
         return True
 
+    @staticmethod
     def ll_endswith_char(s, ch):
         if not len(s.chars):
             return False
         return s.chars[len(s.chars) - 1] == ch
 
+    @staticmethod
     @jit.elidable
     @signature(types.any(), types.any(), types.int(), types.int(), returns=types.int())
     def ll_find_char(s, ch, start, end):
@@ -608,6 +632,7 @@
             i += 1
         return -1
 
+    @staticmethod
     @jit.elidable
     def ll_rfind_char(s, ch, start, end):
         if end > len(s.chars):
@@ -619,6 +644,7 @@
                 return i
         return -1
 
+    @staticmethod
     @jit.elidable
     def ll_count_char(s, ch, start, end):
         count = 0
@@ -631,6 +657,7 @@
             i += 1
         return count
 
+    @staticmethod
     @signature(types.any(), types.any(), types.int(), types.int(), returns=types.int())
     def ll_find(s1, s2, start, end):
         if start < 0:
@@ -646,6 +673,7 @@
 
         return LLHelpers.ll_search(s1, s2, start, end, FAST_FIND)
 
+    @staticmethod
     @signature(types.any(), types.any(), types.int(), types.int(), returns=types.int())
     def ll_rfind(s1, s2, start, end):
         if start < 0:
@@ -681,6 +709,7 @@
             res = 0
         return res
 
+    @staticmethod
     @jit.elidable
     def ll_search(s1, s2, start, end, mode):
         count = 0
@@ -768,6 +797,7 @@
             return -1
         return count
 
+    @staticmethod
     @signature(types.int(), types.any(), returns=types.any())
     @jit.look_inside_iff(lambda length, items: jit.loop_unrolling_heuristic(
         items, length))
@@ -802,6 +832,7 @@
             i += 1
         return result
 
+    @staticmethod
     @jit.look_inside_iff(lambda length, chars, RES: jit.isconstant(length) and jit.isvirtual(chars))
     def ll_join_chars(length, chars, RES):
         # no need to optimize this, will be replaced by string builder
@@ -821,6 +852,7 @@
             i += 1
         return result
 
+    @staticmethod
     @jit.oopspec('stroruni.slice(s1, start, stop)')
     @signature(types.any(), types.int(), types.int(), returns=types.any())
     @jit.elidable
@@ -836,9 +868,11 @@
         s1.copy_contents(s1, newstr, start, 0, lgt)
         return newstr
 
+    @staticmethod
     def ll_stringslice_startonly(s1, start):
         return LLHelpers._ll_stringslice(s1, start, len(s1.chars))
 
+    @staticmethod
     @signature(types.any(), types.int(), types.int(), returns=types.any())
     def ll_stringslice_startstop(s1, start, stop):
         if jit.we_are_jitted():
@@ -851,10 +885,12 @@
                 stop = len(s1.chars)
         return LLHelpers._ll_stringslice(s1, start, stop)
 
+    @staticmethod
     def ll_stringslice_minusone(s1):
         newlen = len(s1.chars) - 1
         return LLHelpers._ll_stringslice(s1, 0, newlen)
 
+    @staticmethod
     def ll_split_chr(LIST, s, c, max):
         chars = s.chars
         strlen = len(chars)
@@ -889,6 +925,7 @@
         item.copy_contents(s, item, i, 0, j - i)
         return res
 
+    @staticmethod
     def ll_split(LIST, s, c, max):
         count = 1
         if max == -1:
@@ -920,6 +957,7 @@
         item.copy_contents(s, item, prev_pos, 0, last - prev_pos)
         return res
 
+    @staticmethod
     def ll_rsplit_chr(LIST, s, c, max):
         chars = s.chars
         strlen = len(chars)
@@ -955,6 +993,7 @@
         item.copy_contents(s, item, j, 0, i - j)
         return res
 
+    @staticmethod
     def ll_rsplit(LIST, s, c, max):
         count = 1
         if max == -1:
@@ -986,6 +1025,7 @@
         item.copy_contents(s, item, 0, 0, prev_pos)
         return res
 
+    @staticmethod
     @jit.elidable
     def ll_replace_chr_chr(s, c1, c2):
         length = len(s.chars)
@@ -1001,6 +1041,7 @@
             j += 1
         return newstr
 
+    @staticmethod
     @jit.elidable
     def ll_contains(s, c):
         chars = s.chars
@@ -1012,6 +1053,7 @@
             i += 1
         return False
 
+    @staticmethod
     @jit.elidable
     def ll_int(s, base):
         if not 2 <= base <= 36:
@@ -1068,23 +1110,29 @@
     #   ll_build_push(x, next_string, n-1)
     #   s = ll_build_finish(x)
 
+    @staticmethod
     def ll_build_start(parts_count):
         return malloc(TEMP, parts_count)
 
+    @staticmethod
     def ll_build_push(builder, next_string, index):
         builder[index] = next_string
 
+    @staticmethod
     def ll_build_finish(builder):
         return LLHelpers.ll_join_strs(len(builder), builder)
 
+    @staticmethod
     @specialize.memo()
     def ll_constant(s):
         return string_repr.convert_const(s)
 
+    @staticmethod
     @specialize.memo()
     def ll_constant_unicode(s):
         return unicode_repr.convert_const(s)
 
+    @classmethod
     def do_stringformat(cls, hop, sourcevarsrepr):
         s_str = hop.args_s[0]
         assert s_str.is_constant()
@@ -1150,8 +1198,8 @@
 
         hop.exception_cannot_occur()   # to ignore the ZeroDivisionError of '%'
         return hop.gendirectcall(cls.ll_join_strs, size, vtemp)
-    do_stringformat = classmethod(do_stringformat)
 
+    @staticmethod
     @jit.dont_look_inside
     def ll_string2list(RESLIST, src):
         length = len(src.chars)
diff --git a/rpython/rtyper/rmodel.py b/rpython/rtyper/rmodel.py
--- a/rpython/rtyper/rmodel.py
+++ b/rpython/rtyper/rmodel.py
@@ -2,8 +2,7 @@
 from rpython.flowspace.model import Constant
 from rpython.rtyper.error import TyperError, MissingRTypeOperation
 from rpython.rtyper.lltypesystem import lltype
-from rpython.rtyper.lltypesystem.lltype import (Void, Bool, typeOf,
-    LowLevelType, isCompatibleType)
+from rpython.rtyper.lltypesystem.lltype import Void, Bool, LowLevelType
 from rpython.tool.pairtype import pairtype, extendabletype, pair
 
 
@@ -120,14 +119,9 @@
 
     def convert_const(self, value):
         "Convert the given constant value to the low-level repr of 'self'."
-        if self.lowleveltype is not Void:
-            try:
-                realtype = typeOf(value)
-            except (AssertionError, AttributeError, TypeError):
-                realtype = '???'
-            if realtype != self.lowleveltype:
-                raise TyperError("convert_const(self = %r, value = %r)" % (
-                    self, value))
+        if not self.lowleveltype._contains_value(value):
+            raise TyperError("convert_const(self = %r, value = %r)" % (
+                self, value))
         return value
 
     def get_ll_eq_function(self):
@@ -356,18 +350,9 @@
         lltype = reqtype
     else:
         raise TypeError(repr(reqtype))
-    # Void Constants can hold any value;
-    # non-Void Constants must hold a correctly ll-typed value
-    if lltype is not Void:
-        try:
-            realtype = typeOf(value)
-        except (AssertionError, AttributeError):
-            realtype = '???'
-        if not isCompatibleType(realtype, lltype):
-            raise TyperError("inputconst(reqtype = %s, value = %s):\n"
-                             "expected a %r,\n"
-                             "     got a %r" % (reqtype, value,
-                                                lltype, realtype))
+    if not lltype._contains_value(value):
+        raise TyperError("inputconst(): expected a %r, got %r" %
+                         (lltype, value))
     c = Constant(value)
     c.concretetype = lltype
     return c
@@ -422,7 +407,8 @@
     def __ne__(self, other):
         return not (self == other)
 
-    def build_ll_dummy_value(self):
+    @property
+    def ll_dummy_value(self):
         TYPE = self.TYPE
         try:
             return self.rtyper.cache_dummy_values[TYPE]
@@ -435,8 +421,6 @@
             self.rtyper.cache_dummy_values[TYPE] = p
             return p
 
-    ll_dummy_value = property(build_ll_dummy_value)
-
 
 # logging/warning
 
diff --git a/rpython/rtyper/rstr.py b/rpython/rtyper/rstr.py
--- a/rpython/rtyper/rstr.py
+++ b/rpython/rtyper/rstr.py
@@ -9,7 +9,6 @@
 from rpython.rtyper.rfloat import FloatRepr
 from rpython.tool.pairtype import pairtype, pair
 from rpython.tool.sourcetools import func_with_new_name
-from rpython.tool.staticmethods import StaticMethods
 from rpython.rlib.rstring import UnicodeBuilder
 
 
@@ -800,10 +799,8 @@
 #  get flowed and annotated, mostly with SomePtr.
 #
 
-# this class contains low level helpers used both by lltypesystem
-class AbstractLLHelpers:
-    __metaclass__ = StaticMethods
-
+class AbstractLLHelpers(object):
+    @staticmethod
     def ll_isdigit(s):
         from rpython.rtyper.annlowlevel import hlstr
 
@@ -815,6 +812,7 @@
                 return False
         return True
 
+    @staticmethod
     def ll_isalpha(s):
         from rpython.rtyper.annlowlevel import hlstr
 
@@ -826,6 +824,7 @@
                 return False
         return True
 
+    @staticmethod
     def ll_isalnum(s):
         from rpython.rtyper.annlowlevel import hlstr
 
@@ -837,14 +836,17 @@
                 return False
         return True
 
+    @staticmethod
     def ll_char_isspace(ch):
         c = ord(ch)
         return c == 32 or (9 <= c <= 13)   # c in (9, 10, 11, 12, 13, 32)
 
+    @staticmethod
     def ll_char_isdigit(ch):
         c = ord(ch)
         return c <= 57 and c >= 48
 
+    @staticmethod
     def ll_char_isalpha(ch):
         c = ord(ch)
         if c >= 97:
@@ -852,6 +854,7 @@
         else:
             return 65 <= c <= 90
 
+    @staticmethod
     def ll_char_isalnum(ch):
         c = ord(ch)
         if c >= 65:
@@ -862,47 +865,54 @@
         else:
             return 48 <= c <= 57
 
+    @staticmethod
     def ll_char_isupper(ch):
         c = ord(ch)
         return 65 <= c <= 90
 
+    @staticmethod
     def ll_char_islower(ch):
         c = ord(ch)
         return 97 <= c <= 122
 
+    @staticmethod
     def ll_upper_char(ch):
         if 'a' <= ch <= 'z':
             ch = chr(ord(ch) - 32)
         return ch
 
+    @staticmethod
     def ll_lower_char(ch):
         if 'A' <= ch <= 'Z':
             ch = chr(ord(ch) + 32)
         return ch
 
+    @staticmethod
     def ll_char_hash(ch):
         return ord(ch)
 
+    @staticmethod
     def ll_unichar_hash(ch):
         return ord(ch)
 
+    @classmethod
     def ll_str_is_true(cls, s):
         # check if a string is True, allowing for None
         return bool(s) and cls.ll_strlen(s) != 0
-    ll_str_is_true = classmethod(ll_str_is_true)
 
+    @classmethod
     def ll_stritem_nonneg_checked(cls, s, i):
         if i >= cls.ll_strlen(s):
             raise IndexError
         return cls.ll_stritem_nonneg(s, i)
-    ll_stritem_nonneg_checked = classmethod(ll_stritem_nonneg_checked)
 
+    @classmethod
     def ll_stritem(cls, s, i):
         if i < 0:
             i += cls.ll_strlen(s)
         return cls.ll_stritem_nonneg(s, i)
-    ll_stritem = classmethod(ll_stritem)
 
+    @classmethod
     def ll_stritem_checked(cls, s, i):
         length = cls.ll_strlen(s)
         if i < 0:
@@ -910,8 +920,8 @@
         if i >= length or i < 0:
             raise IndexError
         return cls.ll_stritem_nonneg(s, i)
-    ll_stritem_checked = classmethod(ll_stritem_checked)
 
+    @staticmethod
     def parse_fmt_string(fmt):
         # we support x, d, s, f, [r]
         it = iter(fmt)
@@ -937,6 +947,7 @@
             r.append(curstr)
         return r
 
+    @staticmethod
     def ll_float(ll_str):
         from rpython.rtyper.annlowlevel import hlstr
         from rpython.rlib.rfloat import rstring_to_float
@@ -961,6 +972,7 @@
         assert end >= 0
         return rstring_to_float(s[beg:end + 1])
 
+    @classmethod
     def ll_splitlines(cls, LIST, ll_str, keep_newlines):
         from rpython.rtyper.annlowlevel import hlstr
         s = hlstr(ll_str)
@@ -991,4 +1003,3 @@
             item = cls.ll_stringslice_startstop(ll_str, j, strlen)
             res.ll_setitem_fast(list_length, item)
         return res
-    ll_splitlines = classmethod(ll_splitlines)
diff --git a/rpython/tool/staticmethods.py b/rpython/tool/staticmethods.py
deleted file mode 100644
--- a/rpython/tool/staticmethods.py
+++ /dev/null
@@ -1,14 +0,0 @@
-import types
-class AbstractMethods(type):
-    def __new__(cls, cls_name, bases, cls_dict):
-        for key, value in cls_dict.iteritems():
-            if isinstance(value, types.FunctionType):
-                cls_dict[key] = cls.decorator(value)
-        return type.__new__(cls, cls_name, bases, cls_dict)
-
-
-class StaticMethods(AbstractMethods):
-    """
-    Metaclass that turns plain methods into staticmethods.
-    """
-    decorator = staticmethod


More information about the pypy-commit mailing list