Commits

Armin Rigo  committed b138acc Merge

hg merge result-in-resops

  • Participants
  • Parent commits 579992e, d0dcc32
  • Branches no-failargs

Comments (0)

Files changed (12)

File pypy/jit/metainterp/optimizeopt/heap.py

         #      value pending in the ResOperation is *not* visible in
         #      'cached_fields'.
         #
+
+        # XXXX kill dicts here
         self._cached_fields = {}
         self._cached_fields_getfield_op = {}
         self._lazy_setfield = None
 
     def do_setfield(self, optheap, op):
         # Update the state with the SETFIELD_GC/SETARRAYITEM_GC operation 'op'.
-        structvalue = optheap.getvalue(op.getarg(0))
-        fieldvalue  = optheap.getvalue(op.getarglist()[-1])
+        structvalue = optheap.getforwarded(op.getarg(0))
+        fieldvalue  = optheap.getforwarded(op.getarglist()[-1])
         if self.possible_aliasing(optheap, structvalue):
             self.force_lazy_setfield(optheap)
             assert not self.possible_aliasing(optheap, structvalue)
             optheap.optimizer.ensure_imported(cached_fieldvalue)
             cached_fieldvalue = self._cached_fields.get(structvalue, None)
 
-        if not fieldvalue.same_value(cached_fieldvalue):
+        if not optheap.optimizer.same_value(fieldvalue, cached_fieldvalue):
             # common case: store the 'op' as lazy_setfield, and register
             # myself in the optheap's _lazy_setfields_and_arrayitems list
             self._lazy_setfield = op
             # possible aliasing).
             self.clear()
             self._lazy_setfield = None
-            optheap.next_optimization.propagate_forward(op)
+            # XXX should we push it through the optimizer chain?
+            optheap.optimizer.emit_operation(op)
             if not can_cache:
                 return
             # Once it is done, we can put at least one piece of information
             # back in the cache: the value of this particular structure's
             # field.
-            structvalue = optheap.getvalue(op.getarg(0))
-            fieldvalue  = optheap.getvalue(op.getarglist()[-1])
+            structvalue = optheap.getforwarded(op.getarg(0))
+            fieldvalue  = optheap.getforwarded(op.getarglist()[-1])
             self.remember_field_value(structvalue, fieldvalue, op)
         elif not can_cache:
             self.clear()
             # of virtualref_info and virtualizable_info are not gcptrs.
 
     def turned_constant(self, value):
-        value = self.getforwarded(value)
+        newvalue = self.getforwarded(value)
         for cf in self.cached_fields.itervalues():
             cf.turned_constant(newvalue, value)
         for submap in self.cached_arrayitems.itervalues():
         return pendingfields
 
     def optimize_GETFIELD_GC_i(self, op):
-        structvalue = self.getvalue(op.getarg(0))
+        structvalue = self.getforwarded(op.getarg(0))
         cf = self.field_cache(op.getdescr())
         fieldvalue = cf.getfield_from_cache(self, structvalue)
         if fieldvalue is not None:
             self.replace(op, fieldvalue.op)
             return
         # default case: produce the operation
-        structvalue.ensure_nonnull()
-        self.emit_operation(op)
-        # then remember the result of reading the field
-        fieldvalue = self.getvalue(op)
-        cf.remember_field_value(structvalue, fieldvalue, op)
+        structvalue.setknownnonnull(True)
+        return op
+
     optimize_GETFIELD_GC_r = optimize_GETFIELD_GC_i
     optimize_GETFIELD_GC_f = optimize_GETFIELD_GC_i
 
+    def postprocess_GETFIELD_GC_i(self, op):
+        # then remember the result of reading the field
+        structvalue = self.getforwarded(op.getarg(0))
+        fieldvalue = self.getforwarded(op)
+        cf = self.field_cache(op.getdescr())
+        cf.remember_field_value(structvalue, fieldvalue, op)
+
+    postprocess_GETFIELD_GC_r = postprocess_GETFIELD_GC_i
+    postprocess_GETFIELD_GC_f = postprocess_GETFIELD_GC_i
+
     def optimize_GETFIELD_GC_PURE_i(self, op):
         structvalue = self.getvalue(op.getarg(0))
         cf = self.field_cache(op.getdescr())
     optimize_GETFIELD_GC_PURE_r = optimize_GETFIELD_GC_PURE_i
 
     def optimize_SETFIELD_GC(self, op):
+        # XXX this is just debugging, should we comment it out somehow?
         if op.type == INT:
             op_key = create_resop_1(rop.GETFIELD_GC_PURE_i, 0, op.getarg(0),
                                     op.getdescr())

File pypy/jit/metainterp/optimizeopt/intbounds.py

         dispatch_bounds_ops(self, op)
 
     def postprocess_GUARD_TRUE(self, op):
-        self.propagate_bounds_backward(op.getarg(0))
+        if op.getarg(0).type == INT:
+            self.propagate_bounds_backward(op.getarg(0))
 
     postprocess_GUARD_FALSE = postprocess_GUARD_TRUE
     postprocess_GUARD_VALUE = postprocess_GUARD_TRUE

File pypy/jit/metainterp/optimizeopt/optimizer.py

             return not op.nonnull()
         return False
 
-    def same_value(self, other):
-        if not other:
-            return False
-        if self.is_constant() and other.is_constant():
-            return self.box.same_constant(other.box)
-        return self is other
-
     def make_constant_class(self, classbox, guardop, index):
         assert self.level < LEVEL_KNOWNCLASS
         self.known_class = classbox
     def __init__(self):
         pass # make rpython happy
 
-    #def propagate_forward(self, op):
-    #    raise NotImplementedError
-
-    #def emit_operation(self, op):
-    #    self.last_emitted_operation = op
-    #    self.next_optimization.propagate_forward(op)
-
     def process_inputargs(self, args):
         pass
 
     def replace(self, op, with_):
         self.getforwarded(op)._forwarded = with_
 
