Author: Armin Rigo <[email protected]>
Branch: portable-threadlocal
Changeset: r74721:ac12cf96b219
Date: 2014-11-26 00:01 +0100
http://bitbucket.org/pypy/pypy/changeset/ac12cf96b219/

Log:    hg merge default

diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -131,7 +131,6 @@
         # class bodies only have CO_NEWLOCALS.
         # CO_NEWLOCALS: make a locals dict unless optimized is also set
         # CO_OPTIMIZED: no locals dict needed at all
-        # NB: this method is overridden in nestedscope.py
         flags = code.co_flags
         if not (flags & pycode.CO_OPTIMIZED):
             if flags & pycode.CO_NEWLOCALS:
diff --git a/pypy/module/pypyjit/test_pypy_c/model.py 
b/pypy/module/pypyjit/test_pypy_c/model.py
--- a/pypy/module/pypyjit/test_pypy_c/model.py
+++ b/pypy/module/pypyjit/test_pypy_c/model.py
@@ -275,9 +275,19 @@
 
     @classmethod
     def parse_op(cls, line):
-        # strip comment
+        # strip comment after '#', but not if it appears inside parentheses
         if '#' in line:
-            line = line[:line.index('#')]
+            nested = 0
+            for i, c in enumerate(line):
+                if c == '(':
+                    nested += 1
+                elif c == ')':
+                    assert nested > 0, "more ')' than '(' in %r" % (line,)
+                    nested -= 1
+                elif c == '#' and nested == 0:
+                    line = line[:i]
+                    break
+        #
         if line.strip() == 'guard_not_invalidated?':
             return 'guard_not_invalidated', None, [], '...', False
         # find the resvar, if any
@@ -314,7 +324,7 @@
         # to repeat it every time
         ticker_check = """
             guard_not_invalidated?
-            ticker0 = getfield_raw(ticker_address, descr=<FieldS 
pypysig_long_struct.c_value .*>)
+            ticker0 = getfield_raw(#, descr=<FieldS 
pypysig_long_struct.c_value .*>)
             ticker_cond0 = int_lt(ticker0, 0)
             guard_false(ticker_cond0, descr=...)
         """
@@ -323,9 +333,9 @@
         # this is the ticker check generated if we have threads
         thread_ticker_check = """
             guard_not_invalidated?
-            ticker0 = getfield_raw(ticker_address, descr=<FieldS 
pypysig_long_struct.c_value .*>)
-            ticker1 = int_sub(ticker0, _)
-            setfield_raw(ticker_address, ticker1, descr=<FieldS 
pypysig_long_struct.c_value .*>)
+            ticker0 = getfield_raw(#, descr=<FieldS 
pypysig_long_struct.c_value .*>)
+            ticker1 = int_sub(ticker0, #)
+            setfield_raw(#, ticker1, descr=<FieldS pypysig_long_struct.c_value 
.*>)
             ticker_cond0 = int_lt(ticker1, 0)
             guard_false(ticker_cond0, descr=...)
         """
@@ -333,7 +343,7 @@
         #
         # this is the ticker check generated in PyFrame.handle_operation_error
         exc_ticker_check = """
-            ticker2 = getfield_raw(ticker_address, descr=<FieldS 
pypysig_long_struct.c_value .*>)
+            ticker2 = getfield_raw(#, descr=<FieldS 
pypysig_long_struct.c_value .*>)
             ticker_cond1 = int_lt(ticker2, 0)
             guard_false(ticker_cond1, descr=...)
         """
@@ -351,18 +361,31 @@
 
     @staticmethod
     def as_numeric_const(v1):
+        # returns one of:  ('int', value)  ('float', value)  None
         try:
-            return int(v1)
-        except (ValueError, TypeError):
-            return None
+            return ('int', int(v1))
+        except ValueError:
+            pass
+        if '.' in v1:
+            try:
+                return ('float', float(v1))
+            except ValueError:
+                pass
+        return None
 
     def match_var(self, v1, exp_v2):
         assert v1 != '_'
-        if exp_v2 == '_':
+        if exp_v2 == '_':           # accept anything
             return True
+        if exp_v2 is None:
+            return v1 is None
+        assert exp_v2 != '...'      # bogus use of '...' in the expected code
         n1 = self.as_numeric_const(v1)
+        if exp_v2 == '#':           # accept any (integer or float) number
+            return n1 is not None
         n2 = self.as_numeric_const(exp_v2)
