Author: Carl Friedrich Bolz <cfb...@gmx.de>
Branch: optinfo-into-bridges
Changeset: r87847:50dd16dbcea8
Date: 2016-10-17 15:52 +0200
http://bitbucket.org/pypy/pypy/changeset/50dd16dbcea8/

Log:    encode pending fields into the resume code

        (it's more compact and saves one word on every guard)

diff --git a/rpython/jit/metainterp/compile.py 
b/rpython/jit/metainterp/compile.py
--- a/rpython/jit/metainterp/compile.py
+++ b/rpython/jit/metainterp/compile.py
@@ -17,8 +17,7 @@
     TargetToken, AbstractFailDescr, ConstInt)
 from rpython.jit.metainterp import history, jitexc
 from rpython.jit.metainterp.optimize import InvalidLoop
-from rpython.jit.metainterp.resume import (PENDINGFIELDSP,
-        ResumeDataDirectReader, AccumInfo)
+from rpython.jit.metainterp.resume import ResumeDataDirectReader
 from rpython.jit.metainterp.resumecode import NUMBERING
 from rpython.jit.codewriter import heaptracker, longlong
 
@@ -864,18 +863,16 @@
 
 class ResumeGuardDescr(AbstractResumeGuardDescr):
     _attrs_ = ('rd_numb', 'rd_consts', 'rd_virtuals',
-               'rd_pendingfields', 'status')
+               'status')
     rd_numb = lltype.nullptr(NUMBERING)
     rd_consts = None
     rd_virtuals = None
-    rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO)
 
     def copy_all_attributes_from(self, other):
         if isinstance(other, ResumeGuardCopiedDescr):
             other = other.prev
         assert isinstance(other, ResumeGuardDescr)
         self.rd_consts = other.rd_consts
-        self.rd_pendingfields = other.rd_pendingfields
         self.rd_virtuals = other.rd_virtuals
         self.rd_numb = other.rd_numb
         # we don't copy status
diff --git a/rpython/jit/metainterp/optimizeopt/heap.py 
b/rpython/jit/metainterp/optimizeopt/heap.py
--- a/rpython/jit/metainterp/optimizeopt/heap.py
+++ b/rpython/jit/metainterp/optimizeopt/heap.py
@@ -227,6 +227,11 @@
         self.cached_infos = []
         self.cached_structs = []
 
+class PendingWrites(object):
+    def __init__(self, fields, arrays):
+        self.fields = fields
+        self.arrays = arrays
+
 class OptHeap(Optimization):
     """Cache repeated heap accesses"""
 
@@ -329,7 +334,7 @@
         if rop.is_ovf(op.opnum):
             return
         if rop.is_guard(op.opnum):
