[pypy-svn] r66541 - in pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp: . test

arigo at codespeak.net arigo at codespeak.net
Thu Jul 23 17:30:03 CEST 2009


Author: arigo
Date: Thu Jul 23 17:30:01 2009
New Revision: 66541

Modified:
   pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/optimizeopt.py
   pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/resume.py
   pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/oparser.py
   pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_optimizeopt.py
   pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_resume.py
Log:
Unrevert r66530, and tie virtuals to FAILs in optimizeopt.py.
In-progress.


Modified: pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/optimizeopt.py	(original)
+++ pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/optimizeopt.py	Thu Jul 23 17:30:01 2009
@@ -4,6 +4,7 @@
 from pypy.jit.metainterp.specnode import SpecNode
 from pypy.jit.metainterp.specnode import VirtualInstanceSpecNode
 from pypy.jit.metainterp.optimizeutil import av_newdict, _findall, sort_descrs
+from pypy.jit.metainterp import resume
 from pypy.rlib.objectmodel import we_are_translated
 
 
@@ -36,11 +37,9 @@
     def force_box(self):
         return self.box
 
-    def get_args_for_fail(self, list, memo):
-        if not self.is_constant():
-            if self.box not in memo:
-                list.append(self.box)
-                memo[self.box] = None
+    def get_args_for_fail(self, srcbox, modifier):
+        if self.is_constant():
+            modifier.make_constant(srcbox, self.box)
 
     def is_constant(self):
         return self.level == LEVEL_CONSTANT
@@ -120,10 +119,11 @@
                 newoperations.append(op)
         return self.box
 
-    def get_args_for_fail(self, list, memo):
+    def get_args_for_fail(self, srcbox, modifier):
         if self.box is not None:
-            InstanceValue.get_args_for_fail(self, list, memo)
+            InstanceValue.get_args_for_fail(self, srcbox, modifier)
         else:
+            xxxxx
             if self.source_op is not None: #otherwise, no loop detection needed
                 keybox = self.source_op.result
                 if keybox in memo:
@@ -258,18 +258,19 @@
         op_fail = op1.suboperations[0]
         assert op_fail.opnum == rop.FAIL
         #
-        memo = {}
-        newboxes = []
+        if not we_are_translated() and op_fail.descr is None:  # for tests
+            op_fail.descr = Storage()
+            resume.ResumeDataBuilder()
+            resume.generate_boxes(op_fail.args)
+            resume.finish(op_fail.descr)
+        modifier = resume.ResumeDataVirtualAdder(op_fail.descr, op_fail.args)
         for box in op_fail.args:
-            try:
+            if box in self.values:
                 value = self.values[box]
-            except KeyError:
-                if box not in memo:
-                    newboxes.append(box)
-                    memo[box] = None
-            else:
-                value.get_args_for_fail(newboxes, memo)
-        # NB. we mutate op_fail in-place above.  That's bad.  Hopefully
+                value.get_args_for_fail(box, modifier)
+        newboxes = modifier.finish()
+        # NB. we mutate op_fail in-place below, as well as op_fail.descr
+        # via the ResumeDataVirtualAdder.  That's bad.  Hopefully
         # it does not really matter because no-one is going to look again
         # at its unoptimized version.  We cannot really clone it because of
         # how the rest works (e.g. it is returned by cpu.execute_operations()).
@@ -405,3 +406,6 @@
 
 
 optimize_ops = _findall(Optimizer, 'optimize_')
+
+class Storage:
+    "for tests."

Modified: pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/pyjitpl.py	Thu Jul 23 17:30:01 2009
@@ -1512,7 +1512,7 @@
         if not we_are_translated():
             self._debug_history.append(['guard_failure', None, None])
         vinfo = self.staticdata.virtualizable_info