-        if n1 is not None and n2 is not None:
+        if n1 is not None or n2 is not None:
+            # at least one is a number; check that both are, and are equal
             return n1 == n2
         if self.is_const(v1) or self.is_const(exp_v2):
             return v1[:-1].startswith(exp_v2[:-1])
@@ -382,10 +405,13 @@
     def match_op(self, op, (exp_opname, exp_res, exp_args, exp_descr, _)):
         self._assert(op.name == exp_opname, "operation mismatch")
         self.match_var(op.res, exp_res)
-        if exp_args != ['...']:
+        if exp_args[-1:] == ['...']:      # exp_args ends with '...'
+            exp_args = exp_args[:-1]
+            self._assert(len(op.args) >= len(exp_args), "not enough arguments")
+        else:
             self._assert(len(op.args) == len(exp_args), "wrong number of 
arguments")
-            for arg, exp_arg in zip(op.args, exp_args):
-                self._assert(self.match_var(arg, exp_arg), "variable mismatch: 
%r instead of %r" % (arg, exp_arg))
+        for arg, exp_arg in zip(op.args, exp_args):
+            self._assert(self.match_var(arg, exp_arg), "variable mismatch: %r 
instead of %r" % (arg, exp_arg))
         self.match_descr(op.descr, exp_descr)
 
 
diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py 
b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
--- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
@@ -158,6 +158,24 @@
         assert match_var('v0', 'V0')
         assert match_var('ConstPtr(ptr0)', '_')
         py.test.raises(AssertionError, "match_var('_', 'v0')")
+        #
+        # numerics
+        assert match_var('1234', '1234')
+        assert not match_var('1234', '1235')
+        assert not match_var('v0', '1234')
+        assert not match_var('1234', 'v0')
+        assert match_var('1234', '#')        # the '#' char matches any number
+        assert not match_var('v0', '#')
+        assert match_var('1234', '_')        # the '_' char matches anything
+        #
+        # float numerics
+        assert match_var('0.000000', '0.0')
+        assert not match_var('0.000000', '0')
+        assert not match_var('0', '0.0')
+        assert not match_var('v0', '0.0')
+        assert not match_var('0.0', 'v0')
+        assert match_var('0.0', '#')
+        assert match_var('0.0', '_')
 
     def test_parse_op(self):
         res = OpMatcher.parse_op("  a =   int_add(  b,  3 ) # foo")
@@ -210,6 +228,19 @@
         """
         assert not self.match(loop, expected)
 
+    def test_dotdotdot_in_operation(self):
+        loop = """
+            [i0, i1]
+            jit_debug(i0, 1, ConstClass(myclass), i1)
+        """
+        assert self.match(loop, "jit_debug(...)")
+        assert self.match(loop, "jit_debug(i0, ...)")
+        assert self.match(loop, "jit_debug(i0, 1, ...)")
+        assert self.match(loop, "jit_debug(i0, 1, _, ...)")
+        assert self.match(loop, "jit_debug(i0, 1, _, i1, ...)")
+        py.test.raises(AssertionError, self.match,
+                       loop, "jit_debug(i0, 1, ..., i1)")
+
     def test_match_descr(self):
         loop = """
             [p0]
@@ -232,7 +263,7 @@
             jump(i4)
         """
         expected = """
-            i1 = int_add(0, 1)
+            i1 = int_add(i0, 1)
             ...
             i4 = int_mul(i1, 1000)
             jump(i4, descr=...)
@@ -249,7 +280,7 @@
             jump(i4, descr=...)
         """
         expected = """
-            i1 = int_add(0, 1)
+            i1 = int_add(i0, 1)
             ...
             _ = int_mul(_, 1000)
             jump(i4, descr=...)
@@ -268,7 +299,7 @@
             jump(i4)
         """
         expected = """
-            i1 = int_add(0, 1)
+            i1 = int_add(i0, 1)
             ...
         """
         assert self.match(loop, expected)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_buffers.py 
b/pypy/module/pypyjit/test_pypy_c/test_buffers.py
--- a/pypy/module/pypyjit/test_pypy_c/test_buffers.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_buffers.py
@@ -21,7 +21,7 @@
             i65 = getfield_gc(p18, descr=...)
             i67 = int_gt(0, i65)
             guard_false(i67, descr=...)
-            i69 = int_gt(., i65)
+            i69 = int_gt(#, i65)
             guard_true(i69, descr=...)
             --TICK--
         """)
@@ -56,7 +56,7 @@
             guard_false(i99, descr=...)
             i100 = int_lshift(i98, 24)
             i101 = int_or(i97, i100)
-            i102 = getfield_raw(\d+, descr=<FieldS pypysig_long_struct.c_value 
0>)
+            i102 = getfield_raw(#, descr=<FieldS pypysig_long_struct.c_value 
0>)
             i103 = int_lt(i102, 0)
             guard_false(i103, descr=...)
         """)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py 
b/pypy/module/pypyjit/test_pypy_c/test_call.py
--- a/pypy/module/pypyjit/test_pypy_c/test_call.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_call.py
@@ -395,7 +395,7 @@
             setarrayitem_gc(p24, 0, p26, descr=<ArrayP .>)
             setfield_gc(p22, p24, descr=<FieldP .*Arguments.inst_arguments_w 
.*>)
             }}}
-            p32 = call_may_force(..., p18, p22, descr=<Callr . rr EF=6>)
+            p32 = call_may_force(_, p18, p22, descr=<Callr . rr EF=6>)
             ...
         """)
 
diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py 
b/pypy/module/pypyjit/test_pypy_c/test_containers.py
--- a/pypy/module/pypyjit/test_pypy_c/test_containers.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py
@@ -82,7 +82,7 @@
             guard_no_exception(descr=...)
             i23 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, 
descr=<Calli . rri EF=4 OS=4>)
             guard_no_exception(descr=...)
