[pypy-commit] pypy jit-short_from_state: keep track of array/str/unicode length and guard for them to make getitems safe in short preamble

hakanardo noreply at buildbot.pypy.org
Wed Jul 20 10:19:41 CEST 2011


Author: Hakan Ardo <hakan at debian.org>
Branch: jit-short_from_state
Changeset: r45766:3f1e8b5dd3b0
Date: 2011-07-20 09:38 +0200
http://bitbucket.org/pypy/pypy/changeset/3f1e8b5dd3b0/

Log:	keep track of array/str/unicode length and guard for them to make
	getitems safe in short preamble

diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py
--- a/pypy/jit/metainterp/optimizeopt/heap.py
+++ b/pypy/jit/metainterp/optimizeopt/heap.py
@@ -3,7 +3,7 @@
 from pypy.jit.metainterp.resoperation import rop, ResOperation
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.jit.metainterp.jitexc import JitException
-from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
+from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, MODE_ARRAY
 from pypy.jit.metainterp.history import ConstInt, Const
 
 
@@ -407,6 +407,7 @@
         indexvalue = self.getvalue(op.getarg(1))
         cf = None
         if indexvalue.is_constant():
+            arrayvalue.make_len_gt(MODE_ARRAY, op.getdescr(), indexvalue.box.getint())
             # use the cache on (arraydescr, index), which is a constant
             cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint())
             fieldvalue = cf.getfield_from_cache(self, arrayvalue)
@@ -434,6 +435,8 @@
         #
         indexvalue = self.getvalue(op.getarg(1))
         if indexvalue.is_constant():
+            arrayvalue = self.getvalue(op.getarg(0))
+            arrayvalue.make_len_gt(MODE_ARRAY, op.getdescr(), indexvalue.box.getint())
             # use the cache on (arraydescr, index), which is a constant
             cf = self.arrayitem_cache(op.getdescr(), indexvalue.box.getint())
             cf.do_setfield(self, op)
diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py
--- a/pypy/jit/metainterp/optimizeopt/intbounds.py
+++ b/pypy/jit/metainterp/optimizeopt/intbounds.py
@@ -1,4 +1,5 @@
-from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0
+from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0, \
+                                                  MODE_ARRAY, MODE_STR, MODE_UNICODE
 from pypy.jit.metainterp.optimizeopt.util import _findall
 from pypy.jit.metainterp.optimizeopt.intutils import (IntBound, IntUnbounded,
     IntLowerBound, IntUpperBound)
@@ -285,10 +286,24 @@
 
     def optimize_ARRAYLEN_GC(self, op):
         self.emit_operation(op)
-        v1 = self.getvalue(op.result)
-        v1.intbound.make_ge(IntLowerBound(0))
+        array  = self.getvalue(op.getarg(0))
+        result = self.getvalue(op.result)
+        array.make_len_gt(MODE_ARRAY, op.getdescr(), -1)
+        result.intbound = array.lenbound[2]
 
-    optimize_STRLEN = optimize_UNICODELEN = optimize_ARRAYLEN_GC
+    def optimize_STRLEN(self, op):
+        self.emit_operation(op)
+        array  = self.getvalue(op.getarg(0))
+        result = self.getvalue(op.result)
+        array.make_len_gt(MODE_STR, op.getdescr(), -1)
+        result.intbound = array.lenbound[2]
+
+    def optimize_UNICODELEN(self, op):
+        self.emit_operation(op)
+        array  = self.getvalue(op.getarg(0))
+        result = self.getvalue(op.result)
+        array.make_len_gt(MODE_UNICODE, op.getdescr(), -1)
+        result.intbound = array.lenbound[2]
 
     def optimize_STRGETITEM(self, op):
         self.emit_operation(op)
diff --git a/pypy/jit/metainterp/optimizeopt/intutils.py b/pypy/jit/metainterp/optimizeopt/intutils.py
--- a/pypy/jit/metainterp/optimizeopt/intutils.py
+++ b/pypy/jit/metainterp/optimizeopt/intutils.py
@@ -1,4 +1,9 @@
 from pypy.rlib.rarithmetic import ovfcheck, ovfcheck_lshift, LONG_BIT