-        resumereader = resume.ResumeDataReader(resumedescr, newboxes)
+        resumereader = resume.ResumeDataReader(resumedescr, newboxes, self)
         if vinfo is not None:
             self.virtualizable_boxes = resumereader.consume_boxes()
             # just jumped away from assembler (case 4 in the comment in

Modified: pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/resume.py
==============================================================================
--- pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/resume.py	(original)
+++ pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/resume.py	Thu Jul 23 17:30:01 2009
@@ -1,10 +1,14 @@
-from pypy.jit.metainterp.history import Box
+import sys
+from pypy.jit.metainterp.history import Box, Const
+from pypy.jit.metainterp.resoperation import rop
 
 # Logic to encode the chain of frames and the state of the boxes at a
-# FAIL operation, and to decode it again.
+# FAIL operation, and to decode it again.  This is a bit advanced,
+# because it needs to support optimize.py which encodes virtuals with
+# arbitrary cycles.
 
 # XXX I guess that building the data so that it is compact as possible
-# would be a big win.
+# on the 'storage' object would be a big win.
 
 
 class ResumeDataBuilder(object):
@@ -39,33 +43,135 @@
         storage.rd_frame_infos = self.frame_infos[:]
         storage.rd_nums = self.nums[:]
         storage.rd_consts = self.consts[:]
+        storage.rd_virtuals = None
         return self.liveboxes
 
 