-    def copy_op_if_modified_by_optimization(self, op):
-        xxxx
-        new_op = op.copy_if_modified_by_optimization(self)
-        if new_op is not op:
-            self.replace(op, new_op)
-        return new_op
-
-    # XXX some RPython magic needed
-    def copy_and_change(self, op, *args, **kwds):
-        xxx
-        new_op = op.copy_and_change(*args, **kwds)
-        if new_op is not op:
-            self.replace(op, new_op)
-        return new_op
-
     def ensure_imported(self, value):
         pass
 
         if not op.is_constant():
             op._forwarded = ConstInt(intvalue)
 
+    def same_value(self, op1, op2):
+        if op1 is op2:
+            return True
+        if op2 is None:
+            return False
+        if op1.is_constant() and op2.is_constant():
+            return op1.same_constant(op2)
+        return False
+
     def new_ptr_box(self):
         return self.cpu.ts.BoxRef()
 
         for opt in self.optimizations:
             opt.process_inputargs(self.loop.inputargs)
         while i < len(self.loop.operations):
-            op = self.loop.operations[i]
-            orig_op = op
+            orig_op = self.loop.operations[i]
+            op = orig_op
             for opt in self.optimizations:
                 op = opt.optimize_operation(op)
+                # result can be either None, the same thing or a new operation
                 if op is None:
                     break
             else:
         dispatch_opt(self, op)
 
     def emit_operation(self, op):
+        op = self.getforwarded(op)
         assert op.getopnum() not in opgroups.CALL_PURE
         assert not op._forwarded
         if isinstance(op, Const):
 
     def store_final_boxes_in_guard(self, op):
         return op # XXX we disable it for tests
+        xxxx
         assert op.getdescr() is None
         descr = op.invent_descr(self.jitdriver_sd, self.metainterp_sd)
         op.setdescr(descr)
             raise compile.giveup()
         descr.store_final_boxes(op, newboxes)
         #
-        if op.getopnum() == rop.GUARD_VALUE:
-            xxx
-            if self.getvalue(op.getarg(0)).is_bool_box:
-                # Hack: turn guard_value(bool) into guard_true/guard_false.
-                # This is done after the operation is emitted to let
-                # store_final_boxes_in_guard set the guard_opnum field of the
-                # descr to the original rop.GUARD_VALUE.
-                constvalue = op.getarg(1).getint()
-                if constvalue == 0:
-                    newop = create_resop_1(rop.GUARD_FALSE, None,
-                                           op.getarg(0))
-                elif constvalue == 1: 
-                    newop = create_resop_1(rop.GUARD_TRUE, None,
-                                           op.getarg(0))
-                else:
-                    raise AssertionError("uh?")
-                newop.set_extra("failargs", op.get_extra("failargs"))
-                self.replace(op, newop)
-                return newop
-            else:
-                # a real GUARD_VALUE.  Make it use one counter per value.
-                descr.make_a_counter_per_value(op)
         return op
 
     def optimize_default(self, op):
     #    self.emit_operation(op)
     # FIXME: Is this still needed?
 
-    def optimize_DEBUG_MERGE_POINT(self, op):
-        self.emit_operation(op)
-
     def optimize_GETARRAYITEM_GC_PURE_i(self, op):
         indexvalue = self.getvalue(op.getarg(1))
         if indexvalue.is_constant():

File pypy/jit/metainterp/optimizeopt/pure.py

         self.emitted_pure_operations = []
 
     def optimize_default(self, op):
+        orig_op = op
         op = self.getforwarded(op)
         canfold = op.is_always_pure()
         if op.is_ovf():
                 return
 
             # did we do the exact same operation already?
-            oldop = self.pure_operations.get(op)
+            oldop = self.pure_operations.get(orig_op)
             if oldop is not None:
-                self.replace(op, oldop)
+                self.optimizer.replace(op, oldop)
                 return
             else:
-                self.pure_operations.set(op, op)
+                self.pure_operations.set(orig_op, op)
                 self.remember_emitting_pure(op)
-
         # otherwise, the operation remains
         if nextop:
             return nextop
                 self.replace(op, oldop)
                 self.last_emitted_operation = REMOVED
                 return
-            else:
-                new_op = op.copy_if_modified_by_optimization(self.optimizer)
-                self.pure_operations.set(new_op, op)
-                self.remember_emitting_pure(op)
-
+            new_op = self.optimizer.getforwarded(op)
+            self.pure_operations.set(op, new_op)
+            self.remember_emitting_pure(new_op)
             # replace CALL_PURE with just CALL
-            self.emit_operation(self.optimizer.copy_and_change(op, opnum))
+            return new_op.make_forwarded_copy(opnum)
         return optimize_CALL_PURE
     optimize_CALL_PURE_i = _new_optimize_call_pure(rop.CALL_i)
     optimize_CALL_PURE_f = _new_optimize_call_pure(rop.CALL_f)
             # it was a CALL_PURE that was killed; so we also kill the
             # following GUARD_NO_EXCEPTION
             return
-        self.emit_operation(op)
+        return op
 
     def flush(self):
         assert self.posponedop is None

File pypy/jit/metainterp/optimizeopt/rewrite.py

 from pypy.jit.metainterp.optimize import InvalidLoop
 from pypy.jit.metainterp.optimizeopt.intutils import IntBound
 from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1,\
-     CONST_0
+     CONST_0, REMOVED
 from pypy.jit.metainterp.resoperation import (opboolinvers, opboolreflex, rop,
                                               ConstInt, make_hashable_int,
-                                              create_resop_2, Const)
+                                              create_resop_2, Const,
+                                              create_resop_1)
 from pypy.rlib.rarithmetic import highest_bit
 
 
                                         arg1=op.getarg(0))
             oldop = self.get_pure_result(key_op)
             if oldop is not None and oldop.getdescr() is op.getdescr():
-                self.replace(op, oldop)
+                self.optimizer.replace(op, oldop)
                 return True
 
         oldopnum = opboolinvers[opboolreflex[op.getopnum()]]
         v1 = self.getvalue(op.getarg(0))
         v2 = self.getvalue(op.getarg(1))
         if v1.is_null():
-            self.replace(op, op.getarg(1))
+            self.optimizer.replace(op, op.getarg(1))
         elif v2.is_null():
-            self.replace(op, op.getarg(0))
+            self.optimizer.replace(op, op.getarg(0))
         else:
-            self.emit_operation(op)
+            return op
 
     def optimize_INT_SUB(self, op):
         v2 = self.getforwarded(op.getarg(1))
         if v2.is_constant() and v2.getint() == 0:
-            self.replace(op, op.getarg(0))
+            self.optimizer.replace(op, op.getarg(0))
         else:
             # Synthesize the reverse ops for optimize_default to reuse
             self.pure(op.getarg(0), rop.INT_ADD, op.getarg(1), op)
 
         # If one side of the op is 0 the result is the other side.
         if v1.is_constant() and v1.getint() == 0:
-            self.replace(op, arg2)
+            self.optimizer.replace(op, arg2)
         elif v2.is_constant() and v2.getint() == 0:
-            self.replace(op, arg1)
+            self.optimizer.replace(op, arg1)
         else:
             # Synthesize the reverse op for optimize_default to reuse
             self.pure(op.getarg(0), rop.INT_SUB, op, op.getarg(1))
 
             if v1.is_constant():
                 if v1.op.getfloat() == 1.0:
-                    self.replace(op, rhs)
+                    self.optimizer.replace(op, rhs)
                     return
                 elif v1.op.getfloat() == -1.0:
                     new_op = create_resop_1(rop.FLOAT_NEG, 0.0, rhs)
-                    self.replace(op, new_op)
+                    self.optimizer.replace(op, new_op)
                     self.emit_operation(new_op)
                     return
         self.emit_operation(op)
                                   'always fail')
             return
         if emit_operation:
-            return self.getforwarded(op)
+            return op
 
     def postprocess_guard(self, op, constbox):
         value = self.getforwarded(op.getarg(0))
     def postprocess_GUARD_FALSE(self, op):
         self.postprocess_guard(op, CONST_0)
 
-    def postprocess_GUARD_NO_OVERFLOW(self, op):
-        pass # to be killed
-
-    def postprocess_default(self, op):
-        if op.is_guard():
-            xxx
-
     def optimize_GUARD_ISNULL(self, op):
-        value = self.getvalue(op.getarg(0))
+        value = self.getforwarded(op.getarg(0))
         if value.is_null():
             return
         elif value.is_nonnull():
             raise InvalidLoop('A GUARD_ISNULL was proven to always fail')
-        self.emit_operation(op)
-        value.make_constant(self.optimizer.cpu.ts.CONST_NULL)
+        return op
+
+    def postprocess_GUARD_ISNULL(self, op):
+        self.optimizer.make_constant(op.getarg(0),
+                                     self.optimizer.cpu.ts.CONST_NULL)
 
     def optimize_GUARD_NONNULL(self, op):
-        value = self.getvalue(op.getarg(0))
+        value = self.getforwarded(op.getarg(0))
         if value.is_nonnull():
             return
         elif value.is_null():
             raise InvalidLoop('A GUARD_NONNULL was proven to always fail')
-        pos = self.optimizer.get_pos()
-        self.emit_operation(op)
-        value.make_nonnull(op, pos)
+        value.setknownnonnull(True)
+        value.setlastguardpos(self.optimizer.get_pos())
+        return op
 
     def optimize_GUARD_VALUE(self, op):
         value = self.getforwarded(op.getarg(0))
             value.last_guard = None
             emit_operation = False
         else:
+            if not value.is_constant() and value.returns_bool_result():
+                constvalue = op.getarg(1).getint()
+                if constvalue == 0:
+                    newop = create_resop_1(rop.GUARD_FALSE, None,
+                                           op.getarg(0))
+                elif constvalue == 1: 
+                    newop = create_resop_1(rop.GUARD_TRUE, None,
+                                           op.getarg(0))
+                else:
+                    raise AssertionError("uh?")
+                return newop
             emit_operation = True
         constbox = op.getarg(1)
         assert isinstance(constbox, Const)
 
             resop = self.loop_invariant_results.get(key, None)
             if resop is not None:
-                self.replace(op, resop)
+                self.optimizer.replace(op, resop)
                 self.last_emitted_operation = REMOVED
                 return
             # change the op to be a normal call, from the backend's point of view
 
     def _optimize_nullness(self, op, arg, expect_nonnull):
         value = self.getforwarded(arg)
-        if value.nonnull():
+        if value.is_nonnull():
             self.make_constant_int(op, expect_nonnull)
-        elif not value.nonnull():
+        elif value.is_null():
             self.make_constant_int(op, not expect_nonnull)
         else:
             return op
 
     def optimize_INT_IS_TRUE(self, op):
         if op.getarg(0).returns_bool_result():
-            self.replace(op, op.getarg(0))
+            self.optimizer.replace(op, op.getarg(0))
             return
         return self._optimize_nullness(op, op.getarg(0), True)
 
     def optimize_INT_IS_ZERO(self, op):
-        self._optimize_nullness(op, op.getarg(0), False)
+        return self._optimize_nullness(op, op.getarg(0), False)
 
     def _optimize_oois_ooisnot(self, op, expect_isnot, instance):
-        value0 = self.getvalue(op.getarg(0))
-        value1 = self.getvalue(op.getarg(1))
+        value0 = self.getforwarded(op.getarg(0))
+        value1 = self.getforwarded(op.getarg(1))
         if value0.is_virtual():
             if value1.is_virtual():
                 intres = (value0 is value1) ^ expect_isnot
         if oopspecindex == EffectInfo.OS_ARRAYCOPY:
             if self._optimize_CALL_ARRAYCOPY(op):
                 return
-        self.emit_operation(op)
+        return op
     optimize_CALL_p = optimize_CALL_i
     optimize_CALL_f = optimize_CALL_i
     optimize_CALL_v = optimize_CALL_i
         # it's being done by someone else)
         for i in range(op.numargs()):
             arg = op.getarg(i)
-            const = self.get_constant_box(arg)
+            const = self.get_constant_op(arg)
             if const is None or not const.eq_value(arg):
                 break
         else:
             self.make_constant(op, op.constbox())
             self.last_emitted_operation = REMOVED
             return
-        self.emit_operation(op)
+        return op
     optimize_CALL_PURE_f = optimize_CALL_PURE_i
     optimize_CALL_PURE_p = optimize_CALL_PURE_i
     optimize_CALL_PURE_v = optimize_CALL_PURE_i
             # it was a CALL_PURE or a CALL_LOOPINVARIANT that was killed;
             # so we also kill the following GUARD_NO_EXCEPTION
             return