+from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.history import BoxInt, ConstInt
+import sys
+MAXINT = sys.maxint
+MININT = -sys.maxint - 1
 
 class IntBound(object):
     _attrs_ = ('has_upper', 'has_lower', 'upper', 'lower')
@@ -225,6 +230,23 @@
         res.has_upper = self.has_upper
         return res
 
+    def make_guards(self, box, guards):
+        if self.has_lower and self.lower > MININT:
+            bound = self.lower
+            res = BoxInt()
+            op = ResOperation(rop.INT_GE, [box, ConstInt(bound)], res)
+            guards.append(op)
+            op = ResOperation(rop.GUARD_TRUE, [res], None)
+            guards.append(op)
+        if self.has_upper and self.upper < MAXINT:
+            bound = self.upper
+            res = BoxInt()
+            op = ResOperation(rop.INT_LE, [box, ConstInt(bound)], res)
+            guards.append(op)
+            op = ResOperation(rop.GUARD_TRUE, [res], None)
+            guards.append(op)
+    
+
 class IntUpperBound(IntBound):
     def __init__(self, upper):
         self.has_upper = True
diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -12,26 +12,29 @@
 from pypy.rpython.lltypesystem import lltype
 from pypy.jit.metainterp.history import AbstractDescr, make_hashable_int
 from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded, \
-                                                     ImmutableIntUnbounded
+                                                     ImmutableIntUnbounded, \
+                                                     IntLowerBound, MININT, MAXINT
 from pypy.tool.pairtype import extendabletype
+from pypy.rlib.debug import debug_start, debug_stop, debug_print
 
 LEVEL_UNKNOWN    = '\x00'
 LEVEL_NONNULL    = '\x01'
 LEVEL_KNOWNCLASS = '\x02'     # might also mean KNOWNARRAYDESCR, for arrays
 LEVEL_CONSTANT   = '\x03'
 
-import sys
-MAXINT = sys.maxint
-MININT = -sys.maxint - 1
+MODE_ARRAY   = '\x00'
+MODE_STR     = '\x01'
+MODE_UNICODE = '\x02'
 
 class OptValue(object):
     __metaclass__ = extendabletype
-    _attrs_ = ('box', 'known_class', 'last_guard_index', 'level', 'intbound')
+    _attrs_ = ('box', 'known_class', 'last_guard_index', 'level', 'intbound', 'lenbound')
     last_guard_index = -1
 
     level = LEVEL_UNKNOWN
     known_class = None
     intbound = ImmutableIntUnbounded()
+    lenbound = None
 
     def __init__(self, box, level=None, known_class=None, intbound=None):
         self.box = box
@@ -50,6 +53,14 @@
             self.make_constant(box)
         # invariant: box is a Const if and only if level == LEVEL_CONSTANT
 
+    def make_len_gt(self, mode, descr, val):
+        if self.lenbound:
+            assert self.lenbound[0] == mode
+            assert self.lenbound[1] == descr
+            self.lenbound[2].make_gt(IntBound(val, val))
+        else:
+            self.lenbound = (mode, descr, IntLowerBound(val + 1))
+
     def make_guards(self, box):
         guards = []
         if self.level == LEVEL_CONSTANT:
@@ -64,20 +75,21 @@
             if self.level == LEVEL_NONNULL:
                 op = ResOperation(rop.GUARD_NONNULL, [box], None)
                 guards.append(op)
-            if self.intbound.has_lower and self.intbound.lower > MININT:
-                bound = self.intbound.lower
-                res = BoxInt()
-                op = ResOperation(rop.INT_GE, [box, ConstInt(bound)], res)
+            self.intbound.make_guards(box, guards)
+            if self.lenbound:
+                lenbox = BoxInt()
+                if self.lenbound[0] == MODE_ARRAY:
+                    op = ResOperation(rop.ARRAYLEN_GC, [box], lenbox, self.lenbound[1])
+                elif self.lenbound[0] == MODE_STR:
+                    op = ResOperation(rop.STRLEN, [box], lenbox, self.lenbound[1])
+                elif self.lenbound[0] == MODE_UNICODE:
+                    op = ResOperation(rop.UNICODELEN, [box], lenbox, self.lenbound[1])
+                else:
+                    debug_print("Unknown lenbound mode")
+                    assert False
                 guards.append(op)