-            self.optimizer.pendingfields = (
+            self.optimizer.pendingwrites = (
                 self.force_lazy_sets_for_guard())
             return
         opnum = op.getopnum()
@@ -513,6 +518,7 @@
                 pendingfields.append(op)
                 continue
             cf.force_lazy_set(self, descr)
+        pendingarrays = []
         for descr, submap in self.cached_arrayitems.iteritems():
             for index, cf in submap.iteritems():
                 op = cf._lazy_set
@@ -525,10 +531,10 @@
                 opinfo = self.getptrinfo(op.getarg(0))
                 assert not opinfo.is_virtual()      # it must be a non-virtual
                 if self.optimizer.is_virtual(op.getarg(2)):
-                    pendingfields.append(op)
+                    pendingarrays.append(op)
                 else:
                     cf.force_lazy_set(self, descr)
-        return pendingfields
+        return PendingWrites(pendingfields, pendingarrays)
 
     def optimize_GETFIELD_GC_I(self, op):
         descr = op.getdescr()
diff --git a/rpython/jit/metainterp/optimizeopt/optimizer.py 
b/rpython/jit/metainterp/optimizeopt/optimizer.py
--- a/rpython/jit/metainterp/optimizeopt/optimizer.py
+++ b/rpython/jit/metainterp/optimizeopt/optimizer.py
@@ -274,8 +274,9 @@
         self.interned_refs = self.cpu.ts.new_ref_dict()
         self.interned_ints = {}
         self.resumedata_memo = resume.ResumeDataLoopMemo(metainterp_sd)
-        self.pendingfields = None # set temporarily to a list, normally by
-                                  # heap.py, as we're about to generate a guard
+        # set temporarily to an instance of heap.PendingWrites, normally by
+        # heap.py, as we're about to generate a guard
+        self.pendingwrites = None
         self.quasi_immutable_deps = None
         self.replaces_guard = {}
         self._newoperations = []
@@ -612,14 +613,14 @@
         if rop.is_guard(op.opnum):
             assert isinstance(op, GuardResOp)
             self.metainterp_sd.profiler.count(jitprof.Counters.OPT_GUARDS)
-            pendingfields = self.pendingfields
-            self.pendingfields = None
+            pendingwrites = self.pendingwrites
+            self.pendingwrites = None
             if self.replaces_guard and orig_op in self.replaces_guard:
                 self.replace_guard_op(self.replaces_guard[orig_op], op)
                 del self.replaces_guard[orig_op]
                 return
             else:
-                op = self.emit_guard_operation(op, pendingfields)
+                op = self.emit_guard_operation(op, pendingwrites)
         elif op.can_raise():
             self.exception_might_have_happened = True
         opnum = op.opnum
@@ -632,7 +633,7 @@
         self._really_emitted_operation = op
         self._newoperations.append(op)
 
-    def emit_guard_operation(self, op, pendingfields):
+    def emit_guard_operation(self, op, pendingwrites):
         guard_op = op # self.replace_op_with(op, op.getopnum())
         opnum = guard_op.getopnum()
         # If guard_(no)_exception is merged with another previous guard, then
@@ -652,7 +653,7 @@
             op = self._copy_resume_data_from(guard_op,
                                              self._last_guard_op)
         else:
-            op = self.store_final_boxes_in_guard(guard_op, pendingfields)
+            op = self.store_final_boxes_in_guard(guard_op, pendingwrites)
             self._last_guard_op = op
             # for unrolling
             for farg in op.getfailargs():
@@ -722,8 +723,7 @@
         new_descr.copy_all_attributes_from(old_descr)
         self._newoperations[old_op_pos] = new_op
 
-    def store_final_boxes_in_guard(self, op, pendingfields):
-        assert pendingfields is not None
+    def store_final_boxes_in_guard(self, op, pendingwrites):
         if op.getdescr() is not None:
             descr = op.getdescr()
             assert isinstance(descr, compile.ResumeGuardDescr)
@@ -735,11 +735,12 @@
         modifier = resume.ResumeDataVirtualAdder(self, descr, op, self.trace,
                                                  self.resumedata_memo)
         try:
-            newboxes = modifier.finish(pendingfields)
+            newboxes = modifier.finish(pendingwrites)
             if (newboxes is not None and
                 len(newboxes) > self.metainterp_sd.options.failargs_limit):
                 raise resume.TagOverflow
         except resume.TagOverflow:
+            #import pdb;pdb.xpm()
             raise compile.giveup()
         # check no duplicates
         #if not we_are_translated():
diff --git a/rpython/jit/metainterp/optimizeopt/simplify.py 
b/rpython/jit/metainterp/optimizeopt/simplify.py
--- a/rpython/jit/metainterp/optimizeopt/simplify.py
+++ b/rpython/jit/metainterp/optimizeopt/simplify.py
@@ -10,8 +10,7 @@
 
     def emit(self, op):
         if op.is_guard():
-            if self.optimizer.pendingfields is None:
-                self.optimizer.pendingfields = []
+            self.optimizer.pendingwrites = None
         return Optimization.emit(self, op)
 
     def optimize_CALL_PURE_I(self, op):
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py 
b/rpython/jit/metainterp/optimizeopt/test/test_util.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_util.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py
@@ -488,6 +488,8 @@
         self.globaldata = Fake()
         self.config = get_combined_translation_config(translating=True)
         self.jitlog = jl.JitLogger()
+        if cpu:
+            self.all_descrs = self.cpu.setup_descrs()
 
     class logger_noopt:
         @classmethod
diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py 
b/rpython/jit/metainterp/optimizeopt/virtualize.py
--- a/rpython/jit/metainterp/optimizeopt/virtualize.py
+++ b/rpython/jit/metainterp/optimizeopt/virtualize.py
@@ -80,7 +80,8 @@
     def postprocess_FINISH(self, op):
         guard_op = self._finish_guard_op
         if guard_op is not None:
-            guard_op = self.optimizer.store_final_boxes_in_guard(guard_op, [])
+            # XXX why are there never any pendingwrites here?
+            guard_op = self.optimizer.store_final_boxes_in_guard(guard_op, 
None)
             i = len(self.optimizer._newoperations) - 1
             assert i >= 0
             self.optimizer._newoperations.insert(i, guard_op)
diff --git a/rpython/jit/metainterp/resume.py b/rpython/jit/metainterp/resume.py
--- a/rpython/jit/metainterp/resume.py
+++ b/rpython/jit/metainterp/resume.py
@@ -116,13 +116,6 @@
             virtualizable_boxes, virtualref_boxes)
     return result
 
-PENDINGFIELDSTRUCT = lltype.Struct('PendingField',
-                                   ('lldescr', OBJECTPTR),
-                                   ('num', rffi.SHORT),
-                                   ('fieldnum', rffi.SHORT),
-                                   ('itemindex', rffi.INT))
-PENDINGFIELDSP = lltype.Ptr(lltype.GcArray(PENDINGFIELDSTRUCT))
-
 TAGMASK = 3
 
 def tag(value, tagbits):
@@ -160,7 +153,7 @@
 TAG_CONST_OFFSET = 0
 
 class NumberingState(resumecode.Writer):
-    def __init__(self, size):
+    def __init__(self, size=0):
         resumecode.Writer.__init__(self, size)
         self.liveboxes = {}
         self.num_boxes = 0
@@ -217,45 +210,47 @@
 
     # env numbering
 
+    def _number_box(self, box, optimizer, numb_state):
+        box = optimizer.get_box_replacement(box)
+        liveboxes = numb_state.liveboxes
+
+        if isinstance(box, Const):
+            tagged = self.getconst(box)
+        elif box in liveboxes:
+            tagged = liveboxes[box]
+        else:
+            is_virtual = False
+            if box.type == 'r':
+                info = optimizer.getptrinfo(box)
+                is_virtual = (info is not None and info.is_virtual())
+            if box.type == 'i':
+                info = optimizer.getrawptrinfo(box, create=False)
+                is_virtual = (info is not None and info.is_virtual()) 
+            if is_virtual:
+                tagged = tag(numb_state.num_virtuals, TAGVIRTUAL)
+                numb_state.num_virtuals += 1
+            else:
+                tagged = tag(numb_state.num_boxes, TAGBOX)
+                numb_state.num_boxes += 1
+            liveboxes[box] = tagged
+        return tagged
+
     def _number_boxes(self, iter, arr, optimizer, numb_state):
         """ Number boxes from one snapshot
         """
-        num_boxes = numb_state.num_boxes
-        num_virtuals = numb_state.num_virtuals
-        liveboxes = numb_state.liveboxes
         for item in arr:
             box = iter.get(rffi.cast(lltype.Signed, item))
-            box = optimizer.get_box_replacement(box)
+            tagged = self._number_box(box, optimizer, numb_state)
+            numb_state.append_int(tagged)
 