-        self.emit_operation(op)
+        return op
 
     def optimize_INT_FLOORDIV(self, op):
         v1 = self.getvalue(op.getarg(0))
     optimize_SAME_AS_r = optimize_SAME_AS_i
     optimize_SAME_AS_f = optimize_SAME_AS_i
 
+    def optimize_JUMP(self, op):
+        self.optimizer.flush()
+        return op
+
+    def optimize_FINISH(self, op):
+        self.optimizer.flush()
+        return op
+
 #dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_',
 #        default=OptRewrite.emit_operation)
 #optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD')

File pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py

+import random
+
 import py
+
 from pypy.rlib.objectmodel import instantiate
 from pypy.jit.metainterp.optimizeopt.test.test_util import (
     LLtypeMixin, BaseTest, FakeMetaInterpStaticData, convert_old_style_to_targets)
 from pypy.jit.metainterp.test.support import boxint
 from pypy.rlib.rarithmetic import LONG_BIT
 
+
 def test_store_final_boxes_in_guard():
     from pypy.jit.metainterp.resume import tag, TAGBOX
     b0 = boxint()
         self.optimize_loop(ops, expected)
 
     def test_constfold_all(self):
-        from pypy.jit.backend.llgraph.llimpl import TYPES     # xxx fish
+        from pypy.jit.metainterp.optimizeopt.test.types import TYPES
         from pypy.jit.metainterp.executor import execute_nonspec
-        import random
+
         for opnum in [rop._ALWAYS_PURE_FIRST, rop._ALWAYS_PURE_NO_PTR_LAST]:
             try:
                 op = opname[opnum]
                 continue
             if op.startswith('_'):
                 continue
-            if 'FLOAT' in op:
-                continue
             argtypes, restype = TYPES[op.lower()]
             args = []
             for argtype in argtypes:
         """
         self.optimize_loop(ops, expected)
 
-    def test_remove_guard_value_if_constant(self):
-        ops = """
-        [p1]
-        guard_value(p1, ConstPtr(myptr))
-        jump(ConstPtr(myptr))
-        """
-        expected = """
-        []
-        jump()
-        """
-        py.test.skip("XXX")
-        self.optimize_loop(ops, 'Constant(myptr)', expected)
-
     def test_ooisnull_oononnull_1(self):
         ops = """
         [p0]
-        guard_class(p0, ConstClass(node_vtable)) []
-        guard_nonnull(p0) []
+        guard_class(p0, ConstClass(node_vtable))
+        guard_nonnull(p0)
         jump(p0)
         """
         expected = """
         [p0]
-        guard_class(p0, ConstClass(node_vtable)) []
+        guard_class(p0, ConstClass(node_vtable))
         jump(p0)
         """
         self.optimize_loop(ops, expected)
         ops = """
         [i0]
         i1 = int_is_true(i0)
-        guard_true(i1) []
+        guard_true(i1)
         i2 = int_is_true(i0)
-        guard_true(i2) []
+        guard_true(i2)
         jump(i0)
         """
         expected = """
         [i0]
         i1 = int_is_true(i0)
-        guard_true(i1) []
+        guard_true(i1)
         jump(i0)
         """
         self.optimize_loop(ops, expected)
         ops = """
         [i0]
         i1 = int_is_zero(i0)
-        guard_true(i1) []
+        guard_true(i1)
         i2 = int_is_true(i0)
-        guard_false(i2) []
+        guard_false(i2)
         jump(i0)
         """
         expected = """
         [i0]
         i1 = int_is_zero(i0)
-        guard_true(i1) []
+        guard_true(i1)
         jump(0)
         """
         self.optimize_loop(ops, expected)
     def test_ooisnull_oononnull_2(self):
         ops = """
         [p0]
-        guard_nonnull(p0) []
-        guard_nonnull(p0) []
+        guard_nonnull(p0)
+        guard_nonnull(p0)
         jump(p0)
         """
         expected = """
         [p0]
-        guard_nonnull(p0) []
+        guard_nonnull(p0)
         jump(p0)
         """
         self.optimize_loop(ops, expected)
     def test_ooisnull_on_null_ptr_1(self):
         ops = """
         [p0, p1]
-        guard_isnull(p0) []
-        guard_isnull(p0) []
+        guard_isnull(p0)
+        guard_isnull(p0)
         jump(p1, p1)
         """
         expected = """
         [p0, p1]
-        guard_isnull(p0) []
+        guard_isnull(p0)
         jump(p1, p1)
         """
         self.optimize_loop(ops, expected)
         [p0]
         pv = new_with_vtable(ConstClass(node_vtable))
         setfield_gc(pv, p0, descr=valuedescr)
-        guard_nonnull(p0) []
+        guard_nonnull(p0)
         p1 = getfield_gc_r(pv, descr=valuedescr)
-        guard_nonnull(p1) []
+        guard_nonnull(p1)
         jump(p0)
         """
         expected = """
         [p0]
-        guard_nonnull(p0) []
+        guard_nonnull(p0)
         jump(p0)
         """
         self.optimize_loop(ops, expected)
     def test_oois_1(self):
         ops = """
         [p0]
-        guard_class(p0, ConstClass(node_vtable)) []
+        guard_class(p0, ConstClass(node_vtable))
         i0 = instance_ptr_ne(p0, NULL)
-        guard_true(i0) []
+        guard_true(i0)
         i1 = instance_ptr_eq(p0, NULL)
-        guard_false(i1) []
+        guard_false(i1)
         i2 = instance_ptr_ne(NULL, p0)
-        guard_true(i0) []
+        guard_true(i0)
         i3 = instance_ptr_eq(NULL, p0)
-        guard_false(i1) []
+        guard_false(i1)
         jump(p0)
         """
         expected = """
         [p0]
-        guard_class(p0, ConstClass(node_vtable)) []
+        guard_class(p0, ConstClass(node_vtable))
         jump(p0)
         """
         self.optimize_loop(ops, expected)
         [p0]
         setfield_gc(p0, 5, descr=valuedescr)     # forces p0 != NULL
         i0 = ptr_ne(p0, NULL)
-        guard_true(i0) []
+        guard_true(i0)
         i1 = ptr_eq(p0, NULL)