-                op = ResOperation(rop.GUARD_TRUE, [res], None)
-                guards.append(op)
-            if self.intbound.has_upper and self.intbound.upper < MAXINT:
-                bound = self.intbound.upper
-                res = BoxInt()
-                op = ResOperation(rop.INT_LE, [box, ConstInt(bound)], res)
-                guards.append(op)
-                op = ResOperation(rop.GUARD_TRUE, [res], None)
-                guards.append(op)
+                self.lenbound[2].make_guards(lenbox, guards)
+
         return guards
 
     def force_box(self):
@@ -428,6 +440,11 @@
 
     def produce_potential_short_preamble_ops(self, sb):
         for op in self.emitted_pure_operations:
+            if op.getopnum() == rop.GETARRAYITEM_GC_PURE or \
+               op.getopnum() == rop.STRGETITEM or \
+               op.getopnum() == rop.UNICODEGETITEM:
+                if not self.getvalue(op.getarg(1)).is_constant():
+                    continue
             sb.add_potential(op)
         for opt in self.optimizations:
             opt.produce_potential_short_preamble_ops(sb)
@@ -676,6 +693,30 @@
     def optimize_DEBUG_MERGE_POINT(self, op):
         self.emit_operation(op)
 
+    def optimize_GETARRAYITEM_GC_PURE(self, op):
+        indexvalue = self.getvalue(op.getarg(1))
+        if indexvalue.is_constant():
+            arrayvalue = self.getvalue(op.getarg(0))
+            arrayvalue.make_len_gt(MODE_ARRAY, op.getdescr(), indexvalue.box.getint())
+        self.optimize_default(op)
+
+    def optimize_STRGETITEM(self, op):
+        indexvalue = self.getvalue(op.getarg(1))
+        if indexvalue.is_constant():
+            arrayvalue = self.getvalue(op.getarg(0))
+            arrayvalue.make_len_gt(MODE_STR, op.getdescr(), indexvalue.box.getint())
+        self.optimize_default(op)
+
+    def optimize_UNICODEGETITEM(self, op):
+        indexvalue = self.getvalue(op.getarg(1))
+        if indexvalue.is_constant():
+            arrayvalue = self.getvalue(op.getarg(0))
+            arrayvalue.make_len_gt(MODE_UNICODE, op.getdescr(), indexvalue.box.getint())
+        self.optimize_default(op)
+        
+
+    
+
 optimize_ops = _findall(Optimizer, 'optimize_')
 
 
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -6467,6 +6467,22 @@
         """
         self.optimize_loop(ops, expected)
 
+    def test_loopinvariant_strlen_with_bound(self):
+        ops = """
+        [p9]
+        i843 = strlen(p9)
+        i1 = int_gt(i843, 7)
+        guard_true(i1) []
+        call(i843, descr=nonwritedescr)
+        jump(p9)
+        """
+        expected = """
+        [p9, i2]
+        call(i2, descr=nonwritedescr)
+        jump(p9, i2)
+        """
+        self.optimize_loop(ops, expected)
+
     def test_loopinvariant_strgetitem(self):
         ops = """
         [p9, i1]
@@ -6474,12 +6490,7 @@
         call(i843, descr=nonwritedescr)
         jump(p9, i1)
         """
-        expected = """
-        [p9, i1, i2]
-        call(i2, descr=nonwritedescr)
-        jump(p9, i1, i2)
-        """
-        self.optimize_loop(ops, expected)
+        self.optimize_loop(ops, ops)
 
     def test_loopinvariant_unicodelen(self):
         ops = """