+VIRTUAL_FLAG = int((sys.maxint+1) // 2)
+assert not (VIRTUAL_FLAG & (VIRTUAL_FLAG-1))    # a power of two
+
+class ResumeDataVirtualAdder(object):
+
+    def __init__(self, storage, liveboxes):
+        self.storage = storage
+        self.nums = storage.rd_nums[:]
+        self.consts = storage.rd_consts[:]
+        assert storage.rd_virtuals is None
+        self.original_liveboxes = liveboxes
+        self.liveboxes = {}
+        for box in liveboxes:
+            self.liveboxes[box] = 0
+        self.liveboxes_order = liveboxes[:]
+        self.virtuals = []
+        self.vfieldboxes = []
+
+    def make_constant(self, box, const):
+        assert self.liveboxes[box] == 0
+        self.liveboxes[box] = self._getconstindex(const)
+
+    def make_virtual(self, virtualbox, known_class, sizedescr,
+                     fielddescrs, fieldboxes):
+        assert self.liveboxes[virtualbox] == 0
+        self.liveboxes[virtualbox] = len(self.virtuals) | VIRTUAL_FLAG
+        vinfo = VirtualInfo(known_class, sizedescr, fielddescrs)
+        self.virtuals.append(vinfo)
+        self.vfieldboxes.append(fieldboxes)
+        for box in fieldboxes:
+            if isinstance(box, Box):
+                self.liveboxes.setdefault(box, 0)
+                self.liveboxes_order.append(box)
+
+    def is_virtual(self, virtualbox):
+        return self.liveboxes[virtualbox] >= VIRTUAL_FLAG
+
+    def finish(self):
+        storage = self.storage
+        liveboxes = []
+        for box in self.liveboxes_order:
+            if self.liveboxes[box] == 0:
+                self.liveboxes[box] = len(liveboxes)
+                liveboxes.append(box)
+        for i in range(len(storage.rd_nums)):
+            num = storage.rd_nums[i]
+            if num >= 0:
+                box = self.original_liveboxes[num]
+                storage.rd_nums[i] = self.liveboxes[box]
+        storage.rd_virtuals = self.virtuals[:]
+        for i in range(len(storage.rd_virtuals)):
+            vinfo = storage.rd_virtuals[i]
+            fieldboxes = self.vfieldboxes[i]
+            vinfo.fieldnums = [self._getboxindex(box) for box in fieldboxes]
+        storage.rd_consts = self.consts[:]
+        return liveboxes
+
+    def _getboxindex(self, box):
+        if isinstance(box, Const):
+            return self._getconstindex(box)
+        else:
+            return self.liveboxes[box]
+
+    def _getconstindex(self, const):
+        result = -2 - len(self.consts)
+        self.consts.append(const)
+        return result
+
+
+class VirtualInfo(object):
+    def __init__(self, known_class, sizedescr, fielddescrs):
+        self.known_class = known_class
+        self.sizedescr = sizedescr
+        self.fielddescrs = fielddescrs
+        #self.fieldnums = ...
+
+    def allocate(self, metainterp):
+        return metainterp.execute_and_record(rop.NEW_WITH_VTABLE,
+                                             [self.known_class],
+                                             descr=self.sizedescr)
+
+    def setfields(self, metainterp, box, fn_decode_box):
+        for i in range(len(self.fielddescrs)):
+            fieldbox = fn_decode_box(self.fieldnums[i])
+            metainterp.execute_and_record(rop.SETFIELD_GC,
+                                          [box, fieldbox],
+                                          descr=self.fielddescrs[i])
+
+
 class ResumeDataReader(object):
     i_frame_infos = 0
     i_boxes = 0
 
-    def __init__(self, storage, liveboxes):
+    def __init__(self, storage, liveboxes, metainterp=None):
         self.frame_infos = storage.rd_frame_infos
         self.nums = storage.rd_nums
         self.consts = storage.rd_consts
         self.liveboxes = liveboxes
+        if storage.rd_virtuals is not None:
+            self._prepare_virtuals(metainterp, storage.rd_virtuals)
+
+    def _prepare_virtuals(self, metainterp, virtuals):
+        self.virtuals = [vinfo.allocate(metainterp) for vinfo in virtuals]
+        for i in range(len(virtuals)):
+            vinfo = virtuals[i]
+            vinfo.setfields(metainterp, self.virtuals[i], self._decode_box)
 
     def consume_boxes(self):
         boxes = []
         while True:
             num = self.nums[self.i_boxes]
             self.i_boxes += 1
-            if num >= 0:
-                box = self.liveboxes[num]
-            elif num != -1:
-                box = self.consts[-2 - num]
-            else:
+            if num == -1:
                 break
-            boxes.append(box)
+            boxes.append(self._decode_box(num))
         return boxes
 
+    def _decode_box(self, num):
+        if num < 0:
+            return self.consts[-2 - num]
+        elif num & VIRTUAL_FLAG:
+            return self.virtuals[num - VIRTUAL_FLAG]
+        else:
+            return self.liveboxes[num]
+
     def has_more_frame_infos(self):
         return self.i_frame_infos < len(self.frame_infos)
 

Modified: pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/oparser.py
==============================================================================
--- pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/oparser.py	(original)
+++ pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/oparser.py	Thu Jul 23 17:30:01 2009
@@ -147,6 +147,8 @@
                 args.append(self.getvar(arg))
             except KeyError:
                 raise ParseError("Unknown var: %s" % arg)
+        if hasattr(descr, '_oparser_uses_descr'):
+            descr._oparser_uses_descr(self, args)
         return opnum, args, descr
 
     def parse_result_op(self, line):

Modified: pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_optimizeopt.py	(original)
+++ pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_optimizeopt.py	Thu Jul 23 17:30:01 2009
@@ -1,8 +1,11 @@
 import py
+from pypy.jit.metainterp.test.test_resume import MyMetaInterp
 from pypy.jit.metainterp.test.test_optimizefindnode import (LLtypeMixin,
                                                             OOtypeMixin,
                                                             BaseTest)
 from pypy.jit.metainterp.optimizeopt import optimize
+from pypy.jit.metainterp.history import AbstractDescr
+from pypy.jit.metainterp import resume
 from pypy.jit.metainterp.resoperation import rop, opname
 from pypy.jit.metainterp.test.oparser import parse
 
@@ -570,28 +573,55 @@
         self.optimize_loop(ops, 'Not', expected, i1=5,
                            boxkinds={'myptr': self.nodebox.value})
 
-    def test_expand_fail_arguments(self):
+    # ----------
+
+    def make_fail_descr(self, boxestext):
+        class FailDescr(AbstractDescr):
+            args_seen = []
+            def _oparser_uses_descr(self, oparse, args):
+                # typically called twice, before and after optimization
+                if len(self.args_seen) == 0:
+                    boxes = [oparse.box_for_var(boxtext.strip())
+                             for boxtext in boxestext.split(',')]
+                    builder = resume.ResumeDataBuilder()
+                    builder.generate_boxes(boxes)
+                    liveboxes = builder.finish(fdescr)
+                    assert liveboxes == args
+                self.args_seen.append((args, oparse))
+        #
+        fdescr = FailDescr()
+        self.fdescr = fdescr
+        self.namespace['fdescr'] = fdescr
+
+    def check_expanded_fail_descr(self, expectedtext):
+        fdescr = self.fdescr
+        args, oparse = fdescr.args_seen[-1]
+        reader = resume.ResumeDataReader(fdescr, args, MyMetaInterp())
+        boxes = reader.consume_boxes()
+        expected = [oparse.getvar(boxtext.strip())
+                    for boxtext in expectedtext.split(',')]
+        assert boxes == expected
+
+    def test_expand_fail_1(self):
+        self.make_fail_descr('i2, i3')
         ops = """
-        [i1, i2, i3, p3]
-        p1 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
-        p2 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
-        setfield_gc(p1, 1, descr=valuedescr)
-        setfield_gc(p1, p2, descr=nextdescr)
-        setfield_gc(p2, i2, descr=valuedescr)
-        setfield_gc(p2, p3, descr=nextdescr)
+        [i1, i3]
+        i2 = int_add(10, 5)
         guard_true(i1)
-            fail(p1, i3)
-        jump(i2, i1, i3, p3)
+            fail(i2, i3, descr=fdescr)
+        jump(i1, i3)
         """
         expected = """
-        [i1, i2, i3, p3]
+        [i1, i3]
         guard_true(i1)
-            fail(i2, p3, i3)
-        jump(i2, 1, i3, p3)
+            fail(i3, descr=fdescr)
+        jump(1, i3)
         """
-        self.optimize_loop(ops, 'Not, Not, Not, Not', expected, i1=1)
+        self.optimize_loop(ops, 'Not, Not', expected, i1=1, i2=15)
+        self.check_expanded_fail_descr('15, i3')
 
-    def test_expand_fail_loop(self):
+    def test_expand_fail_2(self):
+        py.test.skip("in-progress")
         ops = """
         [i1, i2]
         p1 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
@@ -604,12 +634,44 @@
         expected = """
         [i1, i2]
         guard_true(i1)
-            fail(i2)
+            p1 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
+            setfield_gc(p1, i2, descr=valuedescr)
+            setfield_gc(p1, p1, descr=nextdescr)
+            fail(p1)
         jump(1, i2)
         """
         self.optimize_loop(ops, 'Not, Not', expected, i1=1)
 
-    def test_expand_fail_duplicate(self):
+    def test_expand_fail_3(self):
+        py.test.skip("in-progress")
+        ops = """
+        [i1, i2, i3, p3]
+        p1 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
+        p2 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
+        setfield_gc(p1, 1, descr=valuedescr)
+        setfield_gc(p1, p2, descr=nextdescr)
+        setfield_gc(p2, i2, descr=valuedescr)
+        setfield_gc(p2, p3, descr=nextdescr)
+        guard_true(i1)
+            fail(p1, i3)
+        jump(i2, i1, i3, p3)
+        """
+        expected = """
+        [i1, i2, i3, p3]
+        guard_true(i1)
+            p1 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
+            p2 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
+            setfield_gc(p1, 1, descr=valuedescr)
+            setfield_gc(p1, p2, descr=nextdescr)
+            setfield_gc(p2, i2, descr=valuedescr)
+            setfield_gc(p2, p3, descr=nextdescr)
+            fail(p1, i3)
+        jump(i2, 1, i3, p3)
+        """
+        self.optimize_loop(ops, 'Not, Not, Not, Not', expected, i1=1)
+
+    def test_expand_fail_4(self):
+        py.test.skip("in-progress")
         ops = """
         [i1, i2]
         p1 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
@@ -624,17 +686,22 @@
         expected = """
         [i1, i2]
         guard_true(i1)
-            fail(i2)
+            p1 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
+            p2 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
+            setfield_gc(p1, i2, descr=valuedescr)
+            setfield_gc(p1, p2, descr=nextdescr)
+            setfield_gc(p2, i2, descr=valuedescr)
+            fail(%s)
         jump(1, i2)
         """
-        self.optimize_loop(ops % 'p1',         'Not, Not', expected, i1=1)
-        self.optimize_loop(ops % 'p1, i2',     'Not, Not', expected, i1=1)
-        self.optimize_loop(ops % 'p1, i2, i2', 'Not, Not', expected, i1=1)
-        self.optimize_loop(ops % 'i2, p1, i2', 'Not, Not', expected, i1=1)
-        self.optimize_loop(ops % 'i2, i2, p1', 'Not, Not', expected, i1=1)
-        self.optimize_loop(ops % 'p1, p1',     'Not, Not', expected, i1=1)
-        self.optimize_loop(ops % 'p1, p2',     'Not, Not', expected, i1=1)
-        self.optimize_loop(ops % 'p2, p1',     'Not, Not', expected, i1=1)
+        self.optimize_loop(ops      % 'p1',     'Not, Not',
+                           expected % 'p1',     i1=1)
+        self.optimize_loop(ops      % 'p1, i2', 'Not, Not',
+                           expected % 'p1, i2', i1=1)
+        self.optimize_loop(ops      % 'i2, p1', 'Not, Not',
+                           expected % 'i2, p1', i1=1)
+        self.optimize_loop(ops      % 'p1, p2', 'Not, Not',
+                           expected % 'p1, p2', i1=1)
 
 
 class TestLLtype(BaseTestOptimizeOpt, LLtypeMixin):

Modified: pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_resume.py
==============================================================================
--- pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_resume.py	(original)
+++ pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_resume.py	Thu Jul 23 17:30:01 2009
@@ -60,15 +60,40 @@
     def execute_and_record(self, opnum, argboxes, descr=None):
         return executor.execute(LLtypeMixin.cpu, opnum, argboxes, descr)
 
+demo55 = lltype.malloc(LLtypeMixin.NODE)
+demo55o = lltype.cast_opaque_ptr(llmemory.GCREF, demo55)
 
-def test_virtual_adder():
-    py.test.skip("not enabled")
-    # see r66529 in pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp
+
+def test_virtual_adder_no_op():
+    storage = make_demo_storage()
+    b1s, b2s, b3s = [BoxInt(1), BoxPtr(), BoxInt(3)]
+    modifier = ResumeDataVirtualAdder(storage, [b1s, b2s, b3s])
+    assert not modifier.is_virtual(b1s)
+    assert not modifier.is_virtual(b2s)
+    assert not modifier.is_virtual(b3s)
+    # done
+    liveboxes = modifier.finish()
+    assert liveboxes == [b1s, b2s, b3s]
+    #
+    b1t, b2t, b3t = [BoxInt(11), BoxPtr(demo55o), BoxInt(33)]
+    reader = ResumeDataReader(storage, [b1t, b2t, b3t], MyMetaInterp())
+    lst = reader.consume_boxes()
+    assert lst == [b1t, ConstInt(1), b1t, b2t]
+    lst = reader.consume_boxes()
+    assert lst == [ConstInt(2), ConstInt(3)]
+    lst = reader.consume_boxes()
+    assert lst == [b1t, b2t, b3t]
+
+
+def test_virtual_adder_make_virtual():
     storage = make_demo_storage()
     b1s, b2s, b3s, b4s, b5s = [BoxInt(1), BoxPtr(), BoxInt(3),
                                BoxPtr(), BoxPtr()]
     c1s = ConstInt(111)
     modifier = ResumeDataVirtualAdder(storage, [b1s, b2s, b3s])
+    assert not modifier.is_virtual(b1s)
+    assert not modifier.is_virtual(b2s)
+    assert not modifier.is_virtual(b3s)
     modifier.make_virtual(b2s,
                           ConstAddr(LLtypeMixin.node_vtable_adr,
                                     LLtypeMixin.cpu),
@@ -82,24 +107,23 @@
                           [LLtypeMixin.nextdescr, LLtypeMixin.valuedescr,
                                                   LLtypeMixin.otherdescr],
                           [b2s, b3s, b5s])  # new fields
+    assert not modifier.is_virtual(b1s)
+    assert     modifier.is_virtual(b2s)
+    assert not modifier.is_virtual(b3s)
+    assert     modifier.is_virtual(b4s)
+    assert not modifier.is_virtual(b5s)
     # done
     liveboxes = modifier.finish()
-    # we get 'liveboxes' in an unspecified order
-    sortedliveboxes = liveboxes[:]
-    sortedliveboxes.sort(key=lambda box: box.value)
-    assert sortedliveboxes == [b1s,
-                               #b2s -- virtual
-                               b3s,
-                               #b4s -- virtual
-                               #b2s -- again, shared
-                               #b3s -- again, shared
-                               b5s]
+    assert liveboxes == [b1s,
+                         #b2s -- virtual
+                         b3s,
+                         #b4s -- virtual
+                         #b2s -- again, shared
+                         #b3s -- again, shared
+                         b5s]
     #
-    demo55 = lltype.malloc(LLtypeMixin.NODE)
-    demo55o = lltype.cast_opaque_ptr(llmemory.GCREF, demo55)
     b1t, b3t, b5t = [BoxInt(11), BoxInt(33), BoxPtr(demo55o)]
-    newliveboxes = [{b1s:b1t, b3s:b3t, b5s:b5t}[bs] for bs in liveboxes]
-    reader = ResumeDataReader(storage, newliveboxes, MyMetaInterp())
+    reader = ResumeDataReader(storage, [b1t, b3t, b5t], MyMetaInterp())
     lst = reader.consume_boxes()
     b2t = lst[-1]
     assert lst == [b1t, ConstInt(1), b1t, b2t]
@@ -116,3 +140,26 @@
     assert ptr2.other == demo55
     assert ptr2.parent.value == 33
     assert ptr2.parent.next == ptr
+
+
+def test_virtual_adder_make_constant():
+    storage = make_demo_storage()
+    b1s, b2s, b3s = [BoxInt(1), BoxPtr(), BoxInt(3)]
+    modifier = ResumeDataVirtualAdder(storage, [b1s, b2s, b3s])
+    modifier.make_constant(b1s, ConstInt(111))           # <-------
+    assert not modifier.is_virtual(b1s)
+    assert not modifier.is_virtual(b2s)
+    assert not modifier.is_virtual(b3s)
+    # done
+    liveboxes = modifier.finish()
+    assert liveboxes == [b2s, b3s]
+    #
+    b2t, b3t = [BoxPtr(demo55o), BoxInt(33)]
+    reader = ResumeDataReader(storage, [b2t, b3t], MyMetaInterp())
+    lst = reader.consume_boxes()
+    c1t = ConstInt(111)
+    assert lst == [c1t, ConstInt(1), c1t, b2t]
+    lst = reader.consume_boxes()
+    assert lst == [ConstInt(2), ConstInt(3)]
+    lst = reader.consume_boxes()
+    assert lst == [c1t, b2t, b3t]



More information about the Pypy-commit mailing list