[pypy-commit] pypy s390x-backend: merged default

plan_rich pypy.commits at gmail.com
Thu Jan 14 06:27:03 EST 2016


Author: Richard Plangger <planrichi at gmail.com>
Branch: s390x-backend
Changeset: r81758:7cc617cb941e
Date: 2016-01-14 10:29 +0100
http://bitbucket.org/pypy/pypy/changeset/7cc617cb941e/

Log:	merged default

diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -39,5 +39,5 @@
 # runs.  We cannot get their original value either:
 # http://lists.gnu.org/archive/html/help-make/2010-08/msg00106.html
 
-cffi_imports:
+cffi_imports: pypy-c
 	PYTHONPATH=. ./pypy-c pypy/tool/build_cffi_imports.py
diff --git a/pypy/module/_continuation/interp_continuation.py b/pypy/module/_continuation/interp_continuation.py
--- a/pypy/module/_continuation/interp_continuation.py
+++ b/pypy/module/_continuation/interp_continuation.py
@@ -195,7 +195,7 @@
 class SThread(StackletThread):
 
     def __init__(self, space, ec):
-        StackletThread.__init__(self, space.config)
+        StackletThread.__init__(self)
         self.space = space
         self.ec = ec
         # for unpickling
diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py
--- a/pypy/module/itertools/interp_itertools.py
+++ b/pypy/module/itertools/interp_itertools.py
@@ -372,7 +372,7 @@
     def arg_int_w(self, w_obj, minimum, errormsg):
         space = self.space
         try:
-            result = space.int_w(w_obj)
+            result = space.int_w(space.int(w_obj))    # CPython allows floats as parameters
         except OperationError, e:
             if e.async(space):
                 raise
diff --git a/pypy/module/itertools/test/test_itertools.py b/pypy/module/itertools/test/test_itertools.py
--- a/pypy/module/itertools/test/test_itertools.py
+++ b/pypy/module/itertools/test/test_itertools.py
@@ -225,6 +225,12 @@
             assert it.next() == x
         raises(StopIteration, it.next)
 
+        # CPython implementation allows floats
+        it = itertools.islice([1, 2, 3, 4, 5], 0.0, 3.0, 2.0)
+        for x in [1, 3]:
+            assert it.next() == x
+        raises(StopIteration, it.next)
+
         it = itertools.islice([1, 2, 3], 0, None)
         for x in [1, 2, 3]:
             assert it.next() == x
diff --git a/rpython/jit/codewriter/effectinfo.py b/rpython/jit/codewriter/effectinfo.py
--- a/rpython/jit/codewriter/effectinfo.py
+++ b/rpython/jit/codewriter/effectinfo.py
@@ -330,15 +330,11 @@
         return op.opname == 'jit_force_quasi_immutable'
 
 class RandomEffectsAnalyzer(BoolGraphAnalyzer):
-    def analyze_external_call(self, op, seen=None):
-        try:
-            funcobj = op.args[0].value._obj
-            if funcobj.random_effects_on_gcobjs:
-                return True
-        except (AttributeError, lltype.DelayedPointer):
-            return True   # better safe than sorry
+    def analyze_external_call(self, funcobj, seen=None):
+        if funcobj.random_effects_on_gcobjs:
+            return True
         return super(RandomEffectsAnalyzer, self).analyze_external_call(
-            op, seen)
+            funcobj, seen)
 
     def analyze_simple_operation(self, op, graphinfo):
         return False
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
@@ -21,7 +21,10 @@
     pass
 
 
-class CachedField(object):
+class AbstractCachedEntry(object):
+    """ abstract base class abstracting over the difference between caching
+    struct fields and array items. """
+
     def __init__(self):
         # Cache information for a field descr, or for an (array descr, index)
         # pair.  It can be in one of two states:
@@ -29,8 +32,8 @@
         #   1. 'cached_infos' is a list listing all the infos that are
         #      caching this descr
         #
-        #   2. we just did one setfield, which is delayed (and thus
-        #      not synchronized).  'lazy_setfield' is the delayed
+        #   2. we just did one set(field/arrayitem), which is delayed (and thus
+        #      not synchronized).  '_lazy_set' is the delayed
         #      ResOperation.  In this state, 'cached_infos' contains
         #      out-of-date information.  More precisely, the field
         #      value pending in the ResOperation is *not* visible in
@@ -38,43 +41,39 @@
         #
         self.cached_infos = []
         self.cached_structs = []
-        self._lazy_setfield = None
-        self._lazy_setfield_registered = False
+        self._lazy_set = None
 
-    def register_dirty_field(self, structop, info):
+    def register_info(self, structop, info):
+        # invariant: every struct or array ptr info, that is not virtual and
+        # that has a non-None entry at
+        # info._fields[descr.get_index()]
+        # must be in cache_infos
         self.cached_structs.append(structop)
         self.cached_infos.append(info)
 
-    def invalidate(self, descr):
-        for opinfo in self.cached_infos:
-            assert isinstance(opinfo, info.AbstractStructPtrInfo)
-            opinfo._fields[descr.get_index()] = None
-        self.cached_infos = []
-        self.cached_structs = []
-
     def produce_potential_short_preamble_ops(self, optimizer, shortboxes,
                                              descr, index=-1):
-        assert self._lazy_setfield is None
+        assert self._lazy_set is None
         for i, info in enumerate(self.cached_infos):
             structbox = optimizer.get_box_replacement(self.cached_structs[i])
             info.produce_short_preamble_ops(structbox, descr, index, optimizer,
                                             shortboxes)
 
     def possible_aliasing(self, optheap, opinfo):
-        # If lazy_setfield is set and contains a setfield on a different
+        # If lazy_set is set and contains a setfield on a different
         # structvalue, then we are annoyed, because it may point to either
         # the same or a different structure at runtime.
         # XXX constants?
-        return (self._lazy_setfield is not None
+        return (self._lazy_set is not None
                 and (not optheap.getptrinfo(
-                    self._lazy_setfield.getarg(0)).same_info(opinfo)))
+                    self._lazy_set.getarg(0)).same_info(opinfo)))
 
     def do_setfield(self, optheap, op):
         # Update the state with the SETFIELD_GC/SETARRAYITEM_GC operation 'op'.
         structinfo = optheap.ensure_ptr_info_arg0(op)
-        arg1 = optheap.get_box_replacement(self._getvalue(op))
+        arg1 = optheap.get_box_replacement(self._get_rhs_from_set_op(op))
         if self.possible_aliasing(optheap, structinfo):
-            self.force_lazy_setfield(optheap, op.getdescr())
+            self.force_lazy_set(optheap, op.getdescr())
             assert not self.possible_aliasing(optheap, structinfo)
         cached_field = self._getfield(structinfo, op.getdescr(), optheap, False)
         if cached_field is not None:
@@ -87,58 +86,43 @@
         #    cached_fieldvalue = self._cached_fields.get(structvalue, None)
 
         if not cached_field or not cached_field.same_box(arg1):
-            # common case: store the 'op' as lazy_setfield, and register
-            # myself in the optheap's _lazy_setfields_and_arrayitems list
-            self._lazy_setfield = op
-            #if not self._lazy_setfield_registered:
-            #    self._lazy_setfield_registered = True
+            # common case: store the 'op' as lazy_set
+            self._lazy_set = op
 
         else:
             # this is the case where the pending setfield ends up
             # storing precisely the value that is already there,
             # as proved by 'cached_fields'.  In this case, we don't
-            # need any _lazy_setfield: the heap value is already right.
-            # Note that this may reset to None a non-None lazy_setfield,
+            # need any _lazy_set: the heap value is already right.
+            # Note that this may reset to None a non-None lazy_set,
             # cancelling its previous effects with no side effect.
             
             # Now, we have to force the item in the short preamble
             self._getfield(structinfo, op.getdescr(), optheap)