@@ -6502,12 +6513,7 @@
         call(i843, descr=nonwritedescr)
         jump(p9, i1)
         """
-        expected = """
-        [p9, i1, i2]
-        call(i2, descr=nonwritedescr)
-        jump(p9, i1, i2)
-        """
-        self.optimize_loop(ops, expected)
+        self.optimize_loop(ops, ops)
 
     def test_loopinvariant_arraylen(self):
         ops = """
@@ -6525,21 +6531,26 @@
 
     def test_loopinvariant_getarrayitem(self):
         ops = """
-        [p1]
+        [p0]
+        p1 = getfield_gc(p0, descr=nextdescr)
         p2 = getarrayitem_gc(p1, 7, descr=<GcPtrArrayDescr>)
         call(p2, descr=nonwritedescr)
-        jump(p1)
+        jump(p0)
         """
         short = """
-        [p1]
+        [p0]
+        p1 = getfield_gc(p0, descr=nextdescr)
+        guard_nonnull(p1) []
         i1 = arraylen_gc(p1)
+        i2 = int_ge(i1, 8)
+        guard_true(i2) []
         p2 = getarrayitem_gc(p1, 7, descr=<GcPtrArrayDescr>)
-        jump(p1, p2)
-        """
-        expected = """
-        [p1, p2]
+        jump(p0, p2)
+        """
+        expected = """
+        [p0, p2]
         call(p2, descr=nonwritedescr)
-        jump(p1, p2)
+        jump(p0, p2)
         """
         self.optimize_loop(ops, expected, expected_short=short)
 
@@ -6555,6 +6566,115 @@
         """
         self.optimize_loop(ops, expected)
         
+    def test_arraylen_bound(self):
+        ops = """
+        [p1, i]
+        p2 = getarrayitem_gc(p1, 7, descr=<GcPtrArrayDescr>)
+        i1 = arraylen_gc(p1)
+        i2 = int_ge(i1, 8)
+        guard_true(i2) []
+        jump(p2, i2)
+        """
+        expected = """
+        [p1]        
+        p2 = getarrayitem_gc(p1, 7, descr=<GcPtrArrayDescr>)
+        i1 = arraylen_gc(p1)
+        jump(p2)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_loopinvariant_getarrayitem_gc_pure(self):
+        ops = """
+        [p9, i1]
+        i843 = getarrayitem_gc_pure(p9, i1)
+        call(i843, descr=nonwritedescr)
+        jump(p9, i1)
+        """
+        self.optimize_loop(ops, ops)
+
+    def test_loopinvariant_constant_getarrayitem_pure(self):
+        ops = """
+        [p0]
+        p1 = getfield_gc(p0, descr=nextdescr)
+        p2 = getarrayitem_gc_pure(p1, 7, descr=<GcPtrArrayDescr>)
+        call(p2, descr=nonwritedescr)
+        jump(p0)
+        """
+        short = """
+        [p0]
+        p1 = getfield_gc(p0, descr=nextdescr)
+        guard_nonnull(p1) []
+        i1 = arraylen_gc(p1)
+        i2 = int_ge(i1, 8)
+        guard_true(i2) []
+        p2 = getarrayitem_gc_pure(p1, 7, descr=<GcPtrArrayDescr>)
+        jump(p0, p2)
+        """
+        expected = """
+        [p0, p2]
+        call(p2, descr=nonwritedescr)
+        jump(p0, p2)
+        """
+        self.optimize_loop(ops, expected, expected_short=short)
+        
+        
+    def test_loopinvariant_constant_strgetitem(self):
+        ops = """
+        [p0]
+        p1 = getfield_gc(p0, descr=nextdescr)
+        p2 = strgetitem(p1, 7)
+        call(p2, descr=nonwritedescr)
+        jump(p0)
+        """
+        short = """
+        [p0]
+        p1 = getfield_gc(p0, descr=nextdescr)
+        guard_nonnull(p1) []
+        i1 = strlen(p1)
+        i2 = int_ge(i1, 8)
+        guard_true(i2) []
+        p2 = strgetitem(p1, 7, descr=<GcPtrArrayDescr>)
+        i8 = int_ge(p2, 0)
+        guard_true(i8) []
+        i9 = int_le(p2, 255)
+        guard_true(i9) []
+        jump(p0, p2)
+        """
+        expected = """
+        [p0, p2]
+        call(p2, descr=nonwritedescr)
+        jump(p0, p2)
+        """
+        self.optimize_loop(ops, expected, expected_short=short)
+
+    def test_loopinvariant_constant_unicodegetitem(self):
+        ops = """
+        [p0]
+        p1 = getfield_gc(p0, descr=nextdescr)
+        p2 = unicodegetitem(p1, 7)
+        call(p2, descr=nonwritedescr)
+        jump(p0)
+        """
+        short = """
+        [p0]
+        p1 = getfield_gc(p0, descr=nextdescr)
+        guard_nonnull(p1) []
+        i1 = unicodelen(p1)
+        i2 = int_ge(i1, 8)
+        guard_true(i2) []
+        p2 = unicodegetitem(p1, 7, descr=<GcPtrArrayDescr>)
+        i8 = int_ge(p2, 0)
+        guard_true(i8) []
+        jump(p0, p2)
+        """
+        expected = """
+        [p0, p2]
+        call(p2, descr=nonwritedescr)
+        jump(p0, p2)
+        """
+        self.optimize_loop(ops, expected, expected_short=short)
+        
+        
 
 class TestLLtype(OptimizeOptTest, LLtypeMixin):
     pass
diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py
--- a/pypy/jit/metainterp/optimizeopt/unroll.py
+++ b/pypy/jit/metainterp/optimizeopt/unroll.py
@@ -247,6 +247,7 @@
             initial_inputargs_len = len(inputargs)
             self.inliner = Inliner(loop.inputargs, jump_args)
 
+
             short = self.inline(inputargs, self.cloned_operations,
                                 loop.inputargs, short_inputargs,
                                 virtual_state)
diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py
--- a/pypy/jit/metainterp/optimizeopt/virtualstate.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py
@@ -201,6 +201,7 @@
         else:
             self.constbox = None
         self.position_in_notvirtuals = -1
+        self.lenbound = value.lenbound
 
     def generalization_of(self, other, renum, bad):
         # XXX This will always retrace instead of forcing anything which
@@ -235,12 +236,26 @@
             bad[self] = True
             bad[other] = True
             return False
+        if self.lenbound and other.lenbound:
+            if self.lenbound[0] != other.lenbound[0] or \
+               self.lenbound[1] != other.lenbound[1] or \
+               not self.lenbound[2].contains_bound(other.lenbound[2]):
+                bad[self] = True
+                bad[other] = True
+                return False
+        elif self.lenbound or other.lenbound:
+            bad[self] = True
+            bad[other] = True
+            return False
         return True
 
     def _generate_guards(self, other, box, cpu, extra_guards):
         if not isinstance(other, NotVirtualStateInfo):
             raise InvalidLoop
 
+        if self.lenbound or other.lenbound:
+            raise InvalidLoop
+
         if self.level == LEVEL_KNOWNCLASS and \
            box.nonnull() and \
            self.known_class.same_constant(cpu.ts.cls_of_box(box)):
@@ -324,8 +339,12 @@
                  LEVEL_CONSTANT: 'Constant(%r)' % self.constbox,
                  }[self.level]
             
+        lb = ''
+        if self.lenbound:
+            lb = ', ' + self.lenbound[2].__repr__()
+        
         debug_print(indent + mark + 'NotVirtualInfo(%d' % self.position +
-                    ', ' + l + ', ' + self.intbound.__repr__() + ')')
+                    ', ' + l + ', ' + self.intbound.__repr__() + lb + ')')
 
 class VirtualState(object):
     def __init__(self, state):
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
@@ -2782,7 +2782,7 @@
         res = self.meta_interp(f, [16])
         assert res == f(16)
 