-            if isinstance(box, Const):
-                tagged = self.getconst(box)
-            elif box in liveboxes:
-                tagged = liveboxes[box]
-            else:
-                is_virtual = False
-                if box.type == 'r':
-                    info = optimizer.getptrinfo(box)
-                    is_virtual = (info is not None and info.is_virtual())
-                if box.type == 'i':
-                    info = optimizer.getrawptrinfo(box, create=False)
-                    is_virtual = (info is not None and info.is_virtual()) 
-                if is_virtual:
-                    tagged = tag(num_virtuals, TAGVIRTUAL)
-                    num_virtuals += 1
-                else:
-                    tagged = tag(num_boxes, TAGBOX)
-                    num_boxes += 1
-                liveboxes[box] = tagged
-            numb_state.append_int(tagged)
-        numb_state.num_boxes = num_boxes
-        numb_state.num_virtuals = num_virtuals
-
-    def number(self, optimizer, position, trace):
+    def number(self, optimizer, position, trace, pendingwrites=None):
         snapshot_iter = trace.get_snapshot_iter(position)
         numb_state = NumberingState(snapshot_iter.size)
         numb_state.append_int(0) # patch later: size of resume section
         numb_state.append_int(0) # patch later: number of failargs
 
+        self._add_pending_writes(optimizer, pendingwrites, numb_state)
+
         arr = snapshot_iter.vable_array
 
         numb_state.append_int(len(arr))
@@ -278,6 +273,43 @@
 
         return numb_state
 
+    def _add_pending_writes(self, optimizer, pendingwrites, numb_state):
+        if not pendingwrites:
+            numb_state.append_int(0)
+            numb_state.append_int(0)
+            return
+        metainterp_sd = optimizer.metainterp_sd
+        numb_state.append_int(len(pendingwrites.fields))
+        for op in pendingwrites.fields:
+            box = optimizer.get_box_replacement(op.getarg(0))
+            descr = op.getdescr()
+            if descr.descr_index == -1:
+                raise TagOverflow # shouldn't happen
+            fieldbox = optimizer.get_box_replacement(op.getarg(1))
+            numb_state.append_int(self._number_box(box, optimizer, numb_state))
+            numb_state.append_int(descr.descr_index)
+            numb_state.append_int(self._number_box(fieldbox, optimizer, 
numb_state))
+
+        numb_state.append_int(len(pendingwrites.arrays))
+        for op in pendingwrites.arrays:
+            box = optimizer.get_box_replacement(op.getarg(0))
+            descr = op.getdescr()
+            if descr.descr_index == -1:
+                raise TagOverflow # shouldn't happen
+            boxindex = optimizer.get_box_replacement(op.getarg(1))
+            itemindex = boxindex.getint()
+            # sanity: it's impossible to run code with SETARRAYITEM_GC
+            # with negative index, so this guard cannot ever fail;
+            # but it's possible to try to *build* such invalid code
+            if itemindex < 0:
+                raise TagOverflow
+            fieldbox = optimizer.get_box_replacement(op.getarg(2))
+            numb_state.append_int(self._number_box(box, optimizer, numb_state))
+            numb_state.append_int(descr.descr_index)
+            # the index is limited to 2**21
+            numb_state.append_int(itemindex)
+            numb_state.append_int(self._number_box(fieldbox, optimizer, 
numb_state))
+
 
     # caching for virtuals and boxes inside them
 
@@ -409,7 +441,7 @@
         _, tagbits = untag(tagged)
         return tagbits == TAGVIRTUAL
 
-    def finish(self, pending_setfields=[]):
+    def finish(self, pendingwrites=None):
         optimizer = self.optimizer
         # compute the numbering
         storage = self.storage
@@ -419,7 +451,7 @@
         assert resume_position >= 0
         # count stack depth
         numb_state = self.memo.number(optimizer,
-            resume_position, optimizer.trace)
+            resume_position, optimizer.trace, pendingwrites)
         self.liveboxes_from_env = liveboxes_from_env = numb_state.liveboxes
         num_virtuals = numb_state.num_virtuals
         self.liveboxes = {}
@@ -442,22 +474,8 @@
                 assert info.is_virtual()
                 info.visitor_walk_recursive(box, self, optimizer)
 
-        for setfield_op in pending_setfields:
-            box = setfield_op.getarg(0)
-            box = optimizer.get_box_replacement(box)
-            if setfield_op.getopnum() == rop.SETFIELD_GC:
-                fieldbox = setfield_op.getarg(1)
-            else:
-                fieldbox = setfield_op.getarg(2)
-            fieldbox = optimizer.get_box_replacement(fieldbox)
-            self.register_box(box)
-            self.register_box(fieldbox)
-            info = optimizer.getptrinfo(fieldbox)
-            assert info is not None and info.is_virtual()
-            info.visitor_walk_recursive(fieldbox, self, optimizer)
-
+        # extends liveboxes!
         self._number_virtuals(liveboxes, optimizer, num_virtuals)
-        self._add_pending_fields(optimizer, pending_setfields)
 
         numb_state.patch(1, len(liveboxes))
 
@@ -468,7 +486,7 @@
 
     def _number_virtuals(self, liveboxes, optimizer, num_env_virtuals):
         from rpython.jit.metainterp.optimizeopt.info import 
AbstractVirtualPtrInfo
-        
+
         # !! 'liveboxes' is a list that is extend()ed in-place !!
         memo = self.memo
         new_liveboxes = [None] * memo.num_cached_boxes()
@@ -532,45 +550,6 @@
                 return True
         return False
 