-            self._lazy_setfield = None
+            self._lazy_set = None
 
     def getfield_from_cache(self, optheap, opinfo, descr):
         # Returns the up-to-date field's value, or None if not cached.
         if self.possible_aliasing(optheap, opinfo):
-            self.force_lazy_setfield(optheap, descr)
-        if self._lazy_setfield is not None:
-            op = self._lazy_setfield
-            return optheap.get_box_replacement(self._getvalue(op))
+            self.force_lazy_set(optheap, descr)
+        if self._lazy_set is not None:
+            op = self._lazy_set
+            return optheap.get_box_replacement(self._get_rhs_from_set_op(op))
         else:
             res = self._getfield(opinfo, descr, optheap)
             if res is not None:
                 return res.get_box_replacement()
             return None
 
-    def _getvalue(self, op):
-        return op.getarg(1)
-
-    def _getfield(self, opinfo, descr, optheap, true_force=True):
-        res = opinfo.getfield(descr, optheap)
-        if isinstance(res, PreambleOp):
-            if not true_force:
-                return res.op
-            res = optheap.optimizer.force_op_from_preamble(res)
-            opinfo.setfield(descr, None, res, optheap)
-        return res
-
-    def force_lazy_setfield(self, optheap, descr, can_cache=True):
-        op = self._lazy_setfield
+    def force_lazy_set(self, optheap, descr, can_cache=True):
+        op = self._lazy_set
         if op is not None:
-            # This is the way _lazy_setfield is usually reset to None.
+            # This is the way _lazy_set is usually reset to None.
             # Now we clear _cached_fields, because actually doing the
             # setfield might impact any of the stored result (because of
             # possible aliasing).
             self.invalidate(descr)
-            self._lazy_setfield = None
+            self._lazy_set = None
             if optheap.postponed_op:
                 for a in op.getarglist():
                     if a is optheap.postponed_op:
@@ -151,25 +135,74 @@
             # back in the cache: the value of this particular structure's
             # field.
             opinfo = optheap.ensure_ptr_info_arg0(op)
-            self._setfield(op, opinfo, optheap)
+            self.put_field_back_to_info(op, opinfo, optheap)
         elif not can_cache:
             self.invalidate(descr)
 
-    def _setfield(self, op, opinfo, optheap):
+
+    # abstract methods
+
+    def _get_rhs_from_set_op(self, op):
+        """ given a set(field or arrayitem) op, return the rhs argument """
+        raise NotImplementedError("abstract method")
+
+    def put_field_back_to_info(self, op, opinfo, optheap):
+        """ this method is called just after a lazy setfield was ommitted. it
+        puts the information of the lazy setfield back into the proper cache in
+        the info. """
+        raise NotImplementedError("abstract method")
+
+    def _getfield(self, opinfo, descr, optheap, true_force=True):
+        raise NotImplementedError("abstract method")
+
+    def invalidate(self, descr):
+        """ clear all the cached knowledge in the infos in self.cached_infos.
+        """
+        raise NotImplementedError("abstract method")
+
+
+class CachedField(AbstractCachedEntry):
+    def _get_rhs_from_set_op(self, op):
+        return op.getarg(1)
+
+    def put_field_back_to_info(self, op, opinfo, optheap):
         arg = optheap.get_box_replacement(op.getarg(1))
         struct = optheap.get_box_replacement(op.getarg(0))
-        opinfo.setfield(op.getdescr(), struct, arg, optheap, self)
+        opinfo.setfield(op.getdescr(), struct, arg, optheap=optheap, cf=self)
 
-class ArrayCachedField(CachedField):
+    def _getfield(self, opinfo, descr, optheap, true_force=True):
+        res = opinfo.getfield(descr, optheap)
+        if not we_are_translated() and res:
+            if isinstance(opinfo, info.AbstractStructPtrInfo):
+                assert opinfo in self.cached_infos
+        if isinstance(res, PreambleOp):
+            if not true_force:
+                return res.op
+            res = optheap.optimizer.force_op_from_preamble(res)
+            opinfo.setfield(descr, None, res, optheap=optheap)
+        return res
+
+    def invalidate(self, descr):
+        for opinfo in self.cached_infos:
+            assert isinstance(opinfo, info.AbstractStructPtrInfo)
+            opinfo._fields[descr.get_index()] = None
+        self.cached_infos = []
+        self.cached_structs = []
+
+
+class ArrayCachedItem(AbstractCachedEntry):
     def __init__(self, index):
         self.index = index
-        CachedField.__init__(self)
+        AbstractCachedEntry.__init__(self)
 
-    def _getvalue(self, op):
+    def _get_rhs_from_set_op(self, op):
         return op.getarg(2)
 
     def _getfield(self, opinfo, descr, optheap, true_force=True):
         res = opinfo.getitem(descr, self.index, optheap)
+        if not we_are_translated() and res:
+            if isinstance(opinfo, info.ArrayPtrInfo):
+                assert opinfo in self.cached_infos
         if (isinstance(res, PreambleOp) and
             optheap.optimizer.cpu.supports_guard_gc_type):
             if not true_force:
@@ -179,10 +212,10 @@
             opinfo.setitem(descr, index, None, res, optheap=optheap)
         return res
 
-    def _setfield(self, op, opinfo, optheap):
+    def put_field_back_to_info(self, op, opinfo, optheap):
         arg = optheap.get_box_replacement(op.getarg(2))
         struct = optheap.get_box_replacement(op.getarg(0))
-        opinfo.setitem(op.getdescr(), self.index, struct, arg, self, optheap)
+        opinfo.setitem(op.getdescr(), self.index, struct, arg, optheap=optheap, cf=self)
 
     def invalidate(self, descr):
         for opinfo in self.cached_infos:
@@ -201,15 +234,11 @@
 
         self.postponed_op = None
 
-        # XXXX the rest is old
-        # cached array items:  {array descr: {index: CachedField}}
-        #self.cached_arrayitems = {}
         # cached dict items: {dict descr: {(optval, index): box-or-const}}
         self.cached_dict_reads = {}
         # cache of corresponding {array descrs: dict 'entries' field descr}
         self.corresponding_array_descrs = {}
         #
-        self._lazy_setfields_and_arrayitems = []
         self._remove_guard_not_invalidated = False
         self._seen_guard_not_invalidated = False
 
@@ -221,7 +250,7 @@
     def flush(self):
         self.cached_dict_reads.clear()
         self.corresponding_array_descrs.clear()
-        self.force_all_lazy_setfields_and_arrayitems()
+        self.force_all_lazy_sets()
         self.emit_postponed_op()
 
     def emit_postponed_op(self):
@@ -234,7 +263,7 @@
         descrkeys = self.cached_fields.keys()
         if not we_are_translated():
             # XXX Pure operation of boxes that are cached in several places will
-            #     only be removed from the peeled loop when red from the first
+            #     only be removed from the peeled loop when read from the first
             #     place discovered here. This is far from ideal, as it makes
             #     the effectiveness of our optimization a bit random. It should
             #     howevere always generate correct results. For tests we dont
@@ -249,14 +278,7 @@
                 d.produce_potential_short_preamble_ops(self.optimizer, sb,
                                                        descr, index)
 
-    def register_dirty_field(self, descr, op, info):
-        self.field_cache(descr).register_dirty_field(op, info)
-
-    def register_dirty_array_field(self, arraydescr, op, index, info):
-        self.arrayitem_cache(arraydescr, index).register_dirty_field(op, info)
-
     def clean_caches(self):
-        del self._lazy_setfields_and_arrayitems[:]
         items = self.cached_fields.items()
         if not we_are_translated():
             items.sort(key=str, reverse=True)
@@ -285,7 +307,7 @@
         try:
             cf = submap[index]
         except KeyError:
-            cf = submap[index] = ArrayCachedField(index)
+            cf = submap[index] = ArrayCachedItem(index)
         return cf
 
     def emit_operation(self, op):        
@@ -304,7 +326,7 @@
             return
         if op.is_guard():
             self.optimizer.pendingfields = (
-                self.force_lazy_setfields_and_arrayitems_for_guard())
+                self.force_lazy_sets_for_guard())
             return
         opnum = op.getopnum()
         if (opnum == rop.SETFIELD_GC or          # handled specially
@@ -332,7 +354,7 @@
                 if not effectinfo.has_random_effects():
                     self.force_from_effectinfo(effectinfo)
                     return
-        self.force_all_lazy_setfields_and_arrayitems()
+        self.force_all_lazy_sets()
         self.clean_caches()
 
     def optimize_CALL_I(self, op):
@@ -410,7 +432,7 @@
         # XXX we can get the wrong complexity here, if the lists
         # XXX stored on effectinfo are large
         for fielddescr in effectinfo.readonly_descrs_fields:
-            self.force_lazy_setfield(fielddescr)
+            self.force_lazy_set(fielddescr)
         for arraydescr in effectinfo.readonly_descrs_arrays:
             self.force_lazy_setarrayitem(arraydescr)
         for fielddescr in effectinfo.write_descrs_fields:
@@ -420,7 +442,7 @@
                 del self.cached_dict_reads[fielddescr]
             except KeyError:
                 pass
-            self.force_lazy_setfield(fielddescr, can_cache=False)
+            self.force_lazy_set(fielddescr, can_cache=False)
         for arraydescr in effectinfo.write_descrs_arrays:
             self.force_lazy_setarrayitem(arraydescr, can_cache=False)
             if arraydescr in self.corresponding_array_descrs:
@@ -431,16 +453,16 @@
                     pass # someone did it already
         if effectinfo.check_forces_virtual_or_virtualizable():
             vrefinfo = self.optimizer.metainterp_sd.virtualref_info
-            self.force_lazy_setfield(vrefinfo.descr_forced)
+            self.force_lazy_set(vrefinfo.descr_forced)
             # ^^^ we only need to force this field; the other fields
             # of virtualref_info and virtualizable_info are not gcptrs.
 
-    def force_lazy_setfield(self, descr, can_cache=True):
+    def force_lazy_set(self, descr, can_cache=True):
         try:
             cf = self.cached_fields[descr]
         except KeyError:
             return
-        cf.force_lazy_setfield(self, descr, can_cache)
+        cf.force_lazy_set(self, descr, can_cache)
 
     def force_lazy_setarrayitem(self, arraydescr, indexb=None, can_cache=True):
         try:
@@ -449,35 +471,35 @@
             return
         for idx, cf in submap.iteritems():
             if indexb is None or indexb.contains(idx):
-                cf.force_lazy_setfield(self, None, can_cache)
+                cf.force_lazy_set(self, None, can_cache)
 
-    def force_all_lazy_setfields_and_arrayitems(self):
+    def force_all_lazy_sets(self):
         items = self.cached_fields.items()
         if not we_are_translated():
             items.sort(key=str, reverse=True)
         for descr, cf in items:
-            cf.force_lazy_setfield(self, descr)
+            cf.force_lazy_set(self, descr)
         for submap in self.cached_arrayitems.itervalues():
             for index, cf in submap.iteritems():
-                cf.force_lazy_setfield(self, None)
+                cf.force_lazy_set(self, None)
 
-    def force_lazy_setfields_and_arrayitems_for_guard(self):
+    def force_lazy_sets_for_guard(self):
         pendingfields = []
         items = self.cached_fields.items()
         if not we_are_translated():
             items.sort(key=str, reverse=True)
         for descr, cf in items:
-            op = cf._lazy_setfield
+            op = cf._lazy_set
             if op is None:
                 continue
             val = op.getarg(1)
             if self.optimizer.is_virtual(val):
                 pendingfields.append(op)
                 continue
-            cf.force_lazy_setfield(self, descr)
+            cf.force_lazy_set(self, descr)
         for descr, submap in self.cached_arrayitems.iteritems():
             for index, cf in submap.iteritems():
-                op = cf._lazy_setfield
+                op = cf._lazy_set
                 if op is None:
                     continue
                 # the only really interesting case that we need to handle in the
@@ -489,7 +511,7 @@
                 if self.optimizer.is_virtual(op.getarg(2)):
                     pendingfields.append(op)
                 else:
-                    cf.force_lazy_setfield(self, descr)                    
+                    cf.force_lazy_set(self, descr)
         return pendingfields
 
     def optimize_GETFIELD_GC_I(self, op):
@@ -503,7 +525,7 @@
         self.make_nonnull(op.getarg(0))
         self.emit_operation(op)
         # then remember the result of reading the field
-        structinfo.setfield(op.getdescr(), op.getarg(0), op, self, cf)
+        structinfo.setfield(op.getdescr(), op.getarg(0), op, optheap=self, cf=cf)
     optimize_GETFIELD_GC_R = optimize_GETFIELD_GC_I
     optimize_GETFIELD_GC_F = optimize_GETFIELD_GC_I
 
@@ -554,12 +576,12 @@
         # default case: produce the operation
         self.make_nonnull(op.getarg(0))
         self.emit_operation(op)
-        # the remember the result of reading the array item
+        # then remember the result of reading the array item
         if cf is not None:
             arrayinfo.setitem(op.getdescr(), indexb.getint(),
                               self.get_box_replacement(op.getarg(0)),
-                              self.get_box_replacement(op), cf,
-                              self)
+                              self.get_box_replacement(op), optheap=self,
+                              cf=cf)
     optimize_GETARRAYITEM_GC_R = optimize_GETARRAYITEM_GC_I
     optimize_GETARRAYITEM_GC_F = optimize_GETARRAYITEM_GC_I
 
diff --git a/rpython/jit/metainterp/optimizeopt/info.py b/rpython/jit/metainterp/optimizeopt/info.py
--- a/rpython/jit/metainterp/optimizeopt/info.py
+++ b/rpython/jit/metainterp/optimizeopt/info.py
@@ -196,28 +196,28 @@
     def all_items(self):
         return self._fields
 
-    def setfield(self, descr, struct, op, optheap=None, cf=None):
-        self.init_fields(descr.get_parent_descr(), descr.get_index())
+    def setfield(self, fielddescr, struct, op, optheap=None, cf=None):
+        self.init_fields(fielddescr.get_parent_descr(), fielddescr.get_index())
         assert isinstance(op, AbstractValue)
-        self._fields[descr.get_index()] = op
+        self._fields[fielddescr.get_index()] = op
         if cf is not None:
             assert not self.is_virtual()
             assert struct is not None
-            cf.register_dirty_field(struct, self)
+            cf.register_info(struct, self)
 
-    def getfield(self, descr, optheap=None):
-        self.init_fields(descr.get_parent_descr(), descr.get_index())
-        return self._fields[descr.get_index()]
+    def getfield(self, fielddescr, optheap=None):
+        self.init_fields(fielddescr.get_parent_descr(), fielddescr.get_index())
+        return self._fields[fielddescr.get_index()]
 
     def _force_elements(self, op, optforce, descr):
         if self._fields is None:
             return
-        for i, flddescr in enumerate(descr.get_all_fielddescrs()):
+        for i, fielddescr in enumerate(descr.get_all_fielddescrs()):
             fld = self._fields[i]
             if fld is not None:
                 subbox = optforce.force_box(fld)
                 setfieldop = ResOperation(rop.SETFIELD_GC, [op, subbox],
-                                          descr=flddescr)
+                                          descr=fielddescr)
                 self._fields[i] = None
                 optforce.emit_operation(setfieldop)
 
@@ -249,16 +249,16 @@
                 if fieldinfo and fieldinfo.is_virtual():
                     fieldinfo.visitor_walk_recursive(op, visitor, optimizer)
 
-    def produce_short_preamble_ops(self, structbox, descr, index, optimizer,
+    def produce_short_preamble_ops(self, structbox, fielddescr, index, optimizer,
                                    shortboxes):
         if self._fields is None:
             return
-        if descr.get_index() >= len(self._fields):
+        if fielddescr.get_index() >= len(self._fields):
             # we don't know about this item
             return
-        op = optimizer.get_box_replacement(self._fields[descr.get_index()])
-        opnum = OpHelpers.getfield_for_descr(descr)
-        getfield_op = ResOperation(opnum, [structbox], descr=descr)
+        op = optimizer.get_box_replacement(self._fields[fielddescr.get_index()])
+        opnum = OpHelpers.getfield_for_descr(fielddescr)
+        getfield_op = ResOperation(opnum, [structbox], descr=fielddescr)
         shortboxes.add_heap_op(op, getfield_op)
 
     def _is_immutable_and_filled_with_constants(self, optimizer, memo=None):
@@ -294,12 +294,12 @@
         return True
 
     def _force_elements_immutable(self, descr, constptr, optforce):
-        for i, flddescr in enumerate(descr.get_all_fielddescrs()):
+        for i, fielddescr in enumerate(descr.get_all_fielddescrs()):
             fld = self._fields[i]
             subbox = optforce.force_box(fld)
             assert isinstance(subbox, Const)
             execute(optforce.optimizer.cpu, None, rop.SETFIELD_GC,
-                    flddescr, constptr, subbox)
+                    fielddescr, constptr, subbox)
 
 class InstancePtrInfo(AbstractStructPtrInfo):
     _attrs_ = ('_known_class',)
@@ -505,6 +505,7 @@
             info._items = self._items[:]
 
     def _force_elements(self, op, optforce, descr):
+        # XXX
         descr = op.getdescr()
         const = optforce.new_const_item(self.descr)
         for i in range(self.length):
@@ -523,15 +524,16 @@
             optforce.emit_operation(setop)
         optforce.pure_from_args(rop.ARRAYLEN_GC, [op], ConstInt(len(self._items)))
 
-    def setitem(self, descr, index, struct, op, cf=None, optheap=None):
+    def setitem(self, descr, index, struct, op, optheap=None, cf=None):
         if self._items is None:
             self._items = [None] * (index + 1)
         if index >= len(self._items):
+            assert not self.is_virtual()
             self._items = self._items + [None] * (index - len(self._items) + 1)
         self._items[index] = op
         if cf is not None:
             assert not self.is_virtual()
-            cf.register_dirty_field(struct, self)
+            cf.register_info(struct, self)
 
     def getitem(self, descr, index, optheap=None):
         if self._items is None or index >= len(self._items):
@@ -626,13 +628,13 @@
         i = 0
         fielddescrs = op.getdescr().get_all_fielddescrs()
         for index in range(self.length):
-            for flddescr in fielddescrs:
+            for fielddescr in fielddescrs:
                 fld = self._items[i]
                 if fld is not None:
                     subbox = optforce.force_box(fld)
                     setfieldop = ResOperation(rop.SETINTERIORFIELD_GC,
                                               [op, ConstInt(index), subbox],
-                                              descr=flddescr)
+                                              descr=fielddescr)
                     optforce.emit_operation(setfieldop)
                     # heapcache does not work for interiorfields
                     # if it does, we would need a fix here
@@ -645,7 +647,7 @@
         fielddescrs = self.descr.get_all_fielddescrs()
         i = 0
         for index in range(self.getlength()):
-            for flddescr in fielddescrs:
+            for fielddescr in fielddescrs:
                 itemop = self._items[i]
                 if (itemop is not None and
                     not isinstance(itemop, Const)):
@@ -691,21 +693,21 @@
             optheap.const_infos[ref] = info
         return info        
 
-    def getfield(self, descr, optheap=None):
-        info = self._get_info(descr.get_parent_descr(), optheap)
-        return info.getfield(descr)
+    def getfield(self, fielddescr, optheap=None):
+        info = self._get_info(fielddescr.get_parent_descr(), optheap)
+        return info.getfield(fielddescr)
 
     def getitem(self, descr, index, optheap=None):
         info = self._get_array_info(descr, optheap)
         return info.getitem(descr, index)
 
-    def setitem(self, descr, index, struct, op, cf=None, optheap=None):
+    def setitem(self, descr, index, struct, op, optheap=None, cf=None):
         info = self._get_array_info(descr, optheap)
-        info.setitem(descr, index, struct, op, cf)
+        info.setitem(descr, index, struct, op, optheap=optheap, cf=cf)
 
-    def setfield(self, descr, struct, op, optheap=None, cf=None):
-        info = self._get_info(descr.get_parent_descr(), optheap)
-        info.setfield(descr, struct, op, optheap, cf)
+    def setfield(self, fielddescr, struct, op, optheap=None, cf=None):
+        info = self._get_info(fielddescr.get_parent_descr(), optheap)
+        info.setfield(fielddescr, struct, op, optheap=optheap, cf=cf)
 
     def is_null(self):
         return not bool(self._const.getref_base())
diff --git a/rpython/jit/metainterp/optimizeopt/shortpreamble.py b/rpython/jit/metainterp/optimizeopt/shortpreamble.py
--- a/rpython/jit/metainterp/optimizeopt/shortpreamble.py
+++ b/rpython/jit/metainterp/optimizeopt/shortpreamble.py
@@ -81,7 +81,7 @@
             assert index >= 0
             cf = optheap.arrayitem_cache(descr, index)
             opinfo.setitem(self.getfield_op.getdescr(), index, self.res,
-                           pop, cf, optheap=optheap)
+                           pop, optheap, cf)
 
     def repr(self, memo):
         return "HeapOp(%s, %s)" % (self.res.repr(memo),
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -696,58 +696,6 @@
 
     # ----------
 
-    def test_virtual_1(self):
-        ops = """
-        [i, p0]
-        i0 = getfield_gc(p0, descr=valuedescr)
-        i1 = int_add(i0, i)
-        setfield_gc(p0, i1, descr=valuedescr)
-        jump(i, p0)
-        """
-        expected = """
-        [i, i2]
-        i1 = int_add(i2, i)
-        jump(i, i1)
-        """
-        py.test.skip("XXX")
-        self.optimize_loop(ops, 'Not, Virtual(node_vtable, valuedescr=Not)',
-                           expected)
-
-    def test_virtual_float(self):
-        ops = """
-        [f, p0]
-        f0 = getfield_gc(p0, descr=floatdescr)
-        f1 = float_add(f0, f)
-        setfield_gc(p0, f1, descr=floatdescr)
-        jump(f, p0)
-        """
-        expected = """
-        [f, f2]
-        f1 = float_add(f2, f)
-        jump(f, f1)
-        """
-        py.test.skip("XXX")
-        self.optimize_loop(ops, 'Not, Virtual(node_vtable, floatdescr=Not)',
-                           expected)
-
-    def test_virtual_2(self):
-        py.test.skip("XXX")
-        ops = """
-        [i, p0]
-        i0 = getfield_gc(p0, descr=valuedescr)
-        i1 = int_add(i0, i)
-        p1 = new_with_vtable(ConstClass(node_vtable))
-        setfield_gc(p1, i1, descr=valuedescr)
-        jump(i, p1)
-        """
-        expected = """
-        [i, i2]
-        i1 = int_add(i2, i)
-        jump(i, i1)
-        """
-        self.optimize_loop(ops, 'Not, Virtual(node_vtable, valuedescr=Not)',
-                           expected)
-
     def test_virtual_oois(self):
         ops = """
         [p0, p1, p2]
@@ -774,20 +722,6 @@
         guard_false(i12) []
         jump(p0, p1, p2)
         """
-        expected = """
-        [p2]
-        # all constant-folded :-)
-        jump(p2)
-        """
-        py.test.skip("XXX")
-        self.optimize_loop(ops, '''Virtual(node_vtable),
-                                   Virtual(node_vtable),
-                                   Not''',
-                           expected)
-        #
-        # to be complete, we also check the no-opt case where most comparisons
-        # are not removed.  The exact set of comparisons removed depends on
-        # the details of the algorithm...
         expected2 = """
         [p0, p1, p2]
         guard_nonnull(p0) []
@@ -801,26 +735,6 @@
         """
         self.optimize_loop(ops, expected2)
 
-    def test_virtual_default_field(self):
-        py.test.skip("XXX")
-        ops = """
-        [p0]
-        i0 = getfield_gc(p0, descr=valuedescr)
-        guard_value(i0, 0) []
-        p1 = new_with_vtable(ConstClass(node_vtable))
-        # the field 'value' has its default value of 0
-        jump(p1)
-        """
-        expected = """
-        [i]
-        guard_value(i, 0) []
-        jump(0)
-        """
-        # the 'expected' is sub-optimal, but it should be done by another later
-        # optimization step.  See test_find_nodes_default_field() for why.
-        self.optimize_loop(ops, 'Virtual(node_vtable, valuedescr=Not)',
-                           expected)
-
     def test_virtual_3(self):
         ops = """
         [i]
@@ -837,55 +751,6 @@
         """
         self.optimize_loop(ops, expected)
 
-    def test_virtual_4(self):
-        py.test.skip("XXX")
-        ops = """
-        [i0, p0]
-        guard_class(p0, ConstClass(node_vtable)) []
-        i1 = getfield_gc(p0, descr=valuedescr)
-        i2 = int_sub(i1, 1)
-        i3 = int_add(i0, i1)
-        p1 = new_with_vtable(descr=nodesize)
-        setfield_gc(p1, i2, descr=valuedescr)
-        jump(i3, p1)
-        """
-        expected = """
-        [i0, i1]
-        i2 = int_sub(i1, 1)
-        i3 = int_add(i0, i1)
-        jump(i3, i2)
-        """
-        self.optimize_loop(ops, 'Not, Virtual(node_vtable, valuedescr=Not)',
-                           expected)
-
-    def test_virtual_5(self):
-        py.test.skip("XXX")
-        ops = """
-        [i0, p0]
-        guard_class(p0, ConstClass(node_vtable)) []
-        i1 = getfield_gc(p0, descr=valuedescr)
-        i2 = int_sub(i1, 1)
-        i3 = int_add(i0, i1)
-        p2 = new_with_vtable(descr=nodesize2)
-        setfield_gc(p2, i1, descr=valuedescr)
-        p1 = new_with_vtable(descr=nodesize)
-        setfield_gc(p1, i2, descr=valuedescr)
-        setfield_gc(p1, p2, descr=nextdescr)
-        jump(i3, p1)
-        """
-        expected = """
-        [i0, i1, i1bis]
-        i2 = int_sub(i1, 1)
-        i3 = int_add(i0, i1)
-        jump(i3, i2, i1)
-        """
-        self.optimize_loop(ops,
-            '''Not, Virtual(node_vtable,
-                            valuedescr=Not,
-                            nextdescr=Virtual(node_vtable2,
-                                              valuedescr=Not))''',
-                           expected)
-
     def test_virtual_constant_isnull(self):
         ops = """
         [i0]
@@ -1209,27 +1074,6 @@
         """
         self.optimize_loop(ops, expected)
 
-    def test_varray_2(self):
-        ops = """
-        [i0, p1]
-        i1 = getarrayitem_gc(p1, 0, descr=arraydescr)
-        i2 = getarrayitem_gc(p1, 1, descr=arraydescr)
-        i3 = int_sub(i1, i2)
-        guard_value(i3, 15) []
-        p2 = new_array(2, descr=arraydescr)
-        setarrayitem_gc(p2, 1, i0, descr=arraydescr)
-        setarrayitem_gc(p2, 0, 20, descr=arraydescr)
-        jump(i0, p2)
-        """
-        expected = """
-        [i0, i1, i2]
-        i3 = int_sub(i1, i2)
-        guard_value(i3, 15) []
-        jump(i0, 20, i0)
-        """
-        py.test.skip("XXX")
-        self.optimize_loop(ops, 'Not, VArray(arraydescr, Not, Not)', expected)
-
     def test_p123_array(self):
         ops = """
         [i1, p2, p3]
@@ -1264,23 +1108,6 @@
         """
         self.optimize_loop(ops, expected)
 
-    def test_vstruct_1(self):
-        py.test.skip("XXX")
-        ops = """
-        [i1, p2]
-        i2 = getfield_gc(p2, descr=adescr)
-        escape_n(i2)
-        p3 = new(descr=ssize)
-        setfield_gc(p3, i1, descr=adescr)
-        jump(i1, p3)
-        """
-        expected = """
-        [i1, i2]
-        escape_n(i2)
-        jump(i1, i1)
-        """
-        self.optimize_loop(ops, 'Not, VStruct(ssize, adescr=Not)', expected)
-
     def test_p123_vstruct(self):
         ops = """
         [i1, p2, p3]
@@ -1443,26 +1270,6 @@
         """
         self.optimize_loop(ops, expected)
 
-    def test_duplicate_getfield_guard_value_const(self):
-        ops = """
-        [p1]
-        guard_value(p1, ConstPtr(myptr)) []
-        i1 = getfield_gc_i(p1, descr=valuedescr)
-        i2 = getfield_gc_i(ConstPtr(myptr), descr=valuedescr)
-        escape_n(i1)
-        escape_n(i2)
-        jump(p1)
-        """
-        expected = """
-        []
-        i1 = getfield_gc_i(ConstPtr(myptr), descr=valuedescr)
-        escape_n(i1)
-        escape_n(i1)
-        jump()
-        """
-        py.test.skip("XXX")
-        self.optimize_loop(ops, 'Constant(myptr)', expected)
-
     def test_duplicate_getfield_sideeffects_1(self):
         ops = """
         [p1]
@@ -1688,12 +1495,12 @@
         jump(p1, i1, i2)
         """
         expected = """
-        [i1, i2]
+        [p1, i1, i2]
+        guard_value(p1, ConstPtr(myptr)) []
         setfield_gc(ConstPtr(myptr), i2, descr=valuedescr)
-        jump(i1, i2)
-        """
-        py.test.skip("XXX")
-        self.optimize_loop(ops, 'Constant(myptr), Not, Not', expected)
+        jump(ConstPtr(myptr), i1, i2)
+        """
+        self.optimize_loop(ops, expected)
 
     def test_duplicate_getarrayitem_1(self):
         ops = """
@@ -1870,163 +1677,7 @@
         """
         self.optimize_loop(ops, expected)
 
-    def test_bug_1(self):
-        ops = """
-        [i0, p1]
-        p4 = getfield_gc_r(p1, descr=nextdescr)
-        guard_nonnull(p4) []
-        escape_n(p4)
-        #
-        p2 = new_with_vtable(descr=nodesize)
-        p3 = escape_r()
-        setfield_gc(p2, p3, descr=nextdescr)
-        jump(i0, p2)
-        """
-        expected = """
-        [i0, p4]
-        guard_nonnull(p4) []
-        escape_n(p4)
-        #
-        p3 = escape_r()
-        jump(i0, p3)
-        """
-        py.test.skip("XXX")
-        self.optimize_loop(ops, 'Not, Virtual(node_vtable, nextdescr=Not)',
-                           expected)
-
-    def test_bug_2(self):
-        ops = """
-        [i0, p1]
-        p4 = getarrayitem_gc(p1, 0, descr=arraydescr2)
-        guard_nonnull(p4) []
-        escape_n(p4)
-        #
-        p2 = new_array(1, descr=arraydescr2)
-        p3 = escape_r()
-        setarrayitem_gc(p2, 0, p3, descr=arraydescr2)
-        jump(i0, p2)
-        """
-        expected = """
-        [i0, p4]
-        guard_nonnull(p4) []
-        escape_n(p4)
-        #
-        p3 = escape_r()
-        jump(i0, p3)
-        """
-        py.test.skip("XXX")
-        self.optimize_loop(ops, 'Not, VArray(arraydescr2, Not)',
-                           expected)
-
-    def test_bug_3(self):
-        ops = """
-        [p1]
-        guard_nonnull(p1) []
-        guard_class(p1, ConstClass(node_vtable2)) []
-        p2 = getfield_gc_r(p1, descr=nextdescr)
-        guard_nonnull(12) []
-        guard_class(p2, ConstClass(node_vtable)) []
-        p3 = getfield_gc_r(p1, descr=otherdescr)
-        guard_nonnull(12) []
-        guard_class(p3, ConstClass(node_vtable)) []
-        setfield_gc(p3, p2, descr=otherdescr)
-        p1a = new_with_vtable(ConstClass(node_vtable2))
-        p2a = new_with_vtable(descr=nodesize)
-        p3a = new_with_vtable(descr=nodesize)
-        escape_n(p3a)
-        setfield_gc(p1a, p2a, descr=nextdescr)
-        setfield_gc(p1a, p3a, descr=otherdescr)
-        jump(p1a)
-        """
-        expected = """
-        [p2, p3]
-        guard_class(p2, ConstClass(node_vtable)) []
-        guard_class(p3, ConstClass(node_vtable)) []
-        setfield_gc(p3, p2, descr=otherdescr)
-        p3a = new_with_vtable(descr=nodesize)
-        escape_n(p3a)
-        p2a = new_with_vtable(descr=nodesize)
-        jump(p2a, p3a)
-        """
-        py.test.skip("XXX")
-        self.optimize_loop(ops, 'Virtual(node_vtable2, nextdescr=Not, otherdescr=Not)', expected)
-
-    def test_bug_3bis(self):
-        ops = """
-        [p1]
-        guard_nonnull(p1) []
-        guard_class(p1, ConstClass(node_vtable2)) []
-        p2 = getfield_gc_r(p1, descr=nextdescr)
-        guard_nonnull(12) []
-        guard_class(p2, ConstClass(node_vtable)) []
-        p3 = getfield_gc_r(p1, descr=otherdescr)
-        guard_nonnull(12) []
-        guard_class(p3, ConstClass(node_vtable)) []
-        p1a = new_with_vtable(ConstClass(node_vtable2))
-        p2a = new_with_vtable(descr=nodesize)
-        setfield_gc(p3, p2a, descr=otherdescr)
-        p3a = new_with_vtable(descr=nodesize)
-        escape_n(p3a)
-        setfield_gc(p1a, p2a, descr=nextdescr)
-        setfield_gc(p1a, p3a, descr=otherdescr)
-        jump(p1a)
-        """
-        expected = """
-        [p2, p3]
-        guard_class(p2, ConstClass(node_vtable)) []
-        guard_class(p3, ConstClass(node_vtable)) []
-        p2a = new_with_vtable(descr=nodesize)
-        setfield_gc(p3, p2a, descr=otherdescr)
-        p3a = new_with_vtable(descr=nodesize)
-        escape_n(p3a)
-        jump(p2a, p3a)
-        """
-        py.test.skip("XXX")
-        self.optimize_loop(ops, 'Virtual(node_vtable2, nextdescr=Not, otherdescr=Not)', expected)
-
-    def test_invalid_loop_1(self):
-        ops = """
-        [p1]
-        guard_isnull(p1) []
-        #
-        p2 = new_with_vtable(descr=nodesize)
-        jump(p2)
-        """
-        py.test.skip("XXX")
-        py.test.raises(InvalidLoop, self.optimize_loop,
-                       ops, 'Virtual(node_vtable)', None)
-
-    def test_invalid_loop_2(self):
-        py.test.skip("this would fail if we had Fixed again in the specnodes")
-        ops = """
-        [p1]
-        guard_class(p1, ConstClass(node_vtable2)) []
-        #
-        p2 = new_with_vtable(descr=nodesize)
-        escape_n(p2)      # prevent it from staying Virtual
-        jump(p2)
-        """
-        py.test.raises(InvalidLoop, self.optimize_loop,
-                       ops, '...', None)
-
-    def test_invalid_loop_3(self):
-        ops = """
-        [p1]
-        p2 = getfield_gc_r(p1, descr=nextdescr)
-        guard_isnull(p2) []
-        #
-        p3 = new_with_vtable(descr=nodesize)
-        p4 = new_with_vtable(descr=nodesize)
-        setfield_gc(p3, p4, descr=nextdescr)
-        jump(p3)
-        """
-        py.test.skip("XXX")
-        py.test.raises(InvalidLoop, self.optimize_loop, ops,
-                       'Virtual(node_vtable, nextdescr=Virtual(node_vtable))',
-                       None)
-
     def test_merge_guard_class_guard_value(self):
-        py.test.skip("disabled")
         ops = """
         [p1, i0, i1, i2, p2]
         guard_class(p1, ConstClass(node_vtable)) [i0]
@@ -2060,7 +1711,6 @@
         self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS)
 
     def test_merge_guard_nonnull_guard_value(self):
-        py.test.skip("disabled")
         ops = """
         [p1, i0, i1, i2, p2]
         guard_nonnull(p1) [i0]
@@ -2078,7 +1728,6 @@
         self.check_expanded_fail_descr("i0", rop.GUARD_VALUE)
 
     def test_merge_guard_nonnull_guard_class_guard_value(self):
-        py.test.skip("disabled")        
         ops = """
         [p1, i0, i1, i2, p2]
         guard_nonnull(p1) [i0]
@@ -2625,26 +2274,6 @@
             where p2 is a node_vtable, valuedescr=i2, nextdescr=p1
             ''', rop.GUARD_TRUE)
 
-    def test_expand_fail_6(self):
-        ops = """
-        [p0, i0, i1]
-        guard_true(i0) [p0]
-        p1 = new_with_vtable(descr=nodesize)
-        setfield_gc(p1, i1, descr=valuedescr)
-        jump(p1, i1, i1)
-        """
-        expected = """
-        [i1b, i0, i1]
-        guard_true(i0) [i1b]
-        jump(i1, i1, i1)
-        """
-        py.test.skip("XXX")
-        self.optimize_loop(ops, '''Virtual(node_vtable, valuedescr=Not),
-                                   Not, Not''', expected)
-        self.check_expanded_fail_descr('''p0
-            where p0 is a node_vtable, valuedescr=i1b
-            ''', rop.GUARD_TRUE)
-
     def test_expand_fail_varray(self):
         ops = """
         [i1]
@@ -2686,47 +2315,6 @@
             where p2 is a vstruct ssize, adescr=i1, bdescr=p1
             ''', rop.GUARD_TRUE)
 
-    def test_expand_fail_v_all_1(self):
-        ops = """
-        [i1, p1a, i2]
-        p6s = getarrayitem_gc(p1a, 0, descr=arraydescr2)
-        p7v = getfield_gc_r(p6s, descr=bdescr)
-        p5s = new(descr=ssize)
-        setfield_gc(p5s, i2, descr=adescr)
-        setfield_gc(p5s, p7v, descr=bdescr)
-        setarrayitem_gc(p1a, 1, p5s, descr=arraydescr2)
-        guard_true(i1) [p1a]
-        p2s = new(descr=ssize)
-        p3v = new_with_vtable(descr=nodesize)
-        p4a = new_array(2, descr=arraydescr2)
-        setfield_gc(p2s, i1, descr=adescr)
-        setfield_gc(p2s, p3v, descr=bdescr)
-        setfield_gc(p3v, i2, descr=valuedescr)
-        setarrayitem_gc(p4a, 0, p2s, descr=arraydescr2)
-        jump(i1, p4a, i2)
-        """
-        expected = """
-        [i1, ia, iv, pnull, i2]
-        guard_true(i1) [ia, iv, i2]
-        jump(1, 1, i2, NULL, i2)
-        """
-        py.test.skip("XXX")
-        self.optimize_loop(ops, '''
-            Not,
-            VArray(arraydescr2,
-                   VStruct(ssize,
-                           adescr=Not,
-                           bdescr=Virtual(node_vtable,
-                                          valuedescr=Not)),
-                   Not),
-            Not''', expected)
-        self.check_expanded_fail_descr('''p1a
-            where p1a is a varray arraydescr2: p6s, p5s
-            where p6s is a vstruct ssize, adescr=ia, bdescr=p7v
-            where p5s is a vstruct ssize, adescr=i2, bdescr=p7v
-            where p7v is a node_vtable, valuedescr=iv
-            ''', rop.GUARD_TRUE)
-
     def test_expand_fail_lazy_setfield_1(self):
         ops = """
         [p1, i2, i3]
@@ -5179,6 +4767,8 @@
         """
         self.optimize_loop(ops, expected)
 
+    def test_intmod_bounds_harder(self):
+        py.test.skip("harder")
         # Of course any 'maybe-negative % power-of-two' can be turned into
         # int_and(), but that's a bit harder to detect here because it turns
         # into several operations, and of course it is wrong to just turn
@@ -5196,7 +4786,6 @@
         i4 = int_and(i0, 15)
         finish(i4)
         """
-        py.test.skip("harder")
         self.optimize_loop(ops, expected)
 
     def test_intmod_bounds_bug1(self):
@@ -5357,7 +4946,7 @@
         i5 = int_lt(i2, i1)
         guard_true(i5) []
 
-        i6 = getarrayitem_gc(p0, i2)
+        i6 = getarrayitem_gc_i(p0, i2, descr=chararraydescr)
         finish(i6)
         """
         expected = """
@@ -5368,7 +4957,7 @@
         i4 = int_lt(i2, i0)
         guard_true(i4) []
 
-        i6 = getarrayitem_gc(p0, i3)
+        i6 = getarrayitem_gc_i(p0, i3, descr=chararraydescr)
         finish(i6)
         """
         self.optimize_loop(ops, expected)
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -2969,7 +2969,6 @@
             assert "promote of a virtual" in exc.msg
 
     def test_merge_guard_class_guard_value(self):
-        py.test.skip("disabled")
         ops = """
         [p1, i0, i1, i2, p2]
         guard_class(p1, ConstClass(node_vtable)) [i0]
@@ -3015,7 +3014,6 @@
         #self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS)
 
     def test_merge_guard_nonnull_guard_value(self):
-        py.test.skip("disabled")
         ops = """
         [p1, i0, i1, i2, p2]
         guard_nonnull(p1) [i0]
@@ -3039,7 +3037,6 @@
         #self.check_expanded_fail_descr("i0", rop.GUARD_VALUE)
 
     def test_merge_guard_nonnull_guard_class_guard_value(self):
-        py.test.skip("disabled")
         ops = """
         [p1, i0, i1, i2, p2]
         guard_nonnull(p1) [i0]
diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -35,15 +35,11 @@
                 return True
         return graphanalyze.BoolGraphAnalyzer.analyze_direct_call(self, graph,
                                                                   seen)
-    def analyze_external_call(self, op, seen=None):
-        try:
-            funcobj = op.args[0].value._obj
-        except lltype.DelayedPointer:
+    def analyze_external_call(self, funcobj, seen=None):
+        if funcobj.random_effects_on_gcobjs:
             return True
-        if getattr(funcobj, 'random_effects_on_gcobjs', False):
-            return True
-        return graphanalyze.BoolGraphAnalyzer.analyze_external_call(self, op,
-                                                                    seen)
+        return graphanalyze.BoolGraphAnalyzer.analyze_external_call(
+            self, funcobj, seen)
     def analyze_simple_operation(self, op, graphinfo):
         if op.opname in ('malloc', 'malloc_varsize'):
             flags = op.args[1].value
diff --git a/rpython/rlib/rstacklet.py b/rpython/rlib/rstacklet.py
--- a/rpython/rlib/rstacklet.py
+++ b/rpython/rlib/rstacklet.py
@@ -1,7 +1,7 @@
 import sys
 from rpython.rlib import _rffi_stacklet as _c
 from rpython.rlib import jit
-from rpython.rlib.objectmodel import we_are_translated
+from rpython.rlib.objectmodel import fetch_translated_config
 from rpython.rtyper.lltypesystem import lltype, llmemory
 
 DEBUG = False
@@ -10,8 +10,8 @@
 class StackletThread(object):
 
     @jit.dont_look_inside
-    def __init__(self, config):
-        self._gcrootfinder = _getgcrootfinder(config, we_are_translated())
+    def __init__(self, _argument_ignored_for_backward_compatibility=None):
+        self._gcrootfinder = _getgcrootfinder(fetch_translated_config())
         self._thrd = _c.newthread()
         if not self._thrd:
             raise MemoryError
@@ -67,11 +67,8 @@
 
 # ____________________________________________________________
 
-def _getgcrootfinder(config, translated):
-    if translated:
-        assert config is not None, ("you have to pass a valid config, "
-                                    "e.g. from 'driver.config'")
-    elif '__pypy__' in sys.builtin_module_names:
+def _getgcrootfinder(config):
+    if config is None and '__pypy__' in sys.builtin_module_names:
         import py
         py.test.skip("cannot run the stacklet tests on top of pypy: "
                      "calling directly the C function stacklet_switch() "
diff --git a/rpython/rlib/test/test_rstacklet.py b/rpython/rlib/test/test_rstacklet.py
--- a/rpython/rlib/test/test_rstacklet.py
+++ b/rpython/rlib/test/test_rstacklet.py
@@ -17,10 +17,9 @@
 
 class Runner:
     STATUSMAX = 5000
-    config = None
 
     def init(self, seed):
-        self.sthread = rstacklet.StackletThread(self.config)
+        self.sthread = rstacklet.StackletThread()
         self.random = rrandom.Random(seed)
 
     def done(self):
@@ -301,12 +300,11 @@
             config.translation.gcrootfinder = cls.gcrootfinder
             GCROOTFINDER = cls.gcrootfinder
         cls.config = config
-        cls.old_values = Runner.config, Runner.STATUSMAX
-        Runner.config = config
+        cls.old_status_max = Runner.STATUSMAX
         Runner.STATUSMAX = 25000
 
     def teardown_class(cls):
-        Runner.config, Runner.STATUSMAX = cls.old_values
+        Runner.STATUSMAX = cls.old_status_max
 
     def test_demo1(self):
         t, cbuilder = self.compile(entry_point)
diff --git a/rpython/rtyper/rtyper.py b/rpython/rtyper/rtyper.py
--- a/rpython/rtyper/rtyper.py
+++ b/rpython/rtyper/rtyper.py
@@ -22,7 +22,7 @@
 from rpython.rtyper.error import TyperError
 from rpython.rtyper.exceptiondata import ExceptionData
 from rpython.rtyper.lltypesystem.lltype import (Signed, Void, LowLevelType,
-    Ptr, ContainerType, FuncType, functionptr, typeOf, RuntimeTypeInfo,
+    Ptr, ContainerType, FuncType, typeOf, RuntimeTypeInfo,
     attachRuntimeTypeInfo, Primitive, getfunctionptr)
 from rpython.rtyper.rmodel import Repr, inputconst, BrokenReprTyperError
 from rpython.rtyper import rclass
@@ -876,18 +876,6 @@
         return self.genop('direct_call', [c]+newargs_v,
                           resulttype = typeOf(fobj).RESULT)
 
-    def genexternalcall(self, fnname, args_v, resulttype=None, **flags):
-        if isinstance(resulttype, Repr):
-            resulttype = resulttype.lowleveltype
-        argtypes = [v.concretetype for v in args_v]
-        FUNCTYPE = FuncType(argtypes, resulttype or Void)
-        f = functionptr(FUNCTYPE, fnname, **flags)
-        cf = inputconst(typeOf(f), f)
-        return self.genop('direct_call', [cf]+list(args_v), resulttype)
-
-    def gencapicall(self, cfnname, args_v, resulttype=None, **flags):
-        return self.genexternalcall(cfnname, args_v, resulttype=resulttype, external="CPython", **flags)
-
     def genconst(self, ll_value):
         return inputconst(typeOf(ll_value), ll_value)
 
diff --git a/rpython/translator/backendopt/canraise.py b/rpython/translator/backendopt/canraise.py
--- a/rpython/translator/backendopt/canraise.py
+++ b/rpython/translator/backendopt/canraise.py
@@ -22,8 +22,7 @@
             log.WARNING("Unknown operation: %s" % op.opname)
             return True
 
-    def analyze_external_call(self, op, seen=None):
-        fnobj = op.args[0].value._obj
+    def analyze_external_call(self, fnobj, seen=None):
         return getattr(fnobj, 'canraise', True)
 
     analyze_exceptblock = None    # don't call this
diff --git a/rpython/translator/backendopt/gilanalysis.py b/rpython/translator/backendopt/gilanalysis.py
--- a/rpython/translator/backendopt/gilanalysis.py
+++ b/rpython/translator/backendopt/gilanalysis.py
@@ -21,12 +21,8 @@
             self, graph, seen)
 
     def analyze_external_call(self, op, seen=None):
-        funcobj = op.args[0].value._obj
-        if getattr(funcobj, 'transactionsafe', False):
-            return False
-        else:
-            return False
-                
+        return False
+
     def analyze_simple_operation(self, op, graphinfo):
         return False
 
diff --git a/rpython/translator/backendopt/graphanalyze.py b/rpython/translator/backendopt/graphanalyze.py
--- a/rpython/translator/backendopt/graphanalyze.py
+++ b/rpython/translator/backendopt/graphanalyze.py
@@ -1,5 +1,4 @@
 from rpython.rtyper.lltypesystem.lltype import DelayedPointer
-from rpython.translator.simplify import get_graph
 from rpython.tool.algo.unionfind import UnionFind
 
 
@@ -55,11 +54,7 @@
     def analyze_startblock(self, block, seen=None):
         return self.bottom_result()
 
-    def analyze_external_call(self, op, seen=None):
-        try:
-            funcobj = op.args[0].value._obj
-        except DelayedPointer:
-            return self.bottom_result()
+    def analyze_external_call(self, funcobj, seen=None):
         result = self.bottom_result()
         if hasattr(funcobj, '_callbacks'):
             bk = self.translator.annotator.bookkeeper
@@ -80,12 +75,24 @@
 
     def analyze(self, op, seen=None, graphinfo=None):
         if op.opname == "direct_call":
-            graph = get_graph(op.args[0], self.translator)
-            if graph is None:
-                x = self.analyze_external_call(op, seen)
+            try:
+                funcobj = op.args[0].value._obj
+            except DelayedPointer:
+                return self.top_result()
+            if funcobj is None:
+                # We encountered a null pointer.  Calling it will crash.
+                # However, the call could be on a dead path, so we return the
+                # bottom result here.
+                return self.bottom_result()
+            if getattr(funcobj, 'external', None) is not None:
+                x = self.analyze_external_call(funcobj, seen)
                 if self.verbose and x:
                     self.dump_info('analyze_external_call %s: %r' % (op, x))
                 return x
+            try:
+                graph = funcobj.graph
+            except AttributeError:
+                return self.top_result()
             x = self.analyze_direct_call(graph, seen)
             if self.verbose and x:
                 self.dump_info('analyze_direct_call(%s): %r' % (graph, x))
diff --git a/rpython/translator/backendopt/test/test_canraise.py b/rpython/translator/backendopt/test/test_canraise.py
--- a/rpython/translator/backendopt/test/test_canraise.py
+++ b/rpython/translator/backendopt/test/test_canraise.py
@@ -204,8 +204,7 @@
         result = ra.can_raise(fgraph.startblock.operations[0])
         assert not result
 
-        z = lltype.functionptr(lltype.FuncType([lltype.Signed], lltype.Signed),
-                               'foobar')
+        z = llexternal('z', [lltype.Signed], lltype.Signed)
         def g(x):
             return z(x)
         t, ra = self.translate(g, [int])
diff --git a/rpython/translator/backendopt/test/test_graphanalyze.py b/rpython/translator/backendopt/test/test_graphanalyze.py
--- a/rpython/translator/backendopt/test/test_graphanalyze.py
+++ b/rpython/translator/backendopt/test/test_graphanalyze.py
@@ -1,7 +1,7 @@
 import random
 from rpython.tool.algo.unionfind import UnionFind
-from rpython.translator.backendopt.graphanalyze import Dependency
-from rpython.translator.backendopt.graphanalyze import DependencyTracker
+from rpython.translator.backendopt.graphanalyze import (Dependency,
+    DependencyTracker, BoolGraphAnalyzer)
 
 
 class FakeGraphAnalyzer:
@@ -49,3 +49,30 @@
             method1 = rectrack(n, tracker)
             method2 = expected(n)
             assert method1 == method2
+
+
+def test_delayed_fnptr():
+    from rpython.flowspace.model import SpaceOperation
+    from rpython.rtyper.annlowlevel import MixLevelHelperAnnotator
+    from rpython.translator.translator import TranslationContext
+    t = TranslationContext()
+    t.buildannotator()
+    t.buildrtyper()
+    annhelper = MixLevelHelperAnnotator(t.rtyper)
+    def f():
+        pass
+    c_f = annhelper.constfunc(f, [], None)
+    op = SpaceOperation('direct_call', [c_f], None)
+    analyzer = BoolGraphAnalyzer(t)
+    assert analyzer.analyze(op)
+
+
+def test_null_fnptr():
+    from rpython.flowspace.model import SpaceOperation, Constant
+    from rpython.rtyper.lltypesystem.lltype import Void, FuncType, nullptr
+    from rpython.translator.translator import TranslationContext
+    t = TranslationContext()
+    fnptr = nullptr(FuncType([], Void))
+    op = SpaceOperation('direct_call', [Constant(fnptr)], None)
+    analyzer = BoolGraphAnalyzer(t)
+    assert not analyzer.analyze(op)
diff --git a/rpython/translator/simplify.py b/rpython/translator/simplify.py
--- a/rpython/translator/simplify.py
+++ b/rpython/translator/simplify.py
@@ -24,22 +24,13 @@
     if not isinstance(f, lltype._ptr):
         return None
     try:
-        funcobj = f._getobj()
+        funcobj = f._obj
     except lltype.DelayedPointer:
         return None
     try:
-        callable = funcobj._callable
-    except (AttributeError, KeyError, AssertionError):
-        return None
-    try:
         return funcobj.graph
     except AttributeError:
         return None
-    try:
-        callable = funcobj._callable
-        return translator._graphof(callable)
-    except (AttributeError, KeyError, AssertionError):
-        return None
 
 
 def replace_exitswitch_by_constant(block, const):


More information about the pypy-commit mailing list