-    def test_loopinvariant_array_shrinking(self):
+    def test_loopinvariant_array_shrinking1(self):
         myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'i', 'a'])
         def f(n):
             sa = i = 0
@@ -2798,7 +2798,6 @@
         assert res == f(32)
         self.check_loops(arraylen_gc=1)
 
-
 class TestOOtype(BasicTests, OOJitMixin):
 
     def test_oohash(self):
@@ -2976,5 +2975,97 @@
         self.meta_interp(f, [], enable_opts='')
         self.check_loops(new_with_vtable=1)
 
+    def test_two_loopinvariant_arrays1(self):
+        from pypy.rpython.lltypesystem import lltype, llmemory, rffi
+        myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'i', 'a'])
+        TP = lltype.GcArray(lltype.Signed)
+        def f(n):
+            sa = i = 0
+            a = lltype.malloc(TP, 5)
+            a[4] = 7
+            while i < n:
+                myjitdriver.jit_merge_point(sa=sa, n=n, a=a, i=i)
+                if i < n/2:
+                    sa += a[4]
+                if i == n/2:
+                    a = lltype.malloc(TP, 3)
+                i += 1
+            return sa
+        res = self.meta_interp(f, [32])
+        assert res == f(32)
+        self.check_tree_loop_count(3)
+
+    def test_two_loopinvariant_arrays2(self):
+        from pypy.rpython.lltypesystem import lltype, llmemory, rffi
+        myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'i', 'a'])
+        TP = lltype.GcArray(lltype.Signed)
+        def f(n):
+            sa = i = 0
+            a = lltype.malloc(TP, 5)
+            a[4] = 7
+            while i < n:
+                myjitdriver.jit_merge_point(sa=sa, n=n, a=a, i=i)
+                if i < n/2:
+                    sa += a[4]
+                elif i > n/2:
+                    sa += a[2]
+                if i == n/2:
+                    a = lltype.malloc(TP, 3)
+                    a[2] = 42
+                i += 1
+            return sa
+        res = self.meta_interp(f, [32])
+        assert res == f(32)
+        self.check_tree_loop_count(3)
+        
+    def test_two_loopinvariant_arrays3(self):
+        from pypy.rpython.lltypesystem import lltype, llmemory, rffi
+        myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'i', 'a'])
+        TP = lltype.GcArray(lltype.Signed)
+        def f(n):
+            sa = i = 0
+            a = lltype.malloc(TP, 5)
+            a[2] = 7
+            while i < n:
+                myjitdriver.jit_merge_point(sa=sa, n=n, a=a, i=i)
+                if i < n/2:
+                    sa += a[2]
+                elif i > n/2:
+                    sa += a[3]
+                if i == n/2:
+                    a = lltype.malloc(TP, 7)
+                    a[3] = 10
+                    a[2] = 42
+                i += 1
+            return sa
+        res = self.meta_interp(f, [32])
+        assert res == f(32)
+        self.check_tree_loop_count(2)
+        
+    def test_two_loopinvariant_arrays_boxed(self):
+        class A(object):
+            def __init__(self, a):
+                self.a  = a
+        from pypy.rpython.lltypesystem import lltype, llmemory, rffi
+        myjitdriver = JitDriver(greens = [], reds = ['sa', 'n', 'i', 'a'])
+        TP = lltype.GcArray(lltype.Signed)
+        a1 = A(lltype.malloc(TP, 5))
+        a2 = A(lltype.malloc(TP, 3))
+        def f(n):
+            sa = i = 0
+            a = a1
+            a.a[4] = 7
+            while i < n:
+                myjitdriver.jit_merge_point(sa=sa, n=n, a=a, i=i)
+                if i < n/2:
+                    sa += a.a[4]
+                if i == n/2:
+                    a = a2
+                i += 1
+            return sa
+        res = self.meta_interp(f, [32])
+        assert res == f(32)
+        self.check_loops(arraylen_gc=1, everywhere=True)
+
 class TestLLtype(BaseLLtypeTests, LLJitMixin):
     pass


More information about the pypy-commit mailing list