-        guard_false(i1) []
+        guard_false(i1)
         i2 = ptr_ne(NULL, p0)
-        guard_true(i0) []
+        guard_true(i0)
         i3 = ptr_eq(NULL, p0)
-        guard_false(i1) []
-        guard_nonnull(p0) []
+        guard_false(i1)
+        guard_nonnull(p0)
         jump(p0)
         """
         expected = """
     def test_const_guard_value(self):
         ops = """
         [i0]
-        guard_value(i0, 2) []
+        guard_value(i0, 2)
         i = int_add(5, i0)
-        guard_value(i, 7) []
+        guard_value(i, 7)
         jump(i0)
         """
         expected = """
         [i0]
-        guard_value(i0, 2) []
+        guard_value(i0, 2)
         jump(2)
         """
         self.optimize_loop(ops, expected)
     def test_constptr_guard_value(self):
         ops = """
         [p1]
-        guard_value(p1, ConstPtr(myptr)) []
+        guard_value(p1, ConstPtr(myptr))
         jump(p1)
         """
         expected = """
         [p1]
-        guard_value(p1, ConstPtr(myptr)) []
+        guard_value(p1, ConstPtr(myptr))
         jump(ConstPtr(myptr))
         """
         self.optimize_loop(ops, expected)
         ops = """
         [i]
         i1 = int_lt(i, 3)
-        guard_value(i1, 1) [i]
+        guard_value(i1, 1)
         jump(i)
         """
         expected = """
         [i]
         i1 = int_lt(i, 3)
-        guard_true(i1) [i]
+        guard_true(i1)
         jump(i)
         """
         self.optimize_loop(ops, expected)
         ops = """
         [i]
         i1 = int_is_true(i)
-        guard_value(i1, 0) [i]
+        guard_value(i1, 0)
         jump(i)
         """
         expected = """
         [i]
         i1 = int_is_true(i)
-        guard_false(i1) [i]
+        guard_false(i1)
         jump(i)
         """
         self.optimize_loop(ops, expected)
         ops = """
         [i]
         i1 = int_add(i, 3)
-        guard_value(i1, 0) [i]
+        guard_value(i1, 0)
         jump(i)
         """
         expected = """
         [i]
         i1 = int_add(i, 3)
-        guard_value(i1, 0) [i]
+        guard_value(i1, 0)
         jump(-3)
         """
         self.optimize_loop(ops, expected)
         i2 = int_gt(i0, i1)
         i3 = int_is_true(i2)
         i4 = int_is_true(i3)
-        guard_value(i4, 0) [i0, i1]
+        guard_value(i4, 0)
         jump(i0, i1)
         """
         expected = """
         [i0, i1]
         i2 = int_gt(i0, i1)
-        guard_false(i2) [i0, i1]
+        guard_false(i2)
         jump(i0, i1)
         """
         self.optimize_loop(ops, expected)
 
-
-
-
     def test_p123_simple(self):
         ops = """
         [i1, p2, p3]
         escape(i3)
         p1 = new_with_vtable(ConstClass(node_vtable))
         p1sub = new_with_vtable(ConstClass(node_vtable2))
-        setfield_gc(p1, i1, descr=valuedescr)
         setfield_gc(p1sub, i1, descr=valuedescr)
         setfield_gc(p1, p1sub, descr=nextdescr)
+        setfield_gc(p1, i1, descr=valuedescr)
         jump(i1, p1, p2)
         """
         # The same as test_p123_simple, but with a virtual containing another
         p3sub = getfield_gc_r(p3, descr=nextdescr)
         i3 = getfield_gc_i(p3sub, descr=valuedescr)
         escape(i3)
-        p1 = new_with_vtable(ConstClass(node_vtable))
         p2sub = new_with_vtable(ConstClass(node_vtable2))
         setfield_gc(p2sub, i1, descr=valuedescr)
         setfield_gc(p2, p2sub, descr=nextdescr)
+        p1 = new_with_vtable(ConstClass(node_vtable))
         jump(i1, p1, p2)
         """
         # The same as test_p123_simple, but in the end the "old" p2 contains
         ops = """
         [i1]
         i2 = call_i(i1, descr=nonwritedescr)
-        guard_no_exception() [i1, i2]
+        guard_no_exception()
         jump(i2)
         """
         self.optimize_loop(ops, ops)
         ops = """
         [i1]
         i2 = call_pure_i(123456, i1, descr=nonwritedescr)
-        guard_no_exception() [i1, i2]
+        guard_no_exception()
         jump(i2)
         """
         expected = """
         [i1]
         i2 = call_i(123456, i1, descr=nonwritedescr)
-        guard_no_exception() [i1, i2]
+        guard_no_exception()
         jump(i2)
         """
         self.optimize_loop(ops, expected)
         [i1]
         i3 = same_as_i(81)
         i2 = call_pure_i(123456, i3, descr=nonwritedescr)
-        guard_no_exception() [i1, i2]
+        guard_no_exception()
         jump(i2)
         """
         expected = """
         ops = """
         [i1]
         i2 = call_pure_i(123456, i1, descr=nonwritedescr)
-        guard_no_exception() [i1, i2]
+        guard_no_exception()
         i3 = call_pure_i(123456, i1, descr=nonwritedescr)
-        guard_no_exception() [i1, i2, i3]
+        guard_no_exception()
         jump(i3)
         """
         expected = """
         [i1]
         i2 = call_i(123456, i1, descr=nonwritedescr)
-        guard_no_exception() [i1, i2]
+        guard_no_exception()
         jump(i2)
         """
         self.optimize_loop(ops, expected)
         ops = """
         [i1]
         i2 = call_loopinvariant_i(1, i1, descr=nonwritedescr)
-        guard_no_exception() []
-        guard_value(i2, 1) []
+        guard_no_exception()
+        guard_value(i2, 1)
         i3 = call_loopinvariant_i(1, i1, descr=nonwritedescr)
-        guard_no_exception() []
-        guard_value(i3, 1) []
+        guard_no_exception()
+        guard_value(i3, 1)
         i4 = call_loopinvariant_i(1, i1, descr=nonwritedescr)
-        guard_no_exception() []
-        guard_value(i4, 1) []
+        guard_no_exception()
+        guard_value(i4, 1)
         jump(i1)
         """
         expected = """
         [i1]
         i2 = call_i(1, i1, descr=nonwritedescr)
-        guard_no_exception() []
-        guard_value(i2, 1) []
+        guard_no_exception()
+        guard_value(i2, 1)
         jump(i1)
         """
         self.optimize_loop(ops, expected)
 
