[pypy-svn] r69528 - in pypy/branch/compress-virtuals-resumedata2/pypy: . jit/backend/llgraph jit/backend/llvm/test jit/backend/test jit/backend/x86 jit/backend/x86/test jit/metainterp jit/metainterp/test objspace/std/test translator/c/test

pedronis at codespeak.net pedronis at codespeak.net
Mon Nov 23 11:05:17 CET 2009


Author: pedronis
Date: Mon Nov 23 11:05:16 2009
New Revision: 69528

Modified:
   pypy/branch/compress-virtuals-resumedata2/pypy/   (props changed)
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/llgraph/llimpl.py
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/llgraph/runner.py
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/llvm/test/conftest.py   (props changed)
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/test/runner_test.py
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/x86/assembler.py
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/x86/regalloc.py
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/x86/test/test_gc_integration.py   (props changed)
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/x86/test/test_virtual.py
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/compile.py
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/history.py
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/jitprof.py
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/logger.py   (props changed)
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/optimizeopt.py
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/resume.py
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_jitprof.py
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_optimizeopt.py
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_pyjitpl.py
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_resume.py
   pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_virtual.py
   pypy/branch/compress-virtuals-resumedata2/pypy/objspace/std/test/test_setobject.py   (props changed)
   pypy/branch/compress-virtuals-resumedata2/pypy/translator/c/test/test_refcount.py   (props changed)
Log:
merge the work done on the original branch here

Modified: pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/llgraph/llimpl.py
==============================================================================
--- pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/llgraph/llimpl.py	(original)
+++ pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/llgraph/llimpl.py	Mon Nov 23 11:05:16 2009
@@ -364,7 +364,10 @@
     op = loop.operations[-1]
     if op.fail_args is None:
         op.fail_args = []
-    op.fail_args.append(_variables[intvar])
+    if intvar == -1:
+        op.fail_args.append(None)
+    else:
+        op.fail_args.append(_variables[intvar])
 
 def compile_redirect_fail(old_loop, old_index, new_loop):
     old_loop = _from_opaque(old_loop)
@@ -407,23 +410,27 @@
                 except GuardFailed:
                     assert op.is_guard()
                     _stats.exec_conditional_jumps += 1
-                    if op.fail_args:
-                        args = [self.getenv(v) for v in op.fail_args]
-                    else:
-                        args = []
                     if op.jump_target is not None:
                         # a patched guard, pointing to further code
+                        args = [self.getenv(v) for v in op.fail_args if v]
                         assert len(op.jump_target.inputargs) == len(args)
                         self.env = dict(zip(op.jump_target.inputargs, args))
                         operations = op.jump_target.operations
                         opindex = 0
                         continue
                     else:
+                        fail_args = []
+                        if op.fail_args:
+                            for fail_arg in op.fail_args:
+                                if fail_arg is None:
+                                    fail_args.append(None)
+                                else:
+                                    fail_args.append(self.getenv(fail_arg))
                         # a non-patched guard
                         if self.verbose:
                             log.trace('failed: %s' % (
-                                ', '.join(map(str, args)),))
-                        self.fail_args = args
+                                ', '.join(map(str, fail_args)),))
+                        self.fail_args = fail_args
                         return op.fail_index
                 #verbose = self.verbose
                 assert (result is None) == (op.result is None)

Modified: pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/llgraph/runner.py
==============================================================================
--- pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/llgraph/runner.py	(original)
+++ pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/llgraph/runner.py	Mon Nov 23 11:05:16 2009
@@ -171,7 +171,10 @@
                 index = llimpl.compile_add_fail(c, fail_index)
                 faildescr._compiled_fail = c, index
                 for box in op.fail_args:
-                    llimpl.compile_add_fail_arg(c, var2index[box])
+                    if box is not None:
+                        llimpl.compile_add_fail_arg(c, var2index[box])
+                    else:
+                        llimpl.compile_add_fail_arg(c, -1)
             x = op.result
             if x is not None:
                 if isinstance(x, history.BoxInt):

Modified: pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/test/runner_test.py
==============================================================================
--- pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/test/runner_test.py	(original)
+++ pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/test/runner_test.py	Mon Nov 23 11:05:16 2009
@@ -125,6 +125,27 @@
         res = self.cpu.get_latest_value_int(0)
         assert res == 10
 
+    def test_compile_with_holes_in_fail_args(self):
+        i0 = BoxInt()
+        i1 = BoxInt()
+        i2 = BoxInt()
+        looptoken = LoopToken()
+        operations = [
+            ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1),
+            ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2),
+            ResOperation(rop.GUARD_TRUE, [i2], None, descr=BasicFailDescr(2)),
+            ResOperation(rop.JUMP, [i1], None, descr=looptoken),
+            ]
+        inputargs = [i0]
+        operations[2].fail_args = [None, None, i1, None]
+        
+        self.cpu.compile_loop(inputargs, operations, looptoken)
+        self.cpu.set_future_value_int(0, 2)
+        fail = self.cpu.execute_token(looptoken)
+        assert fail == 2
+        res = self.cpu.get_latest_value_int(2)
+        assert res == 10
+
     def test_backends_dont_keep_loops_alive(self):
         import weakref, gc
         self.cpu.dont_keepalive_stuff = True
@@ -183,6 +204,40 @@
         res = self.cpu.get_latest_value_int(0)
         assert res == 20
 
+    def test_compile_bridge_with_holes(self):
+        i0 = BoxInt()
+        i1 = BoxInt()
+        i2 = BoxInt()
+        faildescr1 = BasicFailDescr(1)
+        faildescr2 = BasicFailDescr(2)
+        looptoken = LoopToken()
+        operations = [
+            ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1),
+            ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2),
+            ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr1),
+            ResOperation(rop.JUMP, [i1], None, descr=looptoken),
+            ]
+        inputargs = [i0]
+        operations[2].fail_args = [None, i1, None]
+        self.cpu.compile_loop(inputargs, operations, looptoken)
+
+        i1b = BoxInt()
+        i3 = BoxInt()
+        bridge = [
+            ResOperation(rop.INT_LE, [i1b, ConstInt(19)], i3),
+            ResOperation(rop.GUARD_TRUE, [i3], None, descr=faildescr2),
+            ResOperation(rop.JUMP, [i1b], None, descr=looptoken),
+        ]
+        bridge[1].fail_args = [i1b]
+
+        self.cpu.compile_bridge(faildescr1, [i1b], bridge)        
+
+        self.cpu.set_future_value_int(0, 2)
+        fail = self.cpu.execute_token(looptoken)
+        assert fail == 2
+        res = self.cpu.get_latest_value_int(0)
+        assert res == 20
+
     def test_finish(self):
         i0 = BoxInt()
         class UntouchableFailDescr(AbstractFailDescr):

Modified: pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/x86/assembler.py
==============================================================================
--- pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/x86/assembler.py	(original)
+++ pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/x86/assembler.py	Mon Nov 23 11:05:16 2009
@@ -738,7 +738,7 @@
         """ assert that all args are actually Boxes
         """
         for arg in args:
-            assert isinstance(arg, Box)
+            assert arg is None or isinstance(arg, Box)
 
     def implement_guard_recovery(self, guard_opnum, faildescr, failargs,
                                                                fail_locs):
@@ -754,6 +754,8 @@
         pos = mc.tell()
         for i in range(len(failargs)):
             arg = failargs[i]
+            if arg is None:
+                continue
             loc = locs[i]
             if isinstance(loc, REG):
                 if arg.type == FLOAT:
@@ -767,6 +769,8 @@
                     mc.MOV(heap(adr), loc)
         for i in range(len(failargs)):
             arg = failargs[i]
+            if arg is None:
+                continue
             loc = locs[i]
             if not isinstance(loc, REG):
                 if arg.type == FLOAT:

Modified: pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/x86/regalloc.py
==============================================================================
--- pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/x86/regalloc.py	(original)
+++ pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/x86/regalloc.py	Mon Nov 23 11:05:16 2009
@@ -203,7 +203,8 @@
 
     def possibly_free_vars(self, vars):
         for var in vars:
-            self.possibly_free_var(var)
+            if var is not None:
+                self.possibly_free_var(var)
 
     def make_sure_var_in_reg(self, var, forbidden_vars=[],
                              selected_reg=None, imm_fine=True,
@@ -239,9 +240,12 @@
     def _update_bindings(self, locs, inputargs):
         # XXX this should probably go to llsupport/regalloc.py
         used = {}
-        for i in range(len(inputargs)):
+        i = 0
+        for loc in locs:
+            if loc is None: # xxx bit kludgy
+                continue
             arg = inputargs[i]
-            loc = locs[i]
+            i += 1
             if arg.type == FLOAT:
                 if isinstance(loc, REG):
                     self.xrm.reg_bindings[arg] = loc
@@ -360,6 +364,8 @@
                     longevity[arg] = (start_live[arg], i)
             if op.is_guard():
                 for arg in op.fail_args:
+                    if arg is None: # hole
+                        continue
                     assert isinstance(arg, Box)
                     if arg not in start_live:
                         print "Bogus arg in guard %d at %d" % (op.opnum, i)
@@ -373,6 +379,8 @@
         return longevity
 
     def loc(self, v):
+        if v is None:
+            return None
         if v.type == FLOAT:
             return self.xrm.loc(v)
         return self.rm.loc(v)

Modified: pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/x86/test/test_virtual.py
==============================================================================
--- pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/x86/test/test_virtual.py	(original)
+++ pypy/branch/compress-virtuals-resumedata2/pypy/jit/backend/x86/test/test_virtual.py	Mon Nov 23 11:05:16 2009
@@ -1,4 +1,4 @@
-from pypy.jit.metainterp.test.test_virtual import VirtualTests
+from pypy.jit.metainterp.test.test_virtual import VirtualTests, VirtualMiscTests
 from pypy.jit.backend.x86.test.test_basic import Jit386Mixin
 
 class MyClass:
@@ -13,3 +13,8 @@
     @staticmethod
     def _new():
         return MyClass()
+
+class TestsVirtualMisc(Jit386Mixin, VirtualMiscTests):
+    # for the individual tests see
+    # ====> ../../../metainterp/test/test_virtual.py
+    pass

Modified: pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/compile.py
==============================================================================
--- pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/compile.py	(original)
+++ pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/compile.py	Mon Nov 23 11:05:16 2009
@@ -233,7 +233,12 @@
     def store_final_boxes(self, guard_op, boxes):
         guard_op.fail_args = boxes
         self.guard_opnum = guard_op.opnum
-        self.fail_arg_types = [box.type for box in boxes]
+        fail_arg_types = [history.HOLE] * len(boxes)
+        for i in range(len(boxes)):
+            box = boxes[i]
+            if box:
+                fail_arg_types[i] = box.type
+        self.fail_arg_types = fail_arg_types
 
     def handle_fail(self, metainterp_sd):
         from pypy.jit.metainterp.pyjitpl import MetaInterp

Modified: pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/history.py
==============================================================================
--- pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/history.py	(original)
+++ pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/history.py	Mon Nov 23 11:05:16 2009
@@ -15,6 +15,7 @@
 INT   = 'i'
 REF   = 'r'
 FLOAT = 'f'
+HOLE  = '_'
 
 FAILARGS_LIMIT = 1000
 
@@ -756,8 +757,9 @@
                     ops = op.descr._debug_suboperations
                     TreeLoop.check_consistency_of_branch(ops, seen.copy())
                 for box in op.fail_args or []:
-                    assert isinstance(box, Box)
-                    assert box in seen
+                    if box is not None:
+                        assert isinstance(box, Box)
+                        assert box in seen
             else:
                 assert op.fail_args is None
             box = op.result

Modified: pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/jitprof.py
==============================================================================
--- pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/jitprof.py	(original)
+++ pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/jitprof.py	Mon Nov 23 11:05:16 2009
@@ -20,6 +20,10 @@
 OPT_FORCINGS
 ABORT_TOO_LONG
 ABORT_BRIDGE
+NVIRTUALS
+NVHOLES
+NVREUSED
+NVRIGHTHOLES
 """
 
 def _setup():
@@ -175,6 +179,10 @@
         self._print_intline("forcings", cnt[OPT_FORCINGS])
         self._print_intline("trace too long", cnt[ABORT_TOO_LONG])
         self._print_intline("bridge abort", cnt[ABORT_BRIDGE])
+        self._print_intline("nvirtuals", cnt[NVIRTUALS])
+        self._print_intline("nvholes", cnt[NVHOLES])
+        self._print_intline("nvrightholes", cnt[NVRIGHTHOLES])
+        self._print_intline("nvreused", cnt[NVREUSED])
 
     def _print_line_time(self, string, i, tim):
         final = "%s:%s\t%d\t%f\n" % (string, " " * max(0, 13-len(string)), i, tim)

Modified: pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/optimizeopt.py	(original)
+++ pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/optimizeopt.py	Mon Nov 23 11:05:16 2009
@@ -2,7 +2,7 @@
      ConstFloat
 from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstObj, REF
 from pypy.jit.metainterp.resoperation import rop, ResOperation
-from pypy.jit.metainterp.jitprof import OPT_OPS, OPT_GUARDS, OPT_FORCINGS
+from pypy.jit.metainterp import jitprof
 from pypy.jit.metainterp.executor import execute_nonspec
 from pypy.jit.metainterp.specnode import SpecNode, NotSpecNode, ConstantSpecNode
 from pypy.jit.metainterp.specnode import AbstractVirtualStructSpecNode
@@ -62,6 +62,9 @@
     def get_args_for_fail(self, modifier):
         pass
 
+    def make_virtual_info(self, modifier, fieldnums):
+        raise NotImplementedError # should not be called on this level
+
     def is_constant(self):
         return self.level == LEVEL_CONSTANT
 
@@ -134,9 +137,10 @@
 
 
 class AbstractVirtualValue(OptValue):
-    _attrs_ = ('optimizer', 'keybox', 'source_op')
+    _attrs_ = ('optimizer', 'keybox', 'source_op', '_cached_vinfo')
     box = None
     level = LEVEL_NONNULL
+    _cached_vinfo = None
 
     def __init__(self, optimizer, keybox, source_op=None):
         self.optimizer = optimizer
@@ -155,6 +159,19 @@
             self._really_force()
         return self.box
 
+    def make_virtual_info(self, modifier, fieldnums):
+        vinfo = self._cached_vinfo 
+        if vinfo is not None and resume.tagged_list_eq(
+                vinfo.fieldnums, fieldnums):
+            return vinfo
+        vinfo = self._make_virtual(modifier)
+        vinfo.fieldnums = fieldnums
+        self._cached_vinfo = vinfo
+        return vinfo
+
+    def _make_virtual(self, modifier):
+        raise NotImplementedError("abstract base")
+
 
 class AbstractVirtualStructValue(AbstractVirtualValue):
     _attrs_ = ('_fields', '_cached_sorted_fields')
@@ -207,14 +224,11 @@
             # we have already seen the very same keybox
             lst = self._get_field_descr_list()
             fieldboxes = [self._fields[ofs].get_key_box() for ofs in lst]
-            self._make_virtual(modifier, lst, fieldboxes)
+            modifier.register_virtual_fields(self.keybox, fieldboxes)
             for ofs in lst:
                 fieldvalue = self._fields[ofs]
                 fieldvalue.get_args_for_fail(modifier)
 
-    def _make_virtual(self, modifier, fielddescrs, fieldboxes):
-        raise NotImplementedError
-
 
 class VirtualValue(AbstractVirtualStructValue):
     level = LEVEL_KNOWNCLASS
@@ -224,10 +238,9 @@
         assert isinstance(known_class, Const)
         self.known_class = known_class
 
-    def _make_virtual(self, modifier, fielddescrs, fieldboxes):
-        modifier.make_virtual(self.keybox, self.known_class,
-                              fielddescrs, fieldboxes)
-
+    def _make_virtual(self, modifier):
+        fielddescrs = self._get_field_descr_list()
+        return modifier.make_virtual(self.known_class, fielddescrs)
 
 class VStructValue(AbstractVirtualStructValue):
 
@@ -235,10 +248,9 @@
         AbstractVirtualStructValue.__init__(self, optimizer, keybox, source_op)
         self.structdescr = structdescr
 
-    def _make_virtual(self, modifier, fielddescrs, fieldboxes):
-        modifier.make_vstruct(self.keybox, self.structdescr,
-                              fielddescrs, fieldboxes)
-
+    def _make_virtual(self, modifier):
+        fielddescrs = self._get_field_descr_list()
+        return modifier.make_vstruct(self.structdescr, fielddescrs)
 
 class VArrayValue(AbstractVirtualValue):
 
@@ -282,11 +294,14 @@
             const = self.optimizer.new_const_item(self.arraydescr)
             for itemvalue in self._items:
                 itemboxes.append(itemvalue.get_key_box())
-            modifier.make_varray(self.keybox, self.arraydescr, itemboxes)
+            modifier.register_virtual_fields(self.keybox, itemboxes)
             for itemvalue in self._items:
                 if itemvalue is not self.constvalue:
                     itemvalue.get_args_for_fail(modifier)
 
+    def _make_virtual(self, modifier):
+        return modifier.make_varray(self.arraydescr)
+
 class __extend__(SpecNode):
     def setup_virtual_node(self, optimizer, box, newinputargs):
         raise NotImplementedError
@@ -359,7 +374,7 @@
         self.bool_boxes = {}
 
     def forget_numberings(self, virtualbox):
-        self.metainterp_sd.profiler.count(OPT_FORCINGS)
+        self.metainterp_sd.profiler.count(jitprof.OPT_FORCINGS)
         self.resumedata_memo.forget_numberings(virtualbox)
 
     def getinterned(self, box):
@@ -480,6 +495,8 @@
             else:
                 self.optimize_default(op)
         self.loop.operations = self.newoperations
+        # accumulate counters
+        self.resumedata_memo.update_counters(self.metainterp_sd.profiler)
 
     def emit_operation(self, op, must_clone=True):
         self.heap_op_optimizer.emitting_operation(op)
@@ -492,9 +509,9 @@
                         op = op.clone()
                         must_clone = False
                     op.args[i] = box
-        self.metainterp_sd.profiler.count(OPT_OPS)
+        self.metainterp_sd.profiler.count(jitprof.OPT_OPS)
         if op.is_guard():
-            self.metainterp_sd.profiler.count(OPT_GUARDS)
+            self.metainterp_sd.profiler.count(jitprof.OPT_GUARDS)
             self.store_final_boxes_in_guard(op)
         elif op.can_raise():
             self.exception_might_have_happened = True
@@ -507,7 +524,7 @@
         assert isinstance(descr, compile.ResumeGuardDescr)
         modifier = resume.ResumeDataVirtualAdder(descr, self.resumedata_memo)
         newboxes = modifier.finish(self.values)
-        if len(newboxes) > self.metainterp_sd.options.failargs_limit:
+        if len(newboxes) > self.metainterp_sd.options.failargs_limit: # XXX be careful here
             raise compile.GiveUp
         descr.store_final_boxes(op, newboxes)
         #

Modified: pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/pyjitpl.py	Mon Nov 23 11:05:16 2009
@@ -1683,21 +1683,20 @@
     def initialize_state_from_guard_failure(self, resumedescr, must_compile):
         # guard failure: rebuild a complete MIFrame stack
         self.in_recursion = -1 # always one portal around
-        inputargs = self.load_values_from_failure(resumedescr)
-        warmrunnerstate = self.staticdata.state
+        inputargs_and_holes = self.load_values_from_failure(resumedescr)
         if must_compile:
             self.history = history.History(self.cpu)
-            self.history.inputargs = inputargs
+            self.history.inputargs = [box for box in inputargs_and_holes if box]
             self.staticdata.profiler.start_tracing()
         else:
             self.staticdata.profiler.start_blackhole()
             self.history = None   # this means that is_blackholing() is true
-        self.rebuild_state_after_failure(resumedescr, inputargs)
+        self.rebuild_state_after_failure(resumedescr, inputargs_and_holes)
 
     def load_values_from_failure(self, resumedescr):
         cpu = self.cpu
         fail_arg_types = resumedescr.fail_arg_types
-        inputargs = []
+        inputargs_and_holes = []
         for i in range(len(fail_arg_types)):
             boxtype = fail_arg_types[i]
             if boxtype == history.INT:
@@ -1706,10 +1705,12 @@
                 box = cpu.ts.BoxRef(cpu.get_latest_value_ref(i))
             elif boxtype == history.FLOAT:
                 box = history.BoxFloat(cpu.get_latest_value_float(i))
+            elif boxtype == history.HOLE:
+                box = None
             else:
                 assert False, "bad box type: num=%d" % ord(boxtype)
-            inputargs.append(box)
-        return inputargs
+            inputargs_and_holes.append(box)
+        return inputargs_and_holes
 
     def initialize_virtualizable(self, original_boxes):
         vinfo = self.staticdata.virtualizable_info

Modified: pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/resume.py
==============================================================================
--- pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/resume.py	(original)
+++ pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/resume.py	Mon Nov 23 11:05:16 2009
@@ -1,6 +1,7 @@
 import sys, os
 from pypy.jit.metainterp.history import Box, Const, ConstInt, INT, REF
 from pypy.jit.metainterp.resoperation import rop
+from pypy.jit.metainterp import jitprof
 from pypy.rpython.lltypesystem import rffi
 from pypy.rlib import rarithmetic
 from pypy.rlib.objectmodel import we_are_translated
@@ -84,12 +85,21 @@
     # please rpython :(
     return rarithmetic.widen(x) == rarithmetic.widen(y)
 
+def tagged_list_eq(tl1, tl2):
+    if len(tl1) != len(tl2):
+        return False
+    for i in range(len(tl1)):
+        if not tagged_eq(tl1[i], tl2[i]):
+            return False
+    return True
+
 TAGCONST    = 0
 TAGINT      = 1
 TAGBOX      = 2
 TAGVIRTUAL  = 3
 
-UNASSIGNED = tag(-1, TAGBOX)
+UNASSIGNED = tag(-2 ** 12 - 1, TAGBOX)
+UNASSIGNEDVIRTUAL = tag(-2 ** 12 - 1, TAGVIRTUAL)
 NULLREF = tag(-1, TAGCONST)
 
 
@@ -101,6 +111,13 @@
         self.large_ints = {}
         self.refs = cpu.ts.new_ref_dict_2()
         self.numberings = {}
+        self.cached_boxes = {}
+        self.cached_virtuals = {}
+    
+        self.nvirtuals = 0
+        self.nvholes = 0
+        self.nvrightholes = 0
+        self.nvreused = 0
 
     def getconst(self, const):
         if const.type == INT:
@@ -135,6 +152,8 @@
         self.consts.append(const)
         return result
 
+    # env numbering
+
     def number(self, values, snapshot):
         if snapshot is None:
             return None, {}, 0
@@ -173,7 +192,42 @@
     def forget_numberings(self, virtualbox):
         # XXX ideally clear only the affected numberings
         self.numberings.clear()
+        self.clear_box_virtual_numbers()
+
+    # caching for virtuals and boxes inside them
+
+    def num_cached_boxes(self):
+        return len(self.cached_boxes)
+
+    def assign_number_to_box(self, box, boxes):
+        if box in self.cached_boxes:
+            num = self.cached_boxes[box]
+            boxes[-num-1] = box
+        else:
+            boxes.append(box)
+            num = -len(boxes)
+            self.cached_boxes[box] = num
+        return num
+
+    def num_cached_virtuals(self):
+        return len(self.cached_virtuals)
+
+    def assign_number_to_virtual(self, box):
+        if box in self.cached_virtuals:
+            num = self.cached_virtuals[box]
+        else:
+            num = self.cached_virtuals[box] = -len(self.cached_virtuals) - 1
+        return num
 
+    def clear_box_virtual_numbers(self):
+        self.cached_boxes.clear()
+        self.cached_virtuals.clear()
+
+    def update_counters(self, profiler):
+        profiler.count(jitprof.NVIRTUALS, self.nvirtuals)
+        profiler.count(jitprof.NVHOLES, self.nvholes)
+        profiler.count(jitprof.NVREUSED, self.nvreused)
+        profiler.count(jitprof.NVRIGHTHOLES, self.nvrightholes)
 
 _frame_info_placeholder = (None, 0, 0)
 
@@ -185,30 +239,19 @@
         #self.virtuals = []
         #self.vfieldboxes = []
 
-    def make_virtual(self, virtualbox, known_class, fielddescrs, fieldboxes):
-        vinfo = VirtualInfo(known_class, fielddescrs)
-        self._make_virtual(virtualbox, vinfo, fieldboxes)
-
-    def make_vstruct(self, virtualbox, typedescr, fielddescrs, fieldboxes):
-        vinfo = VStructInfo(typedescr, fielddescrs)
-        self._make_virtual(virtualbox, vinfo, fieldboxes)
-
-    def make_varray(self, virtualbox, arraydescr, itemboxes):
-        vinfo = VArrayInfo(arraydescr)
-        self._make_virtual(virtualbox, vinfo, itemboxes)
-
-    def _make_virtual(self, virtualbox, vinfo, fieldboxes):
-        if virtualbox in self.liveboxes_from_env:
-            tagged = self.liveboxes_from_env[virtualbox]
-            i, _ = untag(tagged)
-            assert self.virtuals[i] is None
-            self.virtuals[i] = vinfo
-            self.vfieldboxes[i] = fieldboxes
-        else:
-            tagged = tag(len(self.virtuals), TAGVIRTUAL)
-            self.virtuals.append(vinfo)
-            self.vfieldboxes.append(fieldboxes)
+    def make_virtual(self, known_class, fielddescrs):
+        return VirtualInfo(known_class, fielddescrs)
+
+    def make_vstruct(self, typedescr, fielddescrs):
+        return VStructInfo(typedescr, fielddescrs)
+
+    def make_varray(self, arraydescr):
+        return VArrayInfo(arraydescr)
+
+    def register_virtual_fields(self, virtualbox, fieldboxes):
+        tagged = self.liveboxes_from_env.get(virtualbox, UNASSIGNEDVIRTUAL)
         self.liveboxes[virtualbox] = tagged
+        self.vfieldboxes[virtualbox] = fieldboxes
         self._register_boxes(fieldboxes)
 
     def register_box(self, box):
@@ -234,7 +277,8 @@
     def finish(self, values):
         # compute the numbering
         storage = self.storage
-        numb, liveboxes_from_env, v = self.memo.number(values, storage.rd_snapshot)
+        numb, liveboxes_from_env, v = self.memo.number(values,
+                                                       storage.rd_snapshot)
         self.liveboxes_from_env = liveboxes_from_env
         self.liveboxes = {}
         storage.rd_numb = numb
@@ -243,8 +287,7 @@
         # collect liveboxes and virtuals
         n = len(liveboxes_from_env) - v
         liveboxes = [None]*n
-        self.virtuals = [None]*v
-        self.vfieldboxes = [None]*v
+        self.vfieldboxes = {}
         for box, tagged in liveboxes_from_env.iteritems():
             i, tagbits = untag(tagged)
             if tagbits == TAGBOX:
@@ -254,31 +297,57 @@
                 value = values[box]
                 value.get_args_for_fail(self)
 
-        self._number_virtuals(liveboxes)
+        self._number_virtuals(liveboxes, values, v)
 
         storage.rd_consts = self.memo.consts
         dump_storage(storage, liveboxes)
         return liveboxes[:]
 
-    def _number_virtuals(self, liveboxes):
+    def _number_virtuals(self, liveboxes, values, num_env_virtuals):
+        memo = self.memo
+        new_liveboxes = [None] * memo.num_cached_boxes()
         for box, tagged in self.liveboxes.iteritems():
             i, tagbits = untag(tagged)
             if tagbits == TAGBOX:
+                assert box not in self.liveboxes_from_env
                 assert tagged_eq(tagged, UNASSIGNED)
-                self.liveboxes[box] = tag(len(liveboxes), TAGBOX)
-                liveboxes.append(box)
+                index = memo.assign_number_to_box(box, new_liveboxes)
+                self.liveboxes[box] = tag(index, TAGBOX)
             else:
                 assert tagbits == TAGVIRTUAL
+                if tagged_eq(tagged, UNASSIGNEDVIRTUAL):
+                    assert box not in self.liveboxes_from_env
+                    index = memo.assign_number_to_virtual(box)
+                    self.liveboxes[box] = tag(index, TAGVIRTUAL)
+        new_liveboxes.reverse()
+        liveboxes.extend(new_liveboxes)
 
         storage = self.storage
         storage.rd_virtuals = None
-        if len(self.virtuals) > 0:
-            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._gettagged(box)
-                                   for box in fieldboxes]
+        vfieldboxes = self.vfieldboxes
+        if vfieldboxes:
+            length = num_env_virtuals + memo.num_cached_virtuals()
+            virtuals = storage.rd_virtuals = [None] * length
+            memo.nvirtuals += length
+            memo.nvholes += length - len(vfieldboxes)
+            for virtualbox, fieldboxes in vfieldboxes.iteritems():
+                num, _ = untag(self.liveboxes[virtualbox])
+                value = values[virtualbox]
+                fieldnums = [self._gettagged(box)
+                             for box in fieldboxes]
+                vinfo = value.make_virtual_info(self, fieldnums)
+                # if a new vinfo instance is made, we get the fieldnums list we
+                # pass in as an attribute. hackish.
+                if vinfo.fieldnums is not fieldnums:
+                    memo.nvreused += 1
+                virtuals[num] = vinfo
+            # count right holes
+            r = 0
+            while r < length:
+                if virtuals[-1-r]:
+                    break
+                r += 1
+            memo.nvrightholes += r
 
     def _gettagged(self, box):
         if isinstance(box, Const):
@@ -392,10 +461,15 @@
 
     def _prepare_virtuals(self, metainterp, virtuals):
         if virtuals:
-            self.virtuals = [vinfo.allocate(metainterp) for vinfo in virtuals]
+            self.virtuals = [None] * len(virtuals)
             for i in range(len(virtuals)):
                 vinfo = virtuals[i]
-                vinfo.setfields(metainterp, self.virtuals[i], self._decode_box)
+                if vinfo is not None:
+                    self.virtuals[i] = vinfo.allocate(metainterp)
+            for i in range(len(virtuals)):
+                vinfo = virtuals[i]
+                if vinfo is not None:
+                    vinfo.setfields(metainterp, self.virtuals[i], self._decode_box)
 
     def consume_boxes(self):
         numb = self.cur_numb
@@ -450,8 +524,14 @@
         for const in storage.rd_consts:
             debug_print('\tconst', const.repr_rpython())
         for box in liveboxes:
-            debug_print('\tbox', box.repr_rpython())
+            if box is None:
+                debug_print('\tbox', 'None')
+            else:
+                debug_print('\tbox', box.repr_rpython())
         if storage.rd_virtuals is not None:
             for virtual in storage.rd_virtuals:
-                virtual.debug_prints()
+                if virtual is None:
+                    debug_print('\t\t', 'None')
+                else:
+                    virtual.debug_prints()
     debug_stop("jit-resume")

Modified: pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_jitprof.py
==============================================================================
--- pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_jitprof.py	(original)
+++ pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_jitprof.py	Mon Nov 23 11:05:16 2009
@@ -63,7 +63,8 @@
             ]
         assert profiler.events == expected
         assert profiler.times == [2, 1, 1, 1]
-        assert profiler.counters == [1, 1, 1, 1, 4, 3, 1, 1, 7, 1, 0, 0, 0]
+        assert profiler.counters == [1, 1, 1, 1, 4, 3, 1, 1, 7, 1, 0, 0, 0,
+                                     0, 0, 0, 0]
 
     def test_simple_loop_with_call(self):
         @dont_look_inside

Modified: pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_optimizeopt.py	(original)
+++ pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_optimizeopt.py	Mon Nov 23 11:05:16 2009
@@ -74,6 +74,22 @@
     lst2 = virt1._get_field_descr_list()
     assert lst1 is lst2
 
+def test_reuse_vinfo():
+    class FakeVInfo(object):
+        pass
+    class FakeVirtualValue(optimizeopt.AbstractVirtualValue):
+        def _make_virtual(self, *args):
+            return FakeVInfo()
+    v1 = FakeVirtualValue(None, None, None)
+    vinfo1 = v1.make_virtual_info(None, [1, 2, 4])
+    vinfo2 = v1.make_virtual_info(None, [1, 2, 4])
+    assert vinfo1 is vinfo2
+    vinfo3 = v1.make_virtual_info(None, [1, 2, 6])
+    assert vinfo3 is not vinfo2
+    vinfo4 = v1.make_virtual_info(None, [1, 2, 6])
+    assert vinfo3 is vinfo4
+    
+
 # ____________________________________________________________
 
 def equaloplists(oplist1, oplist2, strict_fail_args=True, remap={}):

Modified: pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_pyjitpl.py
==============================================================================
--- pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_pyjitpl.py	(original)
+++ pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_pyjitpl.py	Mon Nov 23 11:05:16 2009
@@ -1,7 +1,8 @@
 
 # some unit tests for the bytecode decoding
 
-from pypy.jit.metainterp import pyjitpl, codewriter, resoperation
+from pypy.jit.metainterp import pyjitpl, codewriter, resoperation, history
+from pypy.jit.metainterp import jitprof
 from pypy.jit.metainterp.history import AbstractFailDescr, BoxInt, ConstInt
 from pypy.jit.metainterp.history import History
 from pypy.jit.metainterp.resoperation import ResOperation, rop
@@ -154,3 +155,39 @@
     assert metainterp_sd.get_name_from_address(123) == 'a'
     assert metainterp_sd.get_name_from_address(456) == 'b'
     assert metainterp_sd.get_name_from_address(789) == ''
+
+def test_initialize_state_from_guard_failure():
+    from pypy.jit.metainterp.typesystem import llhelper        
+    calls = []
+
+    class FakeCPU:
+        ts = llhelper
+
+        def get_latest_value_int(self, index):
+            return index
+        
+    class FakeStaticData:
+        cpu = FakeCPU()
+        profiler = jitprof.EmptyProfiler()
+
+    metainterp = pyjitpl.MetaInterp(FakeStaticData())
+
+    def rebuild_state_after_failure(descr, newboxes):
+        calls.append(newboxes)
+    metainterp.rebuild_state_after_failure = rebuild_state_after_failure
+    
+    class FakeResumeDescr:
+        pass
+    resumedescr = FakeResumeDescr()
+    resumedescr.fail_arg_types = [history.INT, history.HOLE,
+                                  history.INT, history.HOLE,
+                                  history.INT]
+
+    metainterp.initialize_state_from_guard_failure(resumedescr, True)
+
+    inp = metainterp.history.inputargs
+    assert len(inp) == 3
+    assert [box.value for box in inp] == [0, 2, 4]
+    b0, b2, b4 = inp
+    assert len(calls) == 1
+    assert calls[0] == [b0, None, b2, None, b4]

Modified: pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_resume.py
==============================================================================
--- pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_resume.py	(original)
+++ pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_resume.py	Mon Nov 23 11:05:16 2009
@@ -1,6 +1,7 @@
 import py
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
-from pypy.jit.metainterp.optimizeopt import VirtualValue, OptValue
+from pypy.jit.metainterp.optimizeopt import VirtualValue, OptValue, VArrayValue
+from pypy.jit.metainterp.optimizeopt import VStructValue
 from pypy.jit.metainterp.resume import *
 from pypy.jit.metainterp.history import BoxInt, BoxPtr, ConstInt, ConstAddr
 from pypy.jit.metainterp.history import ConstPtr, ConstFloat
@@ -33,6 +34,12 @@
     assert tagged_eq(UNASSIGNED, UNASSIGNED)
     assert not tagged_eq(tag(1, TAGBOX), UNASSIGNED)
 
+def test_tagged_list_eq():
+    assert tagged_list_eq([UNASSIGNED, tag(1, TAGBOX), tag(-2, TAGVIRTUAL)],
+                          [UNASSIGNED, tag(1, TAGBOX), tag(-2, TAGVIRTUAL)])
+    assert not tagged_list_eq([tag(1, TAGBOX)], [tag(-2, TAGBOX)])
+    assert not tagged_list_eq([tag(1, TAGBOX), tag(-2, TAGBOX)], [tag(1, TAGBOX)])
+
 class MyMetaInterp:
     def __init__(self, cpu=None):
         if cpu is None:
@@ -105,6 +112,22 @@
     lst = reader.consume_boxes()
     assert lst == [b1s, b2s, b3s]
 
+
+def test_prepare_virtuals():
+    class FakeVinfo(object):
+        def allocate(self, metainterp):
+            return "allocated"
+        def setfields(self, metainterp, virtual, func):
+            assert virtual == "allocated"
+    class FakeStorage(object):
+        rd_virtuals = [FakeVinfo(), None]
+        rd_numb = []
+        rd_consts = []
+    class FakeMetainterp(object):
+        cpu = None
+    reader = ResumeDataReader(FakeStorage(), [], FakeMetainterp())
+    assert reader.virtuals == ["allocated", None]
+
 # ____________________________________________________________
 
 
@@ -356,20 +379,21 @@
     modifier = ResumeDataVirtualAdder(storage, memo)
     liveboxes = modifier.finish(values)
     assert len(storage.rd_virtuals) == 1
-    assert storage.rd_virtuals[0].fieldnums == [tag(len(liveboxes)-1, TAGBOX),
+    assert storage.rd_virtuals[0].fieldnums == [tag(-1, TAGBOX),
                                                 tag(0, TAGCONST)]
 
     b6 = BoxPtr()
     v6 = virtual_value(b6, c2, None)
     v6.setfield(LLtypeMixin.nextdescr, v6)    
     values = {b2: virtual_value(b2, b4, v6), b6: v6}
+    memo.clear_box_virtual_numbers()
     modifier = ResumeDataVirtualAdder(storage2, memo)
     liveboxes2 = modifier.finish(values)
     assert len(storage2.rd_virtuals) == 2    
     assert storage2.rd_virtuals[0].fieldnums == [tag(len(liveboxes2)-1, TAGBOX),
-                                                 tag(1, TAGVIRTUAL)]
+                                                 tag(-1, TAGVIRTUAL)]
     assert storage2.rd_virtuals[1].fieldnums == [tag(2, TAGINT),
-                                                 tag(1, TAGVIRTUAL)]
+                                                 tag(-1, TAGVIRTUAL)]
 
     # now on to resuming
     metainterp = MyMetaInterp()
@@ -398,6 +422,33 @@
            FakeFrame("code2", 10, -1, c3, b2t, b4t)]
     assert metainterp.framestack == fs2    
 
+def test_rebuild_from_resumedata_two_guards_w_shared_virtuals():
+    b1, b2, b3, b4, b5, b6 = [BoxPtr(), BoxPtr(), BoxInt(), BoxPtr(), BoxInt(), BoxInt()]
+    c1, c2, c3, c4 = [ConstInt(1), ConstInt(2), ConstInt(3),
+                      LLtypeMixin.nodebox.constbox()]
+    storage = Storage()
+    fs = [FakeFrame("code0", 0, -1, c1, b2, b3)]
+    capture_resumedata(fs, None, storage)
+    
+    memo = ResumeDataLoopMemo(LLtypeMixin.cpu)
+    values = {b2: virtual_value(b2, b5, c4)}
+    modifier = ResumeDataVirtualAdder(storage, memo)
+    liveboxes = modifier.finish(values)
+    assert len(storage.rd_virtuals) == 1
+    assert storage.rd_virtuals[0].fieldnums == [tag(-1, TAGBOX),
+                                                tag(0, TAGCONST)]
+
+    storage2 = Storage()
+    fs = [FakeFrame("code0", 0, -1, b1, b4, b2)]
+    capture_resumedata(fs, None, storage2)
+    values[b4] = virtual_value(b4, b6, c4)
+    modifier = ResumeDataVirtualAdder(storage2, memo)
+    liveboxes = modifier.finish(values)
+    assert len(storage2.rd_virtuals) == 2
+    assert storage2.rd_virtuals[1].fieldnums == storage.rd_virtuals[0].fieldnums
+    assert storage2.rd_virtuals[1] is storage.rd_virtuals[0]
+    
+
 def test_resumedata_top_recursive_virtuals():
     b1, b2, b3 = [BoxPtr(), BoxPtr(), BoxInt()]
     storage = Storage()
@@ -413,9 +464,9 @@
     liveboxes = modifier.finish(values)
     assert liveboxes == [b3]
     assert len(storage.rd_virtuals) == 2
-    assert storage.rd_virtuals[0].fieldnums == [tag(0, TAGBOX),
+    assert storage.rd_virtuals[0].fieldnums == [tag(-1, TAGBOX),
                                                 tag(1, TAGVIRTUAL)]
-    assert storage.rd_virtuals[1].fieldnums == [tag(0, TAGBOX),
+    assert storage.rd_virtuals[1].fieldnums == [tag(-1, TAGBOX),
                                                 tag(0, TAGVIRTUAL)]    
 
 
@@ -553,31 +604,76 @@
                                           tag(1, TAGVIRTUAL)]
     assert numb5.prev is numb4
 
+def test_ResumeDataLoopMemo_number_boxes():
+    memo = ResumeDataLoopMemo(LLtypeMixin.cpu)
+    b1, b2 = [BoxInt(), BoxInt()]
+    assert memo.num_cached_boxes() == 0
+    boxes = []
+    num = memo.assign_number_to_box(b1, boxes)
+    assert num == -1
+    assert boxes == [b1]
+    assert memo.num_cached_boxes() == 1
+    boxes = [None]
+    num = memo.assign_number_to_box(b1, boxes)
+    assert num == -1
+    assert boxes == [b1]
+    num = memo.assign_number_to_box(b2, boxes)
+    assert num == -2
+    assert boxes == [b1, b2]
+
+    assert memo.num_cached_boxes() == 2
+    boxes = [None, None]
+    num = memo.assign_number_to_box(b2, boxes)
+    assert num == -2
+    assert boxes == [None, b2]
+    num = memo.assign_number_to_box(b1, boxes)
+    assert num == -1
+    assert boxes == [b1, b2]
+
+    memo.clear_box_virtual_numbers()
+    assert memo.num_cached_boxes() == 0
+
+def test_ResumeDataLoopMemo_number_virtuals():
+    memo = ResumeDataLoopMemo(LLtypeMixin.cpu)
+    b1, b2 = [BoxInt(), BoxInt()]
+    assert memo.num_cached_virtuals() == 0
+    num = memo.assign_number_to_virtual(b1)
+    assert num == -1
+    assert memo.num_cached_virtuals() == 1
+    num = memo.assign_number_to_virtual(b1)
+    assert num == -1
+    num = memo.assign_number_to_virtual(b2)
+    assert num == -2
+
+    assert memo.num_cached_virtuals() == 2
+    num = memo.assign_number_to_virtual(b2)
+    assert num == -2
+    num = memo.assign_number_to_virtual(b1)
+    assert num == -1
+
+    memo.clear_box_virtual_numbers()
+    assert memo.num_cached_virtuals() == 0
 
-def test__make_virtual():
+def test_register_virtual_fields():
     b1, b2 = BoxInt(), BoxInt()
     vbox = BoxPtr()
     modifier = ResumeDataVirtualAdder(None, None)
     modifier.liveboxes_from_env = {}
     modifier.liveboxes = {}
-    modifier.virtuals = []
-    modifier.vfieldboxes = []
-    modifier.make_virtual(vbox, None, ['a', 'b'], [b1, b2])
-    assert modifier.liveboxes == {vbox: tag(0, TAGVIRTUAL), b1: UNASSIGNED,
+    modifier.vfieldboxes = {}
+    modifier.register_virtual_fields(vbox, [b1, b2])
+    assert modifier.liveboxes == {vbox: UNASSIGNEDVIRTUAL, b1: UNASSIGNED,
                                   b2: UNASSIGNED}
-    assert len(modifier.virtuals) == 1
-    assert modifier.vfieldboxes == [[b1, b2]]
+    assert modifier.vfieldboxes == {vbox: [b1, b2]}
 
     modifier = ResumeDataVirtualAdder(None, None)
     modifier.liveboxes_from_env = {vbox: tag(0, TAGVIRTUAL)}
     modifier.liveboxes = {}
-    modifier.virtuals = [None]
-    modifier.vfieldboxes = [None]
-    modifier.make_virtual(vbox, None, ['a', 'b', 'c'], [b1, b2, vbox])
+    modifier.vfieldboxes = {}
+    modifier.register_virtual_fields(vbox, [b1, b2, vbox])
     assert modifier.liveboxes == {b1: UNASSIGNED, b2: UNASSIGNED,
                                   vbox: tag(0, TAGVIRTUAL)}
-    assert len(modifier.virtuals) == 1
-    assert modifier.vfieldboxes == [[b1, b2, vbox]]    
+    assert modifier.vfieldboxes == {vbox: [b1, b2, vbox]}
 
 def _resume_remap(liveboxes, expected, *newvalues):
     newboxes = []
@@ -692,22 +788,26 @@
     modifier = ResumeDataVirtualAdder(storage, memo)
     modifier.liveboxes_from_env = {}
     modifier.liveboxes = {}
-    modifier.virtuals = []
-    modifier.vfieldboxes = []
-    modifier.make_virtual(b2s,
-                          ConstAddr(LLtypeMixin.node_vtable_adr,
-                                    LLtypeMixin.cpu),
-                          [LLtypeMixin.nextdescr, LLtypeMixin.valuedescr],
-                          [b4s, c1s])   # new fields
-    modifier.make_virtual(b4s,
-                          ConstAddr(LLtypeMixin.node_vtable_adr2,
-                                    LLtypeMixin.cpu),
-                          [LLtypeMixin.nextdescr, LLtypeMixin.valuedescr,
-                                                  LLtypeMixin.otherdescr],
-                          [b2s, b3s, b5s])  # new fields
+    modifier.vfieldboxes = {}
+
+    v2 = VirtualValue(None, ConstAddr(LLtypeMixin.node_vtable_adr,
+                                                LLtypeMixin.cpu), b2s)
+    v2._fields = {LLtypeMixin.nextdescr: b4s,
+                  LLtypeMixin.valuedescr: c1s}
+    v2._cached_sorted_fields = [LLtypeMixin.nextdescr, LLtypeMixin.valuedescr]
+    v4 = VirtualValue(None, ConstAddr(LLtypeMixin.node_vtable_adr2,
+                                                LLtypeMixin.cpu), b4s)
+    v4._fields = {LLtypeMixin.nextdescr: b2s,
+                  LLtypeMixin.valuedescr: b3s,
+                  LLtypeMixin.otherdescr: b5s}
+    v4._cached_sorted_fields = [LLtypeMixin.nextdescr, LLtypeMixin.valuedescr,
+                                LLtypeMixin.otherdescr]
+    modifier.register_virtual_fields(b2s, [b4s, c1s])
+    modifier.register_virtual_fields(b4s, [b2s, b3s, b5s])
+    values = {b2s: v2, b4s: v4}
 
     liveboxes = []
-    modifier._number_virtuals(liveboxes)
+    modifier._number_virtuals(liveboxes, values, 0)
     storage.rd_consts = memo.consts[:]
     storage.rd_numb = None
     # resume
@@ -722,22 +822,25 @@
     metainterp = MyMetaInterp()
     reader = ResumeDataReader(storage, newboxes, metainterp)
     assert len(reader.virtuals) == 2
-    b2t = reader._decode_box(tag(0, TAGVIRTUAL))
-    b4t = reader._decode_box(tag(1, TAGVIRTUAL))
+    b2t = reader._decode_box(modifier._gettagged(b2s))
+    b4t = reader._decode_box(modifier._gettagged(b4s))
     trace = metainterp.trace
-    expected =  [
-        (rop.NEW_WITH_VTABLE, [ConstAddr(LLtypeMixin.node_vtable_adr,
+    b2new = (rop.NEW_WITH_VTABLE, [ConstAddr(LLtypeMixin.node_vtable_adr,
                                          LLtypeMixin.cpu)],
-                              b2t, None),
-        (rop.NEW_WITH_VTABLE, [ConstAddr(LLtypeMixin.node_vtable_adr2,
+                              b2t, None)
+    b4new = (rop.NEW_WITH_VTABLE, [ConstAddr(LLtypeMixin.node_vtable_adr2,
                                          LLtypeMixin.cpu)],
-                              b4t, None),
-        (rop.SETFIELD_GC, [b2t, b4t],      None, LLtypeMixin.nextdescr),
-        (rop.SETFIELD_GC, [b2t, c1s],      None, LLtypeMixin.valuedescr),
-        (rop.SETFIELD_GC, [b4t, b2t],     None, LLtypeMixin.nextdescr),
-        (rop.SETFIELD_GC, [b4t, b3t],     None, LLtypeMixin.valuedescr),
-        (rop.SETFIELD_GC, [b4t, b5t],     None, LLtypeMixin.otherdescr),
-        ]
+                              b4t, None)
+    b2set = [(rop.SETFIELD_GC, [b2t, b4t],      None, LLtypeMixin.nextdescr),
+             (rop.SETFIELD_GC, [b2t, c1s],      None, LLtypeMixin.valuedescr)]
+    b4set = [(rop.SETFIELD_GC, [b4t, b2t],     None, LLtypeMixin.nextdescr),
+             (rop.SETFIELD_GC, [b4t, b3t],     None, LLtypeMixin.valuedescr),
+             (rop.SETFIELD_GC, [b4t, b5t],     None, LLtypeMixin.otherdescr)]
+    if untag(modifier._gettagged(b2s))[0] == -2:
+        expected = [b2new, b4new] + b2set + b4set
+    else:
+        expected = [b4new, b2new] + b4set + b2set
+        
     for x, y in zip(expected, trace):
         assert x == y
     ptr = b2t.value._obj.container._as_ptr()
@@ -757,13 +860,17 @@
     modifier = ResumeDataVirtualAdder(storage, memo)
     modifier.liveboxes_from_env = {}
     modifier.liveboxes = {}
-    modifier.virtuals = []
-    modifier.vfieldboxes = []
-    modifier.make_varray(b2s,
-                         LLtypeMixin.arraydescr,
-                         [b4s, c1s])   # new fields
+    modifier.vfieldboxes = {}
+
+    class FakeOptimizer(object):
+        def new_const_item(self, descr):
+            return None
+    v2 = VArrayValue(FakeOptimizer(), LLtypeMixin.arraydescr, 2, b2s)
+    v2._items = [b4s, c1s]
+    modifier.register_virtual_fields(b2s, [b4s, c1s])
     liveboxes = []
-    modifier._number_virtuals(liveboxes)
+    values = {b2s: v2}
+    modifier._number_virtuals(liveboxes, values, 0)
     dump_storage(storage, liveboxes)
     storage.rd_consts = memo.consts[:]
     storage.rd_numb = None
@@ -803,14 +910,13 @@
     modifier = ResumeDataVirtualAdder(storage, memo)
     modifier.liveboxes_from_env = {}
     modifier.liveboxes = {}
-    modifier.virtuals = []
-    modifier.vfieldboxes = []
-    modifier.make_vstruct(b2s,
-                          LLtypeMixin.ssize,
-                          [LLtypeMixin.adescr, LLtypeMixin.bdescr],
-                          [c1s, b4s])   # new fields
+    modifier.vfieldboxes = {}
+    v2 = VStructValue(None, LLtypeMixin.ssize, b2s)
+    v2._fields = {LLtypeMixin.adescr: c1s, LLtypeMixin.bdescr: b4s}
+    v2._cached_sorted_fields = [LLtypeMixin.adescr, LLtypeMixin.bdescr]
+    modifier.register_virtual_fields(b2s, [c1s, b4s])
     liveboxes = []
-    modifier._number_virtuals(liveboxes)
+    modifier._number_virtuals(liveboxes, {b2s: v2}, 0)
     dump_storage(storage, liveboxes)
     storage.rd_consts = memo.consts[:]
     storage.rd_numb = None

Modified: pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_virtual.py
==============================================================================
--- pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_virtual.py	(original)
+++ pypy/branch/compress-virtuals-resumedata2/pypy/jit/metainterp/test/test_virtual.py	Mon Nov 23 11:05:16 2009
@@ -304,6 +304,8 @@
         #    ENTER             - compile the leaving path
         self.check_enter_count(4)
 
+class VirtualMiscTests:
+
     def test_guards_around_forcing(self):
         class A(object):
             def __init__(self, x):
@@ -329,6 +331,29 @@
             return 0
         self.meta_interp(f, [50])
 
+    def test_guards_and_holes(self):
+        class A(object):
+            def __init__(self, x):
+                self.x = x
+        mydriver = JitDriver(reds = ['n', 'tot'], greens = [])
+
+        def f(n):
+            tot = 0
+            while n > 0:
+                mydriver.can_enter_jit(n=n, tot=tot)
+                mydriver.jit_merge_point(n=n, tot=tot)
+                a = A(n)
+                b = A(n+1)
+                if n % 9 == 0:
+                    tot += (a.x + b.x) % 3
+                c = A(n+1)
+                if n % 10 == 0:
+                    tot -= (c.x + a.x) % 3
+                n -= 1
+            return tot
+        r = self.meta_interp(f, [70])
+        expected = f(70)
+        assert r == expected
 
 # ____________________________________________________________
 # Run 1: all the tests instantiate a real RPython class
@@ -435,3 +460,11 @@
         p = lltype.malloc(NODE2)
         p.parent.typeptr = vtable2
         return p
+
+# misc
+
+class TestOOTypeMisc(VirtualMiscTests, OOJitMixin):
+    pass
+
+class TestLLTypeMisc(VirtualMiscTests, LLJitMixin):
+    pass



More information about the Pypy-commit mailing list