-    def _add_pending_fields(self, optimizer, pending_setfields):
-        rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO)
-        if pending_setfields:
-            n = len(pending_setfields)
-            rd_pendingfields = lltype.malloc(PENDINGFIELDSP.TO, n)
-            for i in range(n):
-                op = pending_setfields[i]
-                box = optimizer.get_box_replacement(op.getarg(0))
-                descr = op.getdescr()
-                opnum = op.getopnum()
-                if opnum == rop.SETARRAYITEM_GC:
-                    fieldbox = op.getarg(2)
-                    boxindex = optimizer.get_box_replacement(op.getarg(1))
-                    itemindex = boxindex.getint()
-                    # sanity: it's impossible to run code with SETARRAYITEM_GC
-                    # with negative index, so this guard cannot ever fail;
-                    # but it's possible to try to *build* such invalid code
-                    if itemindex < 0:
-                        raise TagOverflow
-                elif opnum == rop.SETFIELD_GC:
-                    fieldbox = op.getarg(1)
-                    itemindex = -1
-                else:
-                    raise AssertionError
-                fieldbox = optimizer.get_box_replacement(fieldbox)
-                #descr, box, fieldbox, itemindex = pending_setfields[i]
-                lldescr = annlowlevel.cast_instance_to_base_ptr(descr)
-                num = rffi.r_short(self._gettagged(box))
-                fieldnum = rffi.r_short(self._gettagged(fieldbox))
-                # the index is limited to 2147483647 (64-bit machines only)
-                if itemindex > 2147483647:
-                    raise TagOverflow
-                #
-                rd_pendingfields[i].lldescr = lldescr
-                rd_pendingfields[i].num = num
-                rd_pendingfields[i].fieldnum = fieldnum
-                rd_pendingfields[i].itemindex = rffi.cast(rffi.INT, itemindex)
-        self.storage.rd_pendingfields = rd_pendingfields
-
     def _gettagged(self, box):
         if box is None:
             return UNINITIALIZED
@@ -926,17 +905,18 @@
     virtual_int_default = None
 
 
-    def _init(self, cpu, storage):
-        self.cpu = cpu
+    def _init(self, metainterp_sd, storage):
+        self.metainterp_sd = metainterp_sd
+        self.cpu = metainterp_sd.cpu
         self.resumecodereader = resumecode.Reader(storage.rd_numb)
-        count = self.resumecodereader.next_item()
-        self.items_resume_section = count
+        items_resume_section = self.resumecodereader.next_item()
+        self.items_resume_section = items_resume_section
         self.count = self.resumecodereader.next_item()
         self.consts = storage.rd_consts
 
     def _prepare(self, storage):
         self._prepare_virtuals(storage.rd_virtuals)
-        self._prepare_pendingfields(storage.rd_pendingfields)
+        self._prepare_pendingfields()
 
     def read_jitcode_pos_pc(self):
         jitcode_pos = self.resumecodereader.next_item()
@@ -1003,21 +983,23 @@
             self.virtuals_cache = self.VirtualCache([self.virtual_ptr_default] 
* len(virtuals),
                                                     [self.virtual_int_default] 
* len(virtuals))
 
-    def _prepare_pendingfields(self, pendingfields):
-        if pendingfields:
-            for i in range(len(pendingfields)):
-                lldescr = pendingfields[i].lldescr
-                num = pendingfields[i].num
-                fieldnum = pendingfields[i].fieldnum
-                itemindex = pendingfields[i].itemindex
-                descr = annlowlevel.cast_base_ptr_to_instance(AbstractDescr,
-                                                              lldescr)
-                struct = self.decode_ref(num)
-                itemindex = rffi.cast(lltype.Signed, itemindex)
-                if itemindex < 0:
-                    self.setfield(struct, fieldnum, descr)
-                else:
-                    self.setarrayitem(struct, itemindex, fieldnum, descr)
+    def _prepare_pendingfields(self):
+        metainterp_sd = self.metainterp_sd
+        for i in range(self.resumecodereader.next_item()):
+            num = self.resumecodereader.next_item()
+            struct = self.decode_ref(num)
+            descrindex = self.resumecodereader.next_item()
+            descr = metainterp_sd.all_descrs[descrindex]
+            fieldnum = self.resumecodereader.next_item()
+            self.setfield(struct, fieldnum, descr)
+        for i in range(self.resumecodereader.next_item()):
+            num = self.resumecodereader.next_item()
+            struct = self.decode_ref(num)
+            descrindex = self.resumecodereader.next_item()
+            descr = metainterp_sd.all_descrs[descrindex]
+            index = self.resumecodereader.next_item()
+            fieldnum = self.resumecodereader.next_item()
+            self.setarrayitem(struct, index, fieldnum, descr)
 
     def setarrayitem(self, array, index, fieldnum, arraydescr):
         if arraydescr.is_array_of_pointers():
@@ -1072,7 +1054,7 @@
     VirtualCache = get_VirtualCache_class('BoxReader')
 
     def __init__(self, storage, deadframe, metainterp):
-        self._init(metainterp.cpu, storage)
+        self._init(metainterp.staticdata, storage)
         self.deadframe = deadframe
         self.metainterp = metainterp
         self.liveboxes = [None] * self.count
@@ -1363,7 +1345,7 @@
     #             2: resuming from the GUARD_NOT_FORCED
 
     def __init__(self, metainterp_sd, storage, deadframe, all_virtuals=None):
-        self._init(metainterp_sd.cpu, storage)
+        self._init(metainterp_sd, storage)
         self.deadframe = deadframe
         self.callinfocollection = metainterp_sd.callinfocollection
         if all_virtuals is None:        # common case
@@ -1376,6 +1358,12 @@
             # self.rd_virtuals can remain None, because virtuals_cache is
             # already filled
 
+            # skip over the resume code section that does pending field writes
+            num_field_writes = self.resumecodereader.next_item()
+            assert num_field_writes == 0
+            num_array_writes = self.resumecodereader.next_item()
+            assert num_array_writes == 0
+
     def handling_async_forcing(self):
         self.resume_after_guard_not_forced = 1
 