-
     # ----------
 
     def test_virtual_1(self):
     def test_getfield_gc_pure_2(self):
         ops = """
         [p0, i]
-        guard_value(p0, ConstPtr(myptr)) []
+        guard_value(p0, ConstPtr(myptr))
         i1 = getfield_gc_pure_i(p0, descr=valuedescr)
         jump(p0, i1)
         """
         expected = """
         [p0, i]
-        guard_value(p0, ConstPtr(myptr)) []
+        guard_value(p0, ConstPtr(myptr))
         jump(ConstPtr(myptr), 5)
         """
         self.node.value = 5
         [i1]
         p1 = new_array(3, descr=arraydescr)
         i3 = arraylen_gc(p1, descr=arraydescr)
-        guard_value(i3, 3) []
+        guard_value(i3, 3)
         setarrayitem_gc(p1, 1, i1, descr=arraydescr)
         setarrayitem_gc(p1, 0, 25, descr=arraydescr)
         i2 = getarrayitem_gc_i(p1, 1, descr=arraydescr)
         [f1]
         p1 = new_array(3, descr=floatarraydescr)
         i3 = arraylen_gc(p1, descr=floatarraydescr)
-        guard_value(i3, 3) []
+        guard_value(i3, 3)
         setarrayitem_gc(p1, 1, f1, descr=floatarraydescr)
         setarrayitem_gc(p1, 0, 3.5, descr=floatarraydescr)
         f2 = getarrayitem_gc_f(p1, 1, descr=floatarraydescr)

File pypy/jit/metainterp/optimizeopt/test/types.py

+TYPES = {
+    'int_add'         : (('int', 'int'), 'int'),
+    'int_sub'         : (('int', 'int'), 'int'),
+    'int_mul'         : (('int', 'int'), 'int'),
+    'int_floordiv'    : (('int', 'int'), 'int'),
+    'int_mod'         : (('int', 'int'), 'int'),
+    'int_and'         : (('int', 'int'), 'int'),
+    'int_or'          : (('int', 'int'), 'int'),
+    'int_xor'         : (('int', 'int'), 'int'),
+    'int_lshift'      : (('int', 'int'), 'int'),
+    'int_rshift'      : (('int', 'int'), 'int'),
+    'int_lt'          : (('int', 'int'), 'bool'),
+    'int_gt'          : (('int', 'int'), 'bool'),
+    'int_ge'          : (('int', 'int'), 'bool'),
+    'int_le'          : (('int', 'int'), 'bool'),
+    'int_eq'          : (('int', 'int'), 'bool'),
+    'int_ne'          : (('int', 'int'), 'bool'),
+    'int_is_true'     : (('int',), 'bool'),
+    'int_is_zero'     : (('int',), 'bool'),
+    'int_neg'         : (('int',), 'int'),
+    'int_invert'      : (('int',), 'int'),
+    'int_add_ovf'     : (('int', 'int'), 'int'),
+    'int_sub_ovf'     : (('int', 'int'), 'int'),
+    'int_mul_ovf'     : (('int', 'int'), 'int'),
+    'int_force_ge_zero':(('int',), 'int'),
+    'uint_add'        : (('int', 'int'), 'int'),
+    'uint_sub'        : (('int', 'int'), 'int'),
+    'uint_mul'        : (('int', 'int'), 'int'),
+    'uint_lt'         : (('int', 'int'), 'bool'),
+    'uint_le'         : (('int', 'int'), 'bool'),
+    'uint_eq'         : (('int', 'int'), 'bool'),
+    'uint_ne'         : (('int', 'int'), 'bool'),
+    'uint_gt'         : (('int', 'int'), 'bool'),
+    'uint_ge'         : (('int', 'int'), 'bool'),
+    'uint_xor'        : (('int', 'int'), 'int'),
+    'uint_rshift'     : (('int', 'int'), 'int'),
+    'uint_floordiv'   : (('int', 'int'), 'int'),
+    'float_add'       : (('float', 'float'), 'float'),
+    'float_sub'       : (('float', 'float'), 'float'),
+    'float_mul'       : (('float', 'float'), 'float'),
+    'float_truediv'   : (('float', 'float'), 'float'),
+    'float_lt'        : (('float', 'float'), 'bool'),
+    'float_le'        : (('float', 'float'), 'bool'),
+    'float_eq'        : (('float', 'float'), 'bool'),
+    'float_ne'        : (('float', 'float'), 'bool'),
+    'float_gt'        : (('float', 'float'), 'bool'),
+    'float_ge'        : (('float', 'float'), 'bool'),
+    'float_neg'       : (('float',), 'float'),
+    'float_abs'       : (('float',), 'float'),
+    'cast_float_to_int':(('float',), 'int'),
+    'cast_int_to_float':(('int',), 'float'),
+    'same_as'         : (('int',), 'int'),      # could also be ptr=>ptr
+    'new_with_vtable' : (('ref',), 'ref'),
+    'new'             : ((), 'ref'),
+    'new_array'       : (('int',), 'ref'),
+    'oois'            : (('ref', 'ref'), 'bool'),
+    'ooisnot'         : (('ref', 'ref'), 'bool'),
+    'instanceof'      : (('ref',), 'bool'),
+    'subclassof'      : (('ref', 'ref'), 'bool'),
+    'runtimenew'      : (('ref',), 'ref'),
+    'setfield_gc'     : (('ref', 'intorptr'), None),
+    'getfield_gc'     : (('ref',), 'intorptr'),
+    'getfield_gc_pure': (('ref',), 'intorptr'),
+    'setfield_raw'    : (('ref', 'intorptr'), None),
+    'getfield_raw'    : (('ref',), 'intorptr'),
+    'getfield_raw_pure': (('ref',), 'intorptr'),
+    'setarrayitem_gc' : (('ref', 'int', 'intorptr'), None),
+    'getarrayitem_gc' : (('ref', 'int'), 'intorptr'),
+    'getarrayitem_gc_pure' : (('ref', 'int'), 'intorptr'),
+    'setarrayitem_raw' : (('ref', 'int', 'intorptr'), None),
+    'getarrayitem_raw' : (('ref', 'int'), 'intorptr'),
+    'getarrayitem_raw_pure' : (('ref', 'int'), 'intorptr'),
+    'arraylen_gc'     : (('ref',), 'int'),
+    'call'            : (('ref', 'varargs'), 'intorptr'),
+    'call_assembler'  : (('varargs',), 'intorptr'),
+    'cond_call_gc_wb' : (('ptr', 'ptr'), None),
+    'cond_call_gc_wb_array': (('ptr', 'int', 'ptr'), None),
+    'oosend'          : (('varargs',), 'intorptr'),
+    'oosend_pure'     : (('varargs',), 'intorptr'),
+    'guard_true'      : (('bool',), None),
+    'guard_false'     : (('bool',), None),
+    'guard_value'     : (('int', 'int'), None),
+    'guard_class'     : (('ref', 'ref'), None),
+    'guard_no_exception'   : ((), None),
+    'guard_exception'      : (('ref',), 'ref'),
+    'guard_no_overflow'    : ((), None),
+    'guard_overflow'       : ((), None),
+    'guard_nonnull'        : (('ref',), None),
+    'guard_isnull'        : (('ref',), None),
+    'guard_nonnull_class' : (('ref', 'ref'), None),
+    'newstr'          : (('int',), 'ref'),
+    'strlen'          : (('ref',), 'int'),
+    'strgetitem'      : (('ref', 'int'), 'int'),
+    'strsetitem'      : (('ref', 'int', 'int'), None),
+    'newunicode'      : (('int',), 'ref'),
+    'unicodelen'      : (('ref',), 'int'),
+    'unicodegetitem'  : (('ref', 'int'), 'int'),
+    'unicodesetitem'  : (('ref', 'int', 'int'), 'int'),
+    'cast_ptr_to_int' : (('ref',), 'int'),
+    'cast_int_to_ptr' : (('int',), 'ref'),
+    'debug_merge_point': (('ref', 'int', 'int'), None),
+    'force_token'     : ((), 'int'),
+    'call_may_force'  : (('int', 'varargs'), 'intorptr'),
+    'guard_not_forced': ((), None),
+}