-            i26 = int_and(i23, .*)
+            i26 = int_and(i23, #)
             i27 = int_is_true(i26)
             guard_false(i27, descr=...)
             p28 = getfield_gc(p13, descr=<FieldP dicttable.entries .*>)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_math.py 
b/pypy/module/pypyjit/test_pypy_c/test_math.py
--- a/pypy/module/pypyjit/test_pypy_c/test_math.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_math.py
@@ -21,7 +21,7 @@
             guard_true(i2, descr=...)
             guard_not_invalidated(descr=...)
             f1 = cast_int_to_float(i0)
-            i3 = float_le(f1, 0)
+            i3 = float_le(f1, 0.0)
             guard_false(i3, descr=...)
             f2 = call(ConstClass(log), f1, descr=<Callf . f EF=2>)
             f3 = call(ConstClass(log10), f1, descr=<Callf . f EF=2>)
@@ -56,7 +56,7 @@
             f3 = call(ConstClass(cos), f1, descr=<Callf . f EF=0>)
             f4 = float_sub(f2, f3)
             f5 = float_add(f0, f4)
-            i7 = int_add(i0, f1)
+            i7 = int_add(i0, 1)
             --TICK--
             jump(..., descr=)
         """)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py 
b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py
--- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py
@@ -104,7 +104,7 @@
             setarrayitem_gc(p150, 1, 0, descr=<ArrayS .+>)
             setarrayitem_gc(p150, 0, 0, descr=<ArrayS .+>)
             guard_not_invalidated(descr=...)
-            i154 = getfield_raw(ticker_address, descr=<FieldS 
pypysig_long_struct.c_value 0>)
+            i154 = getfield_raw(#, descr=<FieldS pypysig_long_struct.c_value 
0>)
             i155 = int_lt(i154, 0)
             guard_false(i155, descr=...)
             p156 = new_with_vtable(...)
@@ -142,7 +142,7 @@
             raw_store(i103, i132, 42.000000, descr=<ArrayF 8>)
             p152 = getfield_gc_pure(p126, descr=<FieldP 
pypy.module.micronumpy.iterators.IterState.inst_indices .+>)
             i153 = int_add(i120, 1)
-            i154 = getfield_raw(ticker_address, descr=<FieldS 
pypysig_long_struct.c_value 0>)
+            i154 = getfield_raw(#, descr=<FieldS pypysig_long_struct.c_value 
0>)
             setarrayitem_gc(p152, 1, 0, descr=<ArrayS .+>)
             setarrayitem_gc(p152, 0, 0, descr=<ArrayS .+>)
             i157 = int_lt(i154, 0)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py 
b/pypy/module/pypyjit/test_pypy_c/test_string.py
--- a/pypy/module/pypyjit/test_pypy_c/test_string.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_string.py
@@ -67,15 +67,15 @@
             i11 = int_lt(i6, i7)
             guard_true(i11, descr=...)
             guard_not_invalidated(descr=...)
-            i13 = int_eq(i6, %d)
+            i13 = int_eq(i6, %d)         # value provided below
             guard_false(i13, descr=...)
-            i15 = int_mod(i6, i8)
-            i17 = int_rshift(i15, %d)
-            i18 = int_and(i8, i17)
+            i15 = int_mod(i6, 10)
+            i17 = int_rshift(i15, %d)    # value provided below
+            i18 = int_and(10, i17)
             i19 = int_add(i15, i18)
             i21 = int_lt(i19, 0)
             guard_false(i21, descr=...)
-            i22 = int_ge(i19, i8)
+            i22 = int_ge(i19, 10)
             guard_false(i22, descr=...)
             i23 = strgetitem(p10, i19)
             p25 = newstr(1)
@@ -83,7 +83,7 @@
             p93 = call(ConstClass(fromstr), p25, 16, descr=<Callr . ri EF=3>)
             guard_no_exception(descr=...)
             i95 = getfield_gc_pure(p93, descr=<FieldS 
rpython.rlib.rbigint.rbigint.inst_size .*>)
-            i96 = int_gt(i95, .*)
+            i96 = int_gt(i95, #)
             guard_false(i96, descr=...)
             i94 = call(ConstClass(rbigint._toint_helper), p93, descr=<Calli . 
r EF=3>)
             guard_no_exception(descr=...)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_thread.py 
b/pypy/module/pypyjit/test_pypy_c/test_thread.py
--- a/pypy/module/pypyjit/test_pypy_c/test_thread.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_thread.py
@@ -64,7 +64,7 @@
         guard_true(i56, descr=...)
         p57 = force_token()
         setfield_gc(p0, p57, descr=<FieldP 
pypy.interpreter.pyframe.PyFrame.vable_token 8>)
-        i58 = call_release_gil(..., i37, 1, descr=<Calli 4 ii EF=6>)
+        i58 = call_release_gil(_, i37, 1, descr=<Calli 4 ii EF=6>)
         guard_not_forced(descr=...)
         guard_no_exception(descr=...)
         i59 = int_is_true(i58)
@@ -72,14 +72,14 @@
         i60 = int_sub(i44, 1)
         p62 = force_token()
         setfield_gc(p0, p62, descr=<FieldP 
pypy.interpreter.pyframe.PyFrame.vable_token 8>)
-        i63 = call_release_gil(..., i37, 0, descr=<Calli 4 ii EF=6>)
+        i63 = call_release_gil(_, i37, 0, descr=<Calli 4 ii EF=6>)
         guard_not_forced(descr=...)
         guard_no_exception(descr=...)
         i64 = int_is_true(i63)
         guard_false(i64, descr=...)
         p65 = force_token()
         setfield_gc(p0, p65, descr=<FieldP 
pypy.interpreter.pyframe.PyFrame.vable_token 8>)
-        call_release_gil(..., i37, descr=<Callv 0 i EF=6>)
+        call_release_gil(_, i37, descr=<Callv 0 i EF=6>)
         guard_not_forced(descr=...)
         guard_no_exception(descr=...)
         guard_not_invalidated(descr=...)
diff --git a/rpython/jit/backend/x86/assembler.py 
b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -1833,15 +1833,17 @@
             offset = self.cpu.get_ofs_of_frame_field('jf_guard_exc')
             mc.MOV_br(offset, ebx.value)
 
-        # now we return from the complete frame, which starts from
-        # _call_header_with_stack_check().  The LEA in _call_footer below
-        # throws away most of the frame, including all the PUSHes that we
-        # did just above.
+        # fill in the jf_descr and jf_gcmap fields of the frame according
+        # to which failure we are resuming from.  These are constants
+        # pushed on the stack just before we jump to the current helper,
+        # in generate_quick_failure().
         ofs = self.cpu.get_ofs_of_frame_field('jf_descr')
         ofs2 = self.cpu.get_ofs_of_frame_field('jf_gcmap')
         mc.POP_b(ofs2)
         mc.POP_b(ofs)
 
+        # now we return from the complete frame, which starts from
+        # _call_header_with_stack_check().  The _call_footer below does it.
         self._call_footer()
         rawstart = mc.materialize(self.cpu.asmmemmgr, [])
         self.failure_recovery_code[exc + 2 * withfloats] = rawstart
diff --git a/rpython/rtyper/normalizecalls.py b/rpython/rtyper/normalizecalls.py
--- a/rpython/rtyper/normalizecalls.py
+++ b/rpython/rtyper/normalizecalls.py
@@ -298,12 +298,16 @@
 
 # ____________________________________________________________
 
+class TooLateForNewSubclass(Exception):
+    pass
+
 class TotalOrderSymbolic(ComputedIntSymbolic):
 
     def __init__(self, orderwitness, peers):
         self.orderwitness = orderwitness
         self.peers = peers
         self.value = None
+        self._with_subclasses = None    # unknown
         peers.append(self)
 
     def __cmp__(self, other):
@@ -320,12 +324,34 @@
     def __rsub__(self, other):
         return other - self.compute_fn()
 
+    def check_any_subclass_in_peer_list(self, i):
+        # check if the next peer, in order, is or not the end
+        # marker for this start marker
+        assert self.peers[i] is self
+        return self.peers[i + 1].orderwitness != self.orderwitness + [MAX]
+
+    def number_with_subclasses(self):
+        # Return True or False depending on whether this is the
+        # subclassrange_min corresponding to a class which has subclasses
+        # or not.  If this is called and returns False, then adding later
+        # new subclasses will crash in compute_fn().
+        if self._with_subclasses is None:     # unknown so far
+            self.peers.sort()
+            i = self.peers.index(self)
+            self._with_subclasses = self.check_any_subclass_in_peer_list(i)
+        return self._with_subclasses
+
     def compute_fn(self):
         if self.value is None:
             self.peers.sort()
             for i, peer in enumerate(self.peers):
                 assert peer.value is None or peer.value == i
                 peer.value = i
+                #
+                if peer._with_subclasses is False:
+                    if peer.check_any_subclass_in_peer_list(i):
+                        raise TooLateForNewSubclass
+                #
             assert self.value is not None
         return self.value
 
diff --git a/rpython/rtyper/rclass.py b/rpython/rtyper/rclass.py
--- a/rpython/rtyper/rclass.py
+++ b/rpython/rtyper/rclass.py
@@ -1007,14 +1007,11 @@
         v_obj, v_cls = hop.inputargs(instance_repr, class_repr)
         if isinstance(v_cls, Constant):
             cls = v_cls.value
-            # XXX re-implement the following optimization
-            #if cls.subclassrange_max == cls.subclassrange_min:
-            #    # a class with no subclass
-            #    return hop.gendirectcall(rclass.ll_isinstance_exact, v_obj, 
v_cls)
-            #else:
-            minid = hop.inputconst(Signed, cls.subclassrange_min)
-            maxid = hop.inputconst(Signed, cls.subclassrange_max)
-            return hop.gendirectcall(ll_isinstance_const, v_obj, minid, maxid)
+            llf, llf_nonnull = make_ll_isinstance(self.rtyper, cls)
+            if hop.args_s[0].can_be_None:
+                return hop.gendirectcall(llf, v_obj)
+            else:
+                return hop.gendirectcall(llf_nonnull, v_obj)
         else:
             return hop.gendirectcall(ll_isinstance, v_obj, v_cls)
 
@@ -1128,16 +1125,26 @@
     obj_cls = obj.typeptr
     return ll_issubclass(obj_cls, cls)
 
-def ll_isinstance_const(obj, minid, maxid):
-    if not obj:
-        return False
-    return ll_issubclass_const(obj.typeptr, minid, maxid)
-
-def ll_isinstance_exact(obj, cls):
-    if not obj:
-        return False
-    obj_cls = obj.typeptr
-    return obj_cls == cls
+def make_ll_isinstance(rtyper, cls):
+    try:
+        return rtyper.isinstance_helpers[cls._obj]
+    except KeyError:
+        minid = cls.subclassrange_min
+        maxid = cls.subclassrange_max
+        if minid.number_with_subclasses():
+            def ll_isinstance_const_nonnull(obj):
+                objid = obj.typeptr.subclassrange_min
+                return llop.int_between(Bool, minid, objid, maxid)
+        else:
+            def ll_isinstance_const_nonnull(obj):
+                return obj.typeptr == cls
+        def ll_isinstance_const(obj):
+            if not obj:
+                return False
+            return ll_isinstance_const_nonnull(obj)
+        result = (ll_isinstance_const, ll_isinstance_const_nonnull)
+        rtyper.isinstance_helpers[cls._obj] = result
+        return result
 
 def ll_runtime_type_info(obj):
     return obj.typeptr.rtti
diff --git a/rpython/rtyper/rtyper.py b/rpython/rtyper/rtyper.py
--- a/rpython/rtyper/rtyper.py
+++ b/rpython/rtyper/rtyper.py
@@ -59,6 +59,7 @@
         self.typererror_count = 0
         # make the primitive_to_repr constant mapping
         self.primitive_to_repr = {}
+        self.isinstance_helpers = {}
         self.exceptiondata = ExceptionData(self)
         self.custom_trace_funcs = []
 
diff --git a/rpython/rtyper/test/test_normalizecalls.py 
b/rpython/rtyper/test/test_normalizecalls.py
--- a/rpython/rtyper/test/test_normalizecalls.py
+++ b/rpython/rtyper/test/test_normalizecalls.py
@@ -6,6 +6,7 @@
 from rpython.rtyper.test.test_llinterp import interpret
 from rpython.rtyper.lltypesystem import lltype
 from rpython.rtyper.normalizecalls import TotalOrderSymbolic, MAX
+from rpython.rtyper.normalizecalls import TooLateForNewSubclass
 
 
 def test_TotalOrderSymbolic():
@@ -21,6 +22,49 @@
     assert t1 <= 5
     assert t1.value == 0
 
+def test_TotalOrderSymbolic_with_subclasses():
+    lst = []
+    t3 = TotalOrderSymbolic([3, 4, 2, MAX], lst)
+    t1 = TotalOrderSymbolic([3, 4], lst)
+    t2 = TotalOrderSymbolic([3, 4, 2], lst)
+    t4 = TotalOrderSymbolic([3, 4, MAX], lst)
+    assert t1.number_with_subclasses()
+    assert not t2.number_with_subclasses()
+    assert [t.compute_fn() for t in [t1, t2, t3, t4]] == range(4)
+    #
+    lst = []
+    t1 = TotalOrderSymbolic([3, 4], lst)
+    t3 = TotalOrderSymbolic([3, 4, 2, MAX], lst)
+    t4 = TotalOrderSymbolic([3, 4, MAX], lst)
+    t2 = TotalOrderSymbolic([3, 4, 2], lst)
+    assert not t2.number_with_subclasses()
+    assert t1.number_with_subclasses()
+    assert [t.compute_fn() for t in [t1, t2, t3, t4]] == range(4)
+    #
+    lst = []
+    t1 = TotalOrderSymbolic([3, 4], lst)
+    t4 = TotalOrderSymbolic([3, 4, MAX], lst)
+    assert not t1.number_with_subclasses()
+    t2 = TotalOrderSymbolic([3, 4, 2], lst)
+    t3 = TotalOrderSymbolic([3, 4, 2, MAX], lst)
+    py.test.raises(TooLateForNewSubclass, t2.compute_fn)
+    #
+    lst = []
+    t1 = TotalOrderSymbolic([3, 4], lst)
+    t4 = TotalOrderSymbolic([3, 4, MAX], lst)
+    assert not t1.number_with_subclasses()
+    t2 = TotalOrderSymbolic([1], lst)
+    t3 = TotalOrderSymbolic([1, MAX], lst)
+    assert [t.compute_fn() for t in [t2, t3, t1, t4]] == range(4)
+    #
+    lst = []
+    t1 = TotalOrderSymbolic([3, 4], lst)
+    t4 = TotalOrderSymbolic([3, 4, MAX], lst)
+    assert not t1.number_with_subclasses()
+    t2 = TotalOrderSymbolic([6], lst)
+    t3 = TotalOrderSymbolic([6, MAX], lst)
+    assert [t.compute_fn() for t in [t1, t4, t2, t3]] == range(4)
+
 # ____________________________________________________________
 
 class TestNormalize(object):
diff --git a/rpython/tool/jitlogparser/parser.py 
b/rpython/tool/jitlogparser/parser.py
--- a/rpython/tool/jitlogparser/parser.py
+++ b/rpython/tool/jitlogparser/parser.py
@@ -216,7 +216,7 @@
     line_starts_here = property(getline_starts_here)
 
     def __repr__(self):
-        return "[%s]" % ", ".join([repr(op) for op in self.operations])
+        return "[%s\n]" % "\n    ".join([repr(op) for op in self.operations])
 
     def pretty_print(self, out):
         pass
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to