diff --git a/rpython/jit/metainterp/resumecode.py 
b/rpython/jit/metainterp/resumecode.py
--- a/rpython/jit/metainterp/resumecode.py
+++ b/rpython/jit/metainterp/resumecode.py
@@ -3,6 +3,8 @@
   # ----- resume section
   [total size of resume section, unencoded]
   [number of failargs]
+  [<length> (<numb> <descr> <numb>]                         setfields
+  [<length> (<numb> <descr> <index> <numb>]                 setarrayitems
   [<length> <virtualizable object> <numb> <numb> <numb>]    if vinfo is not 
None
    -OR-
   [1 <ginfo object>]                                        if ginfo is not 
None
diff --git a/rpython/jit/metainterp/test/test_resume.py 
b/rpython/jit/metainterp/test/test_resume.py
--- a/rpython/jit/metainterp/test/test_resume.py
+++ b/rpython/jit/metainterp/test/test_resume.py
@@ -10,9 +10,9 @@
      VArrayInfoNotClear, VStrPlainInfo, VStrConcatInfo, VStrSliceInfo,\
      VUniPlainInfo, VUniConcatInfo, VUniSliceInfo,\
      capture_resumedata, ResumeDataLoopMemo, UNASSIGNEDVIRTUAL, INT,\
-     annlowlevel, PENDINGFIELDSP, TAG_CONST_OFFSET
+     annlowlevel, TAG_CONST_OFFSET, NumberingState
 from rpython.jit.metainterp.resumecode import unpack_numbering,\
-     create_numbering, NULL_NUMBER
+     create_numbering, NULL_NUMBER, Reader
 from rpython.jit.metainterp.opencoder import Trace, Snapshot, TopSnapshot
 
 from rpython.jit.metainterp.optimizeopt import info
@@ -35,7 +35,6 @@
     rd_numb = None
     rd_consts = []
     rd_virtuals = None
-    rd_pendingfields = None
 
 
 class FakeOptimizer(object):
@@ -97,14 +96,6 @@
                     debug_print('\t\t', 'None')
                 else:
                     virtual.debug_prints()
-        if storage.rd_pendingfields:
-            debug_print('\tpending setfields')
-            for i in range(len(storage.rd_pendingfields)):
-                lldescr = storage.rd_pendingfields[i].lldescr
-                num = storage.rd_pendingfields[i].num
-                fieldnum = storage.rd_pendingfields[i].fieldnum
-                itemindex = storage.rd_pendingfields[i].itemindex
-                debug_print("\t\t", str(lldescr), str(untag(num)), 
str(untag(fieldnum)), itemindex)
 
     debug_stop("jit-resume")
 
@@ -171,6 +162,12 @@
     else:
         assert op.type == 'v'
 
+class FakeStaticData(object):
+    def __init__(self, cpu):
+        self.cpu = cpu
+        if hasattr(cpu, 'setup_descrs'):
+            self.all_descrs = cpu.setup_descrs()
+
 class MyMetaInterp:
     _already_allocated_resume_virtuals = None
     callinfocollection = None
@@ -179,6 +176,7 @@
         if cpu is None:
             cpu = LLtypeMixin.cpu
         self.cpu = cpu
+        self.staticdata = FakeStaticData(cpu)
         self.trace = []
         self.framestack = []
 
@@ -301,7 +299,7 @@
     c1, c2, c3 = [ConstInt(111), ConstInt(222), ConstInt(333)]
     storage = Storage()
     storage.rd_consts = [c1, c2, c3]
-    numb = Numbering([3, tag(0, TAGBOX), tagconst(0),
+    numb = Numbering([3, 0, 0, tag(0, TAGBOX), tagconst(0),
                        NULLREF, tag(0, TAGBOX), tag(1, TAGBOX)] +
                        [tagconst(1), tagconst(2)] +
                        [tag(0, TAGBOX), tag(1, TAGBOX), tag(2, TAGBOX)])
@@ -346,7 +344,7 @@
 def test_simple_read_tagged_ints():
     storage = Storage()
     storage.rd_consts = []
-    numb = Numbering([1, tag(100, TAGINT)])
+    numb = Numbering([1, 0, 0, tag(100, TAGINT)])
     storage.rd_numb = numb
     #
     cpu = MyCPU([])
@@ -363,9 +361,8 @@
             return s
     class FakeStorage(object):
         rd_virtuals = [FakeVinfo(), None]
-        rd_numb = Numbering([1])
+        rd_numb = Numbering([1, 0, 0])
         rd_consts = []
-        rd_pendingfields = None
     class FakeMetainterp(object):
         _already_allocated_resume_virtuals = None
         cpu = None
@@ -858,7 +855,7 @@
     base = [0, 0, tag(0, TAGBOX), tag(1, TAGINT),
             tag(1, TAGBOX), tag(0, TAGBOX), tag(2, TAGINT)]
 
-    assert unpack_numbering(numb) == [17, 0, 0, 0] + base + [0, 2, tag(3, 
TAGINT), tag(2, TAGBOX),
+    assert unpack_numbering(numb) == [19, 0, 0, 0, 0, 0] + base + [0, 2, 
tag(3, TAGINT), tag(2, TAGBOX),
                                       tag(0, TAGBOX), tag(1, TAGINT)]
     t.append(0)
     snap2 = t.create_top_snapshot(FakeJitCode("jitcode", 0), 2, Frame(env2),
@@ -872,7 +869,7 @@
     assert numb_state2.liveboxes == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX),
                                      b3: tag(2, TAGBOX)}
     assert numb_state2.liveboxes is not numb_state.liveboxes
-    assert unpack_numbering(numb2) == [17, 0, 0, 0] + base + [0, 2, tag(3, 
TAGINT), tag(2, TAGBOX),
+    assert unpack_numbering(numb2) == [19, 0, 0, 0, 0, 0] + base + [0, 2, 
tag(3, TAGINT), tag(2, TAGBOX),
                                        tag(0, TAGBOX), tag(3, TAGINT)]
 
     t.append(0)
@@ -894,7 +891,7 @@
     assert numb_state3.num_virtuals == 0
     
     assert numb_state3.liveboxes == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX)}
-    assert unpack_numbering(numb3) == ([17, 0, 0, 2, tag(3, TAGINT), tag(4, 
TAGINT),
+    assert unpack_numbering(numb3) == ([19, 0, 0, 0, 0, 2, tag(3, TAGINT), 
tag(4, TAGINT),
                                        tag(0, TAGBOX), tag(3, TAGINT)] +
                                        base + [0, 2])
 
@@ -911,7 +908,7 @@
     
     assert numb_state4.liveboxes == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX),
                                      b4: tag(0, TAGVIRTUAL)}
-    assert unpack_numbering(numb4) == [17, 0, 0, 2, tag(3, TAGINT), tag(0, 
TAGVIRTUAL),
+    assert unpack_numbering(numb4) == [19, 0, 0, 0, 0, 2, tag(3, TAGINT), 
tag(0, TAGVIRTUAL),
                                        tag(0, TAGBOX), tag(3, TAGINT)] + base 
+ [0, 2]
 
     t.append(0)
@@ -930,7 +927,7 @@
 
     assert numb_state5.liveboxes == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX),
                                      b4: tag(0, TAGVIRTUAL), b5: tag(1, 
TAGVIRTUAL)}
-    assert unpack_numbering(numb5) == [22, 0,
+    assert unpack_numbering(numb5) == [24, 0, 0, 0,
         3, tag(0, TAGBOX), tag(0, TAGVIRTUAL), tag(1, TAGVIRTUAL),
         0] + base + [
         2, 1, tag(3, TAGINT), tag(0, TAGVIRTUAL), tag(0, TAGBOX), tag(3, 
TAGINT)
@@ -951,15 +948,17 @@
     l = unpack_numbering(numb)
     assert l[0] == len(l)
     assert l[1] == 0
-    assert l[1] == 0
     assert l[2] == 0
     assert l[3] == 0
     assert l[4] == 0
+    assert l[5] == 0
+    assert l[6] == 0
+    assert l[7] == 0
     mapping = dict(zip(inpargs, i.inputargs))
     for i, item in enumerate(lst):
-        v, tag = untag(l[i + 6])
+        v, tag = untag(l[i + 8])
         if tag == TAGBOX:
-            assert l[i + 6] == numb_state.liveboxes[mapping[item]]
+            assert l[i + 8] == numb_state.liveboxes[mapping[item]]
         elif tag == TAGCONST:
             assert memo.consts[v].getint() == item.getint()
         elif tag == TAGINT:
@@ -1102,7 +1101,7 @@
 class ResumeDataFakeReader(ResumeDataBoxReader):
     """Another subclass of AbstractResumeDataReader meant for tests."""
     def __init__(self, storage, newboxes, metainterp):
-        self._init(metainterp.cpu, storage)
+        self._init(metainterp.staticdata, storage)
         self.liveboxes = newboxes
         self.metainterp = metainterp
         self._prepare(storage)
@@ -1232,7 +1231,7 @@
     liveboxes = []
     modifier._number_virtuals(liveboxes, FakeOptimizer(), 0)
     storage.rd_consts = memo.consts[:]
-    storage.rd_numb = Numbering([0])
+    storage.rd_numb = Numbering([0, 0, 0])
     # resume
     b3t, b5t = [IntFrontendOp(0), RefFrontendOp(0)]
     b5t.setref_base(demo55o)
@@ -1303,7 +1302,7 @@
     modifier._number_virtuals(liveboxes, FakeOptimizer(), 0)
     dump_storage(storage, liveboxes)
     storage.rd_consts = memo.consts[:]
-    storage.rd_numb = Numbering([0])
+    storage.rd_numb = Numbering([0, 0, 0])
     # resume
     b1t, b3t, b4t = [IntFrontendOp(0), IntFrontendOp(0), IntFrontendOp(0)]
     b1t.setint(11)
@@ -1356,7 +1355,7 @@
     modifier._number_virtuals(liveboxes, FakeOptimizer(), 0)
     dump_storage(storage, liveboxes)
     storage.rd_consts = memo.consts[:]
-    storage.rd_numb = Numbering([0])
+    storage.rd_numb = Numbering([0, 0, 0])
     b4t = RefFrontendOp(0)
     newboxes = _resume_remap(liveboxes, [#b2s -- virtual
                                          b4s], b4t)
@@ -1384,25 +1383,50 @@
     assert ptr.b == lltype.nullptr(LLtypeMixin.NODE)
 
 
-def test_virtual_adder_pending_fields():
+def test_virtual_adder_pending_fields(monkeypatch):
+    from rpython.jit.metainterp.optimizeopt.heap import PendingWrites
+    monkeypatch.setattr(LLtypeMixin.nextdescr, "descr_index", 0)
+    metainterp_sd = FakeMetaInterpStaticData()
+    metainterp_sd.all_descrs = [LLtypeMixin.nextdescr]
     b2s, b4s = [RefFrontendOp(0), RefFrontendOp(0)]
     storage = Storage()
-    memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
+    optimizer = FakeOptimizer()
+    optimizer.metainterp_sd = metainterp_sd
+
+    memo = ResumeDataLoopMemo(metainterp_sd)
+
     modifier = ResumeDataVirtualAdder(None, storage, storage, None, memo)
-    modifier.liveboxes_from_env = {}
+    # simulated call to "finish"
+    # first call number:
+    numb_state = NumberingState()
+    numb_state.append_int(0)
+    numb_state.append_int(0)
+    pendingwrites = PendingWrites([
+        ResOperation(rop.SETFIELD_GC, [b2s, b4s], 
descr=LLtypeMixin.nextdescr)],
+        [])
+    memo._add_pending_writes(optimizer, pendingwrites, numb_state)
+
+    # now back in finish
+
+    modifier.liveboxes_from_env = numb_state.liveboxes
     modifier.liveboxes = {}
+    liveboxes = [None] * len(modifier.liveboxes_from_env)
+    for box, tagged in modifier.liveboxes_from_env.iteritems():
+        i, tagbits = untag(tagged)
+        assert tagbits == TAGBOX
+        liveboxes[i] = box
+    assert liveboxes == [b2s, b4s]
+
     modifier.vfieldboxes = {}
 
+    # simulate _walk_pending_write # XXX unneeded?
     modifier.register_box(b2s)
     modifier.register_box(b4s)
 
-    liveboxes = []
     modifier._number_virtuals(liveboxes, FakeOptimizer(), 0)
-    assert liveboxes == [b2s, b4s] or liveboxes == [b4s, b2s]
-    modifier._add_pending_fields(FakeOptimizer(), [
-        ResOperation(rop.SETFIELD_GC, [b2s, b4s], 
descr=LLtypeMixin.nextdescr)])
     storage.rd_consts = memo.consts[:]
-    storage.rd_numb = Numbering([0])
+    storage.rd_numb = numb_state.create_numbering()
+
     # resume
     demo55.next = lltype.nullptr(LLtypeMixin.NODE)
     b2t = RefFrontendOp(0)
@@ -1412,6 +1436,7 @@
     newboxes = _resume_remap(liveboxes, [b2s, b4s], b2t, b4t)
 
     metainterp = MyMetaInterp()
+    metainterp.staticdata = metainterp_sd
     reader = ResumeDataFakeReader(storage, newboxes, metainterp)
     assert reader.virtuals_cache is None
     trace = metainterp.trace
@@ -1424,125 +1449,130 @@
     assert demo55.next == demo66
 
 def test_virtual_adder_pending_fields_and_arrayitems():
-    class Storage(object):
-        pass
-    storage = Storage()
-    modifier = ResumeDataVirtualAdder(None, storage, storage, None, None)
-    modifier._add_pending_fields(None, [])
-    assert not storage.rd_pendingfields
+    from rpython.jit.metainterp.optimizeopt.heap import PendingWrites
+    metainterp_sd = FakeMetaInterpStaticData()
+    metainterp_sd.all_descrs = []
+    optimizer = FakeOptimizer()
+    optimizer.metainterp_sd = metainterp_sd
+
+    memo = ResumeDataLoopMemo(metainterp_sd)
+    numb_state = NumberingState()
+    memo._add_pending_writes(optimizer, None, numb_state)
+    assert numb_state.current == [0, 0]
+
     #
     class FieldDescr(AbstractDescr):
+        def __init__(self):
+            self.descr_index = len(metainterp_sd.all_descrs)
+            metainterp_sd.all_descrs.append(self)
+
         def is_array_of_primitives(self):
             return False
+
     field_a = FieldDescr()
-    storage = Storage()
-    modifier = ResumeDataVirtualAdder(None, storage, storage, None, None)
+    memo = ResumeDataLoopMemo(metainterp_sd)
+    numb_state = NumberingState()
     a = IntFrontendOp(0)
     b = IntFrontendOp(0)
-    modifier.liveboxes_from_env = {a: rffi.cast(rffi.SHORT, 1042),
-                                   b: rffi.cast(rffi.SHORT, 1061)}
-    modifier._add_pending_fields(FakeOptimizer(), [
+    numb_state.liveboxes = {a: 1042, b: 1061}
+    pendingwrites = PendingWrites([
         ResOperation(rop.SETFIELD_GC, [a, b],
-                     descr=field_a)])
-    pf = storage.rd_pendingfields
-    assert len(pf) == 1
-    assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr)
-            is field_a)
-    assert rffi.cast(lltype.Signed, pf[0].num) == 1042
-    assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061
-    assert rffi.cast(lltype.Signed, pf[0].itemindex) == -1
+                     descr=field_a)], [])
+    memo._add_pending_writes(optimizer, pendingwrites, numb_state)
+    assert numb_state.current == [1, 1042, 0, 1061, 0]
+
     #
     array_a = FieldDescr()
-    storage = Storage()
-    modifier = ResumeDataVirtualAdder(None, storage, storage, None, None)
+    memo = ResumeDataLoopMemo(metainterp_sd)
+    numb_state = NumberingState()
     a42 = IntFrontendOp(0)
     a61 = IntFrontendOp(0)
     a62 = IntFrontendOp(0)
     a63 = IntFrontendOp(0)
-    modifier.liveboxes_from_env = {a42: rffi.cast(rffi.SHORT, 1042),
-                                   a61: rffi.cast(rffi.SHORT, 1061),
-                                   a62: rffi.cast(rffi.SHORT, 1062),
-                                   a63: rffi.cast(rffi.SHORT, 1063)}
-    modifier._add_pending_fields(FakeOptimizer(), [
+    numb_state.liveboxes = {a42: 1042, a61: 1061, a62: 1062, a63: 1063}
+    pendingwrites = PendingWrites([],
+        [
         ResOperation(rop.SETARRAYITEM_GC, [a42, ConstInt(0), a61],
                      descr=array_a),
-        ResOperation(rop.SETARRAYITEM_GC, [a42, ConstInt(2147483647), a62],
+        ResOperation(rop.SETARRAYITEM_GC, [a42, ConstInt(2**21 - 1), a62],
                      descr=array_a)])
-    pf = storage.rd_pendingfields
-    assert len(pf) == 2
-    assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr)
-            is array_a)
-    assert rffi.cast(lltype.Signed, pf[0].num) == 1042
-    assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061
-    assert rffi.cast(lltype.Signed, pf[0].itemindex) == 0
-    assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[1].lldescr)
-            is array_a)
-    assert rffi.cast(lltype.Signed, pf[1].num) == 1042
-    assert rffi.cast(lltype.Signed, pf[1].fieldnum) == 1062
-    assert rffi.cast(lltype.Signed, pf[1].itemindex) == 2147483647
+    memo._add_pending_writes(optimizer, pendingwrites, numb_state)
+    assert numb_state.current == [0, # no pending field writes
+        2, # two pending array writes
+        1042, 1, 0, 1061, # first write
+        1042, 1, 2 ** 21 - 1, 1062 # second write
+        ]
     #