File pypy/jit/metainterp/optimizeopt/virtualize.py

         # was already forced).
 
     def optimize_GETFIELD_GC_i(self, op):
-        value = self.getvalue(op.getarg(0))
+        value = self.getforwarded(op.getarg(0))
         # If this is an immutable field (as indicated by op.is_always_pure())
         # then it's safe to reuse the virtual's field, even if it has been
         # forced, because it should never be written to again.
                 self.replace(op, fieldvalue.op)
                 return
         if value.is_virtual():
-            assert isinstance(value, AbstractVirtualValue)
             fieldvalue = value.getfield(op.getdescr(), None)
             if fieldvalue is None:
                 fieldvalue = self.optimizer.new_const(op.getdescr())
-            self.replace(op, fieldvalue.op)
+            self.optimizer.replace(op, fieldvalue)
         else:
-            value.ensure_nonnull()
-            self.emit_operation(op)
+            value.setknownnonnull(True)
+            return op
     optimize_GETFIELD_GC_r = optimize_GETFIELD_GC_i
     optimize_GETFIELD_GC_f = optimize_GETFIELD_GC_i
 
     optimize_GETFIELD_GC_PURE_f = optimize_GETFIELD_GC_i
 
     def optimize_SETFIELD_GC(self, op):
-        value = self.getvalue(op.getarg(0))
+        value = self.getforwarded(op.getarg(0))
 
         if value.is_virtual():
-            fieldvalue = self.getvalue(op.getarg(1))
+            fieldvalue = self.getforwarded(op.getarg(1))
             value.setfield(op.getdescr(), fieldvalue)
         else:
-            value.ensure_nonnull()
-            self.emit_operation(op)
+            value.setknownnonnull(True)
+            return op
 
     def optimize_NEW_WITH_VTABLE(self, op):
-        value = self.getforwarded(op)
-        value.setknownclass(op.getarg(0))
+        pass
 
     def optimize_NEW(self, op):
         self.make_vstruct(op.getdescr(), op)
 
     def optimize_NEW_ARRAY(self, op):
-        sizebox = self.get_constant_box(op.getarg(0))
+        sizebox = self.get_constant_op(op.getarg(0))
         if sizebox is not None:
             # if the original 'op' did not have a ConstInt as argument,
             # build a new one with the ConstInt argument

File pypy/jit/metainterp/optimizeopt/vstring.py

             if oopspecindex == EffectInfo.OS_STR2UNICODE:
                 if self.opt_call_str_STR2UNICODE(op):
                     return
-        self.emit_operation(op)
+        return op
     optimize_CALL_f = optimize_CALL_i
     optimize_CALL_r = optimize_CALL_i
     optimize_CALL_v = optimize_CALL_i
     def optimize_GUARD_NO_EXCEPTION(self, op):
         if self.last_emitted_operation is REMOVED:
             return
-        self.emit_operation(op)
+        return op
 
     def opt_call_str_STR2UNICODE(self, op):
         # Constant-fold unicode("constant string").

File pypy/jit/metainterp/optmodel.py

 
 from pypy.tool.sourcetools import func_with_new_name
 from pypy.jit.metainterp.resoperation import opclasses, opclasses_mutable, rop,\
-     VOID, INT, REF, ConstInt, Const
+     VOID, INT, REF, ConstInt, Const, ConstPtr
 from pypy.jit.metainterp.optimizeopt.intutils import ImmutableIntUnbounded,\
-     ConstantIntBound
+     ConstantIntBound, IntBound
+from pypy.jit.metainterp.virtualmodel import Virtual
 
 class __extend__(ConstInt):
     def getintbound(self):
     def getboolres(self):
         return False # for optimization
 
+class __extend__(ConstPtr):
+    def is_virtual(self):
+        return False
+
+    def is_forced_virtual(self):
+        return False
+
 class __extend__(Const):
     def getlastguardpos(self):
         return -1
     def force(self, _):
         return self
 
+    def is_nonnull(self):
+        return self.nonnull()
+
+    def is_null(self):
+        return not self.nonnull()
+
+opclasses_mutable[rop.NEW_WITH_VTABLE] = Virtual
+
 def create_mutable_subclasses():
     def addattr(cls, attr, default_value=None):
-        cls.attributes_to_copy.append('_' + attr)
+        if hasattr(cls, 'attributes_to_copy'):
+            cls.attributes_to_copy.append('_' + attr)
         def getter(self):
             return getattr(self, '_' + attr)
         def setter(self, value):
                 setattr(new, attr, getattr(self, attr))
         cls._copy_extra_attrs = _copy_extra_attrs
 
+    def int_is_null(self):
+        return False
+
+    def int_is_nonnull(self):
+        intbound = self.getintbound()
+        if intbound is not None:
+            if intbound.known_gt(IntBound(0, 0)) or \
+               intbound.known_lt(IntBound(0, 0)):
+                return True
+            return False
+        return False
+
+    def ref_is_null(self):
+        return False
+
+    def ref_is_nonnull(self):
+        return self.getknownclass() is not None or self.getknownnonnull()
+
     imm_int_unbound = ImmutableIntUnbounded()
     for i, cls in enumerate(opclasses):
         if cls is None:
-            Mutable = None
+            continue
+        elif opclasses_mutable[cls.getopnum()] is not None:
+            addattr(opclasses_mutable[cls.getopnum()], 'lastguardpos')
+            continue
         else:
             class Mutable(cls):
                 is_mutable = True
                 attributes_to_copy = []
 
-                if cls.getopnum() in (rop.NEW_WITH_VTABLE, rop.NEW):
-                    def force(self, optimizer):
-                        optimizer.emit_operation(self)
-                        return self
-                else:
-                    def force(self, _):
-                        return self
+                def force(self, _):
+                    return self
+                def is_virtual(self):
+                    return False
+                def is_forced_virtual(self):
+                    return False
+
             if cls.type != VOID:
                 addattr(Mutable, 'varindex', -1)
                 #if cls.type == REF:
                 # all the integers have bounds
                 addattr(Mutable, 'intbound', imm_int_unbound)
                 addattr(Mutable, 'boolres', False)
+                Mutable.is_nonnull = int_is_nonnull
+                Mutable.is_null = int_is_null
             elif cls.type == REF:
                 addattr(Mutable, 'knownclass', None)
+                addattr(Mutable, 'knownnonnull', False)
+                Mutable.is_nonnull = ref_is_nonnull
+                Mutable.is_null = ref_is_null
             # for tracking last guard and merging GUARD_VALUE with
             # GUARD_NONNULL etc
             addattr(Mutable, 'lastguardpos', -1)
             Mutable.__name__ = cls.__name__ + '_mutable'
             if Mutable.attributes_to_copy:
                 make_new_copy_function(Mutable, cls)
-        assert len(opclasses_mutable) == i
-        opclasses_mutable.append(Mutable)
-    assert len(opclasses) == len(opclasses_mutable)
+            opclasses_mutable[i] = Mutable
 
 create_mutable_subclasses()

File pypy/jit/metainterp/resoperation.py

         # XXX this is a hack kill me
         import sys
         co_fname = sys._getframe(1).f_code.co_filename
-        if co_fname.endswith('resume.py') or co_fname.endswith('optimizeopt/util.py') or 'backend/llgraph' in co_fname or 'backend/test' in co_fname or 'test/test_util' in co_fname:
+        if co_fname.endswith('resume.py') or co_fname.endswith('optimizeopt/util.py') or 'backend/llgraph' in co_fname or 'backend/test' in co_fname or 'test/test_util' in co_fname or co_fname.endswith('heap.py'):
             return object.__hash__(self)
-        raise Exception("Should not hash resops, use get/set extra instead")
+        raise Exception("Should not hash resops")
 
     def _get_hash_(self):
         """ rpython level implementation of hash, cache it because computations
     pass
 
 def setup(debug_print=False):
+    global opclasses_mutable
+    
     i = 0
     for basename in _oplist:
         if '/' in basename:
         if k.startswith('CALL'):
             ALLCALLS.append(v)
     opgroups.ALLCALLS = tuple(ALLCALLS)
+    opclasses_mutable = [None] * len(opclasses)
 
 def get_base_class(mixin, tpmixin, base):
     try:

File pypy/jit/metainterp/virtualmodel.py

+
+from pypy.jit.metainterp.resoperation import rop, opclasses, create_resop_2
+from pypy.rlib.objectmodel import we_are_translated
+
+NEW_WITH_VTABLE = opclasses[rop.NEW_WITH_VTABLE]
+
+class Virtual(NEW_WITH_VTABLE):
+    is_mutable = True
+
+    def __init__(self, pval):
+        NEW_WITH_VTABLE.__init__(self, pval)
+        self._fields = {} # XXX convert from dict to a list
+        self._is_forced = False
+
+    def getfield(self, ofs, default):
+        return self._fields.get(ofs, default)
+
+    def setfield(self, ofs, fieldvalue):
+        self._fields[ofs] = fieldvalue
+
+    def getknownclass(self):
+        return self.getarg(0)
+
+    def setknownclass(self, cls):
+        pass # ignore
+
+    def is_nonnull(self):
+        return True
+
+    def is_null(self):
+        return False
+
+    def _copy_extra_attrs(self, new):
+        raise Exception("Virtual should not be forwarded")
+    
+    def force(self, optimizer):
+        if not self._is_forced:
+            self._is_forced = True
+            optimizer.emit_operation(self)
+            iteritems = self._fields.iteritems()
+            if not we_are_translated(): #random order is fine, except for tests
+                iteritems = list(iteritems)
+                iteritems.sort(key = lambda (x,y): x.sort_key())
+            for ofs, value in iteritems:
+                if value.is_null():
+                    continue
+                subbox = value.force(optimizer)
+                op = create_resop_2(rop.SETFIELD_GC, None, self, subbox,
+                                    descr=ofs)
+                optimizer.emit_operation(op)
+        return self
+
+    def is_virtual(self):
+        return not self._is_forced
+
+    def is_forced_virtual(self):
+        return self._is_forced