-    if sys.maxint >= 2147483648:
-        py.test.raises(TagOverflow, modifier._add_pending_fields,
-                       FakeOptimizer(),
-                       [ResOperation(rop.SETARRAYITEM_GC,
-                                     [a42, ConstInt(2147483648), a63],
-                                     descr=array_a)])
+
+    pendingwrites = PendingWrites([],
+        [ResOperation(rop.SETARRAYITEM_GC,
+                      [a42, ConstInt(2147483648), a63],
+                      descr=array_a)])
+    with py.test.raises(TagOverflow):
+        memo._add_pending_writes(optimizer, pendingwrites, numb_state)
+
 
 def test_resume_reader_fields_and_arrayitems():
+    metainterp_sd = FakeMetaInterpStaticData()
+    metainterp_sd.all_descrs = []
+
     class ResumeReader(AbstractResumeDataReader):
-        def __init__(self, got=None, got_array=None):
+        def __init__(self, numb, got=None, got_array=None):
+            self.resumecodereader = Reader(numb)
+            self.metainterp_sd = metainterp_sd
             self.got = got
             self.got_array = got_array
         def setfield(self, struct, fieldnum, descr):
             assert lltype.typeOf(struct) is lltype.Signed
-            assert lltype.typeOf(fieldnum) is rffi.SHORT
-            fieldnum = rffi.cast(lltype.Signed, fieldnum)
+            assert lltype.typeOf(fieldnum) is lltype.Signed
             self.got.append((descr, struct, fieldnum))
         def setarrayitem(self, array, index, fieldnum, arraydescr):
             assert lltype.typeOf(array) is lltype.Signed
             assert lltype.typeOf(index) is lltype.Signed
-            assert lltype.typeOf(fieldnum) is rffi.SHORT
-            fieldnum = rffi.cast(lltype.Signed, fieldnum)
+            assert lltype.typeOf(fieldnum) is lltype.Signed
             self.got_array.append((arraydescr, array, index, fieldnum))
         def decode_ref(self, num):
             return rffi.cast(lltype.Signed, num) * 100
+    numb = create_numbering([0, 0])
     got = []
-    pf = lltype.nullptr(PENDINGFIELDSP.TO)
-    ResumeReader(got)._prepare_pendingfields(pf)
+    ResumeReader(numb, got)._prepare_pendingfields()
     assert got == []
     #
     class FieldDescr(AbstractDescr):
-        pass
+        def __init__(self):
+            self.descr_index = len(metainterp_sd.all_descrs)
+            metainterp_sd.all_descrs.append(self)
     field_a = FieldDescr()
     field_b = FieldDescr()
-    pf = lltype.malloc(PENDINGFIELDSP.TO, 2)
-    pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(field_a)
-    pf[0].num = rffi.cast(rffi.SHORT, 1042)
-    pf[0].fieldnum = rffi.cast(rffi.SHORT, 1061)
-    pf[0].itemindex = rffi.cast(rffi.INT, -1)
-    pf[1].lldescr = annlowlevel.cast_instance_to_base_ptr(field_b)
-    pf[1].num = rffi.cast(rffi.SHORT, 2042)
-    pf[1].fieldnum = rffi.cast(rffi.SHORT, 2061)
-    pf[1].itemindex = rffi.cast(rffi.INT, -1)
+    numb = create_numbering([2, # number writes
+        1042,
+        field_a.descr_index,
+        1061,
+        2042,
+        field_b.descr_index,
+        2061,
+        0, # number array writes
+        ])
     got = []
-    ResumeReader(got)._prepare_pendingfields(pf)
+    ResumeReader(numb, got)._prepare_pendingfields()
     assert got == [(field_a, 104200, 1061), (field_b, 204200, 2061)]
     #
     array_a = FieldDescr()
-    pf = lltype.malloc(PENDINGFIELDSP.TO, 1)
-    pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(array_a)
-    pf[0].num = rffi.cast(rffi.SHORT, 1042)
-    pf[0].fieldnum = rffi.cast(rffi.SHORT, 1063)
-    pf[0].itemindex = rffi.cast(rffi.INT, 123)
+    numb = create_numbering([0, # number writes
+        1, # number array writes
+        1042,
+        array_a.descr_index,
+        123,
+        1063])
     got_array = []
-    ResumeReader(got_array=got_array)._prepare_pendingfields(pf)
+    ResumeReader(numb, got_array=got_array)._prepare_pendingfields()
     assert got_array == [(array_a, 104200, 123, 1063)]
 
 
 def test_invalidation_needed():
     class options:
         failargs_limit = 10
-        
+
     metainterp_sd = FakeMetaInterpStaticData()
     metainterp_sd.options = options
     memo = ResumeDataLoopMemo(metainterp_sd)
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to