[pypy-commit] pypy unrecursive-opt: All the rest of the unrecursion.

jerith noreply at buildbot.pypy.org
Mon Oct 12 11:31:10 CEST 2015


Author: Jeremy Thurgood <firxen at gmail.com>
Branch: unrecursive-opt
Changeset: r80125:9945934d8515
Date: 2015-10-12 11:03 +0200
http://bitbucket.org/pypy/pypy/changeset/9945934d8515/

Log:	All the rest of the unrecursion.

diff --git a/rpython/jit/metainterp/optimizeopt/earlyforce.py b/rpython/jit/metainterp/optimizeopt/earlyforce.py
--- a/rpython/jit/metainterp/optimizeopt/earlyforce.py
+++ b/rpython/jit/metainterp/optimizeopt/earlyforce.py
@@ -26,7 +26,10 @@
 
             for arg in op.getarglist():
                 self.optimizer.force_box(arg, self)
-        self.emit_operation(op)
+        return self.emit(op)
+
+    def propagate_postprocess(self, op, oldop):
+        pass
 
     def setup(self):
         self.optimizer.optearlyforce = self
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
@@ -144,7 +144,7 @@
                     if a is optheap.postponed_op:
                         optheap.emit_postponed_op()
                         break
-            optheap.next_optimization.propagate_forward(op)
+            optheap.emit_extra(op, emit=False)
             if not can_cache:
                 return
             # Once it is done, we can put at least one piece of information
@@ -228,7 +228,7 @@
         if self.postponed_op:
             postponed_op = self.postponed_op
             self.postponed_op = None
-            self.next_optimization.propagate_forward(postponed_op)
+            self.emit_extra(postponed_op, emit=False)
 
     def produce_potential_short_preamble_ops(self, sb):
         descrkeys = self.cached_fields.keys()
@@ -288,14 +288,14 @@
             cf = submap[index] = ArrayCachedField(index)
         return cf
 
-    def emit_operation(self, op):        
+    def emit(self, op, callback_func=None, *callback_args):
         self.emitting_operation(op)
         self.emit_postponed_op()
         if (op.is_comparison() or op.is_call_may_force()
             or op.is_ovf()):
             self.postponed_op = op
         else:
-            Optimization.emit_operation(self, op)
+            return Optimization.emit(self, op, callback_func, *callback_args)
 
     def emitting_operation(self, op):
         if op.has_no_side_effect():
@@ -344,7 +344,7 @@
         if oopspecindex == EffectInfo.OS_DICT_LOOKUP:
             if self._optimize_CALL_DICT_LOOKUP(op):
                 return
-        self.emit_operation(op)
+        return self.emit(op)
     optimize_CALL_F = optimize_CALL_I
     optimize_CALL_R = optimize_CALL_I
     optimize_CALL_N = optimize_CALL_I
@@ -402,7 +402,7 @@
     def optimize_GUARD_NO_EXCEPTION(self, op):
         if self.last_emitted_operation is REMOVED:
             return
-        self.emit_operation(op)
+        return self.emit(op)
 
     optimize_GUARD_EXCEPTION = optimize_GUARD_NO_EXCEPTION
 
@@ -499,15 +499,20 @@
             return
         # default case: produce the operation
         self.make_nonnull(op.getarg(0))
-        self.emit_operation(op)
-        self.optimize_GETFIELD_GC_I_callback(op, structinfo, cf)
+        # return self.emit(op)
+        return self.emit(op)
 
-    def optimize_GETFIELD_GC_I_callback(self, op, structinfo, cf):
+    def postprocess_GETFIELD_GC_I(self, op, oldop):
         # then remember the result of reading the field
+        structinfo = self.ensure_ptr_info_arg0(op)
+        cf = self.field_cache(op.getdescr())
         structinfo.setfield(op.getdescr(), op.getarg(0), op, self, cf)
     optimize_GETFIELD_GC_R = optimize_GETFIELD_GC_I
     optimize_GETFIELD_GC_F = optimize_GETFIELD_GC_I
 
+    postprocess_GETFIELD_GC_R = postprocess_GETFIELD_GC_I
+    postprocess_GETFIELD_GC_F = postprocess_GETFIELD_GC_I
+
     def optimize_GETFIELD_GC_PURE_I(self, op):
         structinfo = self.ensure_ptr_info_arg0(op)
         cf = self.field_cache(op.getdescr())
@@ -517,7 +522,7 @@
             return
         # default case: produce the operation
         self.make_nonnull(op.getarg(0))
-        self.emit_operation(op)
+        return self.emit(op)
     optimize_GETFIELD_GC_PURE_R = optimize_GETFIELD_GC_PURE_I
     optimize_GETFIELD_GC_PURE_F = optimize_GETFIELD_GC_PURE_I
 
@@ -554,12 +559,16 @@
                                          self.getintbound(op.getarg(1)))
         # default case: produce the operation
         self.make_nonnull(op.getarg(0))
-        self.emit_operation(op)
-        self.optimize_GETARRAYITEM_GC_I_callback(op, cf, arrayinfo, indexb)
+        # return self.emit(op)
+        return self.emit(op)
 
-    def optimize_GETARRAYITEM_GC_I_callback(self, op, cf, arrayinfo, indexb):
+    def postprocess_GETARRAYITEM_GC_I(self, op, oldop):
         # the remember the result of reading the array item
-        if cf is not None:
+        arrayinfo = self.ensure_ptr_info_arg0(op)
+        indexb = self.getintbound(op.getarg(1))
+        if indexb.is_constant():
+            index = indexb.getint()
+            cf = self.arrayitem_cache(op.getdescr(), index)
             arrayinfo.setitem(op.getdescr(), indexb.getint(),
                               self.get_box_replacement(op.getarg(0)),
                               self.get_box_replacement(op), cf,
@@ -567,6 +576,9 @@
     optimize_GETARRAYITEM_GC_R = optimize_GETARRAYITEM_GC_I
     optimize_GETARRAYITEM_GC_F = optimize_GETARRAYITEM_GC_I
 
+    postprocess_GETARRAYITEM_GC_R = postprocess_GETARRAYITEM_GC_I
+    postprocess_GETARRAYITEM_GC_F = postprocess_GETARRAYITEM_GC_I
+
     def optimize_GETARRAYITEM_GC_PURE_I(self, op):
         arrayinfo = self.ensure_ptr_info_arg0(op)
         indexb = self.getintbound(op.getarg(1))
@@ -585,7 +597,7 @@
             self.force_lazy_setarrayitem(op.getdescr(), self.getintbound(op.getarg(1)))
         # default case: produce the operation
         self.make_nonnull(op.getarg(0))
-        self.emit_operation(op)
+        return self.emit(op)
 
     optimize_GETARRAYITEM_GC_PURE_R = optimize_GETARRAYITEM_GC_PURE_I
     optimize_GETARRAYITEM_GC_PURE_F = optimize_GETARRAYITEM_GC_PURE_I
@@ -609,7 +621,7 @@
             # variable index, so make sure the lazy setarrayitems are done
             self.force_lazy_setarrayitem(op.getdescr(), indexb, can_cache=False)
             # and then emit the operation
-            self.emit_operation(op)
+            return self.emit(op)
 
     def optimize_QUASIIMMUT_FIELD(self, op):
         # Pattern: QUASIIMMUT_FIELD(s, descr=QuasiImmutDescr)
@@ -647,9 +659,11 @@
         if self._seen_guard_not_invalidated:
             return
         self._seen_guard_not_invalidated = True
-        self.emit_operation(op)
+        return self.emit(op)
 
 
 dispatch_opt = make_dispatcher_method(OptHeap, 'optimize_',
-        default=OptHeap.emit_operation)
+                                      default=OptHeap.emit)
 OptHeap.propagate_forward = dispatch_opt
+dispatch_postprocess = make_dispatcher_method(OptHeap, 'postprocess_')
+OptHeap.propagate_postprocess = dispatch_postprocess
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
@@ -141,7 +141,7 @@
                 return constptr
             #
             op.set_forwarded(None)
-            optforce.emit_operation(op)
+            optforce.emit_extra(op)
             newop = optforce.getlastop()
             op.set_forwarded(newop)
             newop.set_forwarded(self)
@@ -218,7 +218,7 @@
                 setfieldop = ResOperation(rop.SETFIELD_GC, [op, subbox],
                                           descr=flddescr)
                 self._fields[i] = None
-                optforce.emit_operation(setfieldop)
+                optforce.emit_extra(setfieldop)
 
     def _force_at_the_end_of_preamble(self, op, optforce, rec):
         if self._fields is None:
@@ -406,7 +406,7 @@
             itembox = buffer.values[i]
             setfield_op = ResOperation(rop.RAW_STORE,
                               [op, ConstInt(offset), itembox], descr=descr)
-            optforce.emit_operation(setfield_op)
+            optforce.emit_extra(setfield_op)
 
     def _visitor_walk_recursive(self, op, visitor, optimizer):
         itemboxes = [optimizer.get_box_replacement(box)
@@ -519,7 +519,7 @@
                                  [op, ConstInt(i), subbox],
                                   descr=descr)
             self._items[i] = None
-            optforce.emit_operation(setop)
+            optforce.emit_extra(setop)
         optforce.pure_from_args(rop.ARRAYLEN_GC, [op], ConstInt(len(self._items)))
 
     def setitem(self, descr, index, struct, op, cf=None, optheap=None):
@@ -632,7 +632,7 @@
                     setfieldop = ResOperation(rop.SETINTERIORFIELD_GC,
                                               [op, ConstInt(index), subbox],
                                               descr=flddescr)
-                    optforce.emit_operation(setfieldop)
+                    optforce.emit_extra(setfieldop)
                     # heapcache does not work for interiorfields
                     # if it does, we would need a fix here
                 i += 1
diff --git a/rpython/jit/metainterp/optimizeopt/intbounds.py b/rpython/jit/metainterp/optimizeopt/intbounds.py
--- a/rpython/jit/metainterp/optimizeopt/intbounds.py
+++ b/rpython/jit/metainterp/optimizeopt/intbounds.py
@@ -42,9 +42,6 @@
     """Keeps track of the bounds placed on integers by guards and remove
        redundant guards"""
 
-    def opt_default(self, op):
-        return op
-
     def propagate_forward(self, op):
         return dispatch_opt(self, op)
 
@@ -63,7 +60,7 @@
             dispatch_bounds_ops(self, box)
 
     def _optimize_guard_true_false_value(self, op):
-        return op
+        return self.emit(op)
 
     def _postprocess_guard_true_false_value(self, op, oldop):
         if op.getarg(0).type == 'i':
@@ -86,7 +83,7 @@
             else:
                 self.make_constant_int(op, 0)
             return None
-        return op
+        return self.emit(op)
 
     def postprocess_INT_OR_or_XOR(self, op, oldop):
         v1 = self.get_box_replacement(op.getarg(0))
@@ -106,7 +103,7 @@
     postprocess_INT_XOR = postprocess_INT_OR_or_XOR
 
     def optimize_INT_AND(self, op):
-        return op
+        return self.emit(op)
 
     def postprocess_INT_AND(self, op, oldop):
         b1 = self.getintbound(op.getarg(0))
@@ -125,7 +122,7 @@
             r.intersect(IntBound(0, next_pow2_m1(lesser)))
 
     def optimize_INT_SUB(self, op):
-        return op
+        return self.emit(op)
 
     def postprocess_INT_SUB(self, op, oldop):
         b1 = self.getintbound(op.getarg(0))
@@ -138,7 +135,7 @@
         arg1 = self.get_box_replacement(op.getarg(0))
         arg2 = self.get_box_replacement(op.getarg(1))
         if self.is_raw_ptr(arg1) or self.is_raw_ptr(arg2):
-            return op
+            return self.emit(op)
         v1 = self.getintbound(arg1)
         v2 = self.getintbound(arg2)
 
@@ -172,7 +169,7 @@
                         arg2 = ConstInt(sum)
                         op = self.replace_op_with(op, rop.INT_ADD, args=[arg1, arg2])
 
-        return op
+        return self.emit(op)
 
     def postprocess_INT_ADD(self, op, oldop):
         b1 = self.getintbound(op.getarg(0))
@@ -183,7 +180,7 @@
             r.intersect(b)
 
     def optimize_INT_MUL(self, op):
-        return op
+        return self.emit(op)
 
     def postprocess_INT_MUL(self, op, oldop):
         b1 = self.getintbound(op.getarg(0))
@@ -194,7 +191,7 @@
             r.intersect(b)
 
     def optimize_INT_FLOORDIV(self, op):
-        return op
+        return self.emit(op)
 
     def postprocess_INT_FLOORDIV(self, op, oldop):
         b1 = self.getintbound(op.getarg(0))
@@ -215,7 +212,7 @@
                 arg2 = ConstInt(val-1)
                 op = self.replace_op_with(op, rop.INT_AND,
                                           args=[arg1, arg2])
-        return op
+        return self.emit(op)
 
     def postprocess_INT_MOD(self, op, oldop):
         b1 = self.getintbound(op.getarg(0))
@@ -236,7 +233,7 @@
             r.make_lt(IntBound(val, val))
 
     def optimize_INT_LSHIFT(self, op):
-        return op
+        return self.emit(op)
 
     def postprocess_INT_LSHIFT(self, op, oldop):
         arg0 = self.get_box_replacement(op.getarg(0))
@@ -262,7 +259,7 @@
             # constant result (likely 0, for rshifts that kill all bits)
             self.make_constant_int(op, b.lower)
             return None
-        return op
+        return self.emit(op)
 
     def postprocess_INT_RSHIFT(self, op, oldop):
         b1 = self.getintbound(op.getarg(0))
@@ -295,7 +292,7 @@
                 self.pure_from_args(rop.INT_SUB, [args[0], result], args[1])
             #elif opnum == rop.INT_MUL_OVF:
             #    self.pure(rop.INT_MUL, args[:], result)
-            return op
+            return self.emit(op)
 
     def optimize_GUARD_OVERFLOW(self, op):
         # If INT_xxx_OVF was replaced by INT_xxx, *but* we still see
@@ -308,7 +305,7 @@
             raise InvalidLoop('An INT_xxx_OVF was proven not to overflow but' +
                               'guarded with GUARD_OVERFLOW')
 
-        return op
+        return self.emit(op)
 
     def optimize_INT_ADD_OVF(self, op):
         b1 = self.getintbound(op.getarg(0))
@@ -319,7 +316,7 @@
             # by optimize_GUARD_NO_OVERFLOW; if we see instead an
             # optimize_GUARD_OVERFLOW, then InvalidLoop.
             op = self.replace_op_with(op, rop.INT_ADD)
-        return op
+        return self.emit(op)
 
     def postprocess_INT_ADD_OVF(self, op, oldop):
         b1 = self.getintbound(op.getarg(0))
@@ -339,7 +336,7 @@
         resbound = b0.sub_bound(b1)
         if resbound.bounded():
             op = self.replace_op_with(op, rop.INT_SUB)
-        return op
+        return self.emit(op)
 
     def postprocess_INT_SUB_OVF(self, op, oldop):
         arg0 = self.get_box_replacement(op.getarg(0))
@@ -356,7 +353,7 @@
         resbound = b1.mul_bound(b2)
         if resbound.bounded():
             op = self.replace_op_with(op, rop.INT_MUL)
-        return op
+        return self.emit(op)
 
     def postprocess_INT_MUL_OVF(self, op, oldop):
         b1 = self.getintbound(op.getarg(0))
@@ -375,7 +372,7 @@
         elif b1.known_ge(b2) or arg1 is arg2:
             self.make_constant_int(op, 0)
         else:
-            return op
+            return self.emit(op)
 
     def optimize_INT_GT(self, op):
         arg1 = self.get_box_replacement(op.getarg(0))
@@ -387,7 +384,7 @@
         elif b1.known_le(b2) or arg1 is arg2:
             self.make_constant_int(op, 0)
         else:
-            return op
+            return self.emit(op)
 
     def optimize_INT_LE(self, op):
         arg1 = self.get_box_replacement(op.getarg(0))
@@ -399,7 +396,7 @@
         elif b1.known_gt(b2):
             self.make_constant_int(op, 0)
         else:
-            return op
+            return self.emit(op)
 
     def optimize_INT_GE(self, op):
         arg1 = self.get_box_replacement(op.getarg(0))
@@ -411,7 +408,7 @@
         elif b1.known_lt(b2):
             self.make_constant_int(op, 0)
         else:
-            return op
+            return self.emit(op)
 
     def optimize_INT_EQ(self, op):
         arg0 = self.get_box_replacement(op.getarg(0))
@@ -425,7 +422,7 @@
         elif arg0.same_box(arg1):
             self.make_constant_int(op, 1)
         else:
-            return op
+            return self.emit(op)
 
     def optimize_INT_NE(self, op):
         arg0 = self.get_box_replacement(op.getarg(0))
@@ -439,14 +436,14 @@
         elif arg0 is arg1:
             self.make_constant_int(op, 0)
         else:
-            return op
+            return self.emit(op)
 
     def optimize_INT_FORCE_GE_ZERO(self, op):
         b = self.getintbound(op.getarg(0))
         if b.known_ge(IntBound(0, 0)):
             self.make_equal_to(op, op.getarg(0))
         else:
-            return op
+            return self.emit(op)
 
     def optimize_INT_SIGNEXT(self, op):
         b = self.getintbound(op.getarg(0))
@@ -457,7 +454,7 @@
         if bounds.contains_bound(b):
             self.make_equal_to(op, op.getarg(0))
         else:
-            return op
+            return self.emit(op)
 
     def postprocess_INT_SIGNEXT(self, op, oldop):
         numbits = op.getarg(1).getint() * 8
@@ -468,14 +465,14 @@
         bres.intersect(bounds)
 
     def optimize_ARRAYLEN_GC(self, op):
-        return op
+        return self.emit(op)
 
     def postprocess_ARRAYLEN_GC(self, op, oldop):
         array = self.ensure_ptr_info_arg0(op)
         self.optimizer.setintbound(op, array.getlenbound(None))
 
     def optimize_STRLEN(self, op):
-        return op
+        return self.emit(op)
 
     def postprocess_STRLEN(self, op, oldop):
         self.make_nonnull_str(op.getarg(0), vstring.mode_string)
@@ -483,7 +480,7 @@
         self.optimizer.setintbound(op, array.getlenbound(vstring.mode_string))
 
     def optimize_UNICODELEN(self, op):
-        return op
+        return self.emit(op)
 
     def postprocess_UNICODELEN(self, op, oldop):
         self.make_nonnull_str(op.getarg(0), vstring.mode_unicode)
@@ -491,7 +488,7 @@
         self.optimizer.setintbound(op, array.getlenbound(vstring.mode_unicode))
 
     def optimize_STRGETITEM(self, op):
-        return op
+        return self.emit(op)
 
     def postprocess_STRGETITEM(self, op, oldop):
         v1 = self.getintbound(op)
@@ -505,7 +502,7 @@
         v1.make_lt(IntUpperBound(256))
 
     def optimize_GETFIELD_RAW_I(self, op):
-        return op
+        return self.emit(op)
 
     def postprocess_GETFIELD_RAW_I(self, op, oldop):
         descr = op.getdescr()
@@ -535,7 +532,7 @@
     postprocess_GETINTERIORFIELD_GC_F = postprocess_GETFIELD_RAW_I
 
     def optimize_GETARRAYITEM_RAW_I(self, op):
-        return op
+        return self.emit(op)
 
     def postprocess_GETARRAYITEM_RAW_I(self, op, oldop):
         descr = op.getdescr()
@@ -555,7 +552,7 @@
     postprocess_GETARRAYITEM_GC_R = postprocess_GETARRAYITEM_RAW_I
 
     def optimize_UNICODEGETITEM(self, op):
-        return op
+        return self.emit(op)
 
     def postprocess_UNICODEGETITEM(self, op, oldop):
         b1 = self.getintbound(op)
@@ -722,6 +719,6 @@
 
 
 dispatch_opt = make_dispatcher_method(OptIntBounds, 'optimize_',
-        default=OptIntBounds.opt_default)
+                                      default=OptIntBounds.emit)
 dispatch_bounds_ops = make_dispatcher_method(OptIntBounds, 'propagate_bounds_')
 dispatch_postprocess = make_dispatcher_method(OptIntBounds, 'postprocess_')
diff --git a/rpython/jit/metainterp/optimizeopt/optimizer.py b/rpython/jit/metainterp/optimizeopt/optimizer.py
--- a/rpython/jit/metainterp/optimizeopt/optimizer.py
+++ b/rpython/jit/metainterp/optimizeopt/optimizer.py
@@ -34,6 +34,19 @@
         return True
 
 
+class OptimizationResult(object):
+    def __init__(self, opt, op, callback_func=None, *callback_args):
+        self.opt = opt
+        self.op = op
+        if callback_func is None:
+            callback_func = opt.propagate_postprocess
+        self.callback_func = callback_func
+        self.callback_args = callback_args
+
+    def callback(self, oldop):
+        self.callback_func(self.op, oldop, *self.callback_args)
+
+
 class Optimization(object):
     next_optimization = None
     potential_extra_ops = None
@@ -41,15 +54,26 @@
     def __init__(self):
         pass # make rpython happy
 
-    def send_extra_operation(self, op):
-        self.optimizer.send_extra_operation(op)
+    def send_extra_operation(self, op, opt=None):
+        self.optimizer.send_extra_operation(op, opt)
 
     def propagate_forward(self, op):
         raise NotImplementedError
 
+    def propagate_postprocess(self, op):
+        raise NotImplementedError
+
     def emit_operation(self, op):
+        assert False, "This should never be called."
+
+    def emit(self, op, callback_func=None, *callback_args):
         self.last_emitted_operation = op
-        self.next_optimization.propagate_forward(op)
+        return OptimizationResult(self, op, callback_func, *callback_args)
+
+    def emit_extra(self, op, emit=True):
+        if emit:
+            self.emit(op)
+        self.send_extra_operation(op, self.next_optimization)
 
     def getintbound(self, op):
         assert op.type == 'i'
@@ -272,7 +296,7 @@
 
     def set_optimizations(self, optimizations):
         if optimizations:
-            self.first_optimization = optimizations[3]
+            self.first_optimization = optimizations[0]
             for i in range(1, len(optimizations)):
                 optimizations[i - 1].next_optimization = optimizations[i]
             optimizations[-1].next_optimization = self
@@ -284,7 +308,7 @@
             optimizations = []
             self.first_optimization = self
 
-        self.optimizations  = optimizations
+        self.optimizations = optimizations
 
     def force_op_from_preamble(self, op):
         return op
@@ -537,21 +561,34 @@
             if op.get_forwarded() is not None:
                 op.set_forwarded(None)
 
-    def send_extra_operation(self, op):
+    def send_extra_operation(self, op, opt=None):
+        if opt is None:
+            opt = self.first_optimization
         oldop = op
-        for optimization in self.optimizations[:3]:
-            op = optimization.propagate_forward(op)
-            if op is None:
-                return
-            optimization.last_emitted_operation = op
-        self.first_optimization.propagate_forward(op)
-        for optimization in reversed(self.optimizations[:3]):
-            optimization.propagate_postprocess(op, oldop)
+        opt_results = []
+        while opt is not None:
+            opt_result = opt.propagate_forward(op)
+            if opt_result is None:
+                op = None
+                break
+            opt_results.append(opt_result)
+            op = opt_result.op
+            opt = opt.next_optimization
+        for opt_result in reversed(opt_results):
+            opt_result.callback(oldop)
 
     def propagate_forward(self, op):
         dispatch_opt(self, op)
 
-    def emit_operation(self, op):
+    def propagate_postprocess(self, op):
+        pass
+
+    def emit_extra(self, op):
+        # no forwarding, because we're at the end of the chain
+        self.emit(op)
+
+    def emit(self, op, callback_func=None, *callback_args):
+        # this actually emits the operation instead of forwarding it
         if op.returns_bool_result():
             self.getintbound(op).make_bool()
         self._emit_operation(op)
@@ -725,7 +762,7 @@
         return op
 
     def optimize_default(self, op):
-        self.emit_operation(op)
+        self.emit(op)
 
     def constant_fold(self, op):
         argboxes = [self.get_constant_box(op.getarg(i))
@@ -803,14 +840,14 @@
     #def optimize_GUARD_NO_OVERFLOW(self, op):
     #    # otherwise the default optimizer will clear fields, which is unwanted
     #    # in this case
-    #    self.emit_operation(op)
+    #    self.emit(op)
     # FIXME: Is this still needed?
 
     def optimize_DEBUG_MERGE_POINT(self, op):
-        self.emit_operation(op)
+        self.emit(op)
 
     def optimize_JIT_DEBUG(self, op):
-        self.emit_operation(op)
+        self.emit(op)
 
     def optimize_STRGETITEM(self, op):
         indexb = self.getintbound(op.getarg(1))
diff --git a/rpython/jit/metainterp/optimizeopt/pure.py b/rpython/jit/metainterp/optimizeopt/pure.py
--- a/rpython/jit/metainterp/optimizeopt/pure.py
+++ b/rpython/jit/metainterp/optimizeopt/pure.py
@@ -71,7 +71,10 @@
         self.extra_call_pure = []
 
     def propagate_forward(self, op):
-        dispatch_opt(self, op)
+        return dispatch_opt(self, op)
+
+    def propagate_postprocess(self, op, oldop):
+        dispatch_postprocess(self, op, oldop)
 
     def optimize_default(self, op):
         canfold = op.is_always_pure()
@@ -108,17 +111,17 @@
                 return
 
         # otherwise, the operation remains
-        self.emit_operation(op)
-        self.optimize_default_callback(op, save, nextop)
+        return self.emit(op, self.postprocess_default, save, nextop)
 
-    def optimize_default_callback(self, op, save, nextop):
+    def postprocess_default(self, op, oldop, save, nextop):
+        # postprocessor for optimize_default, not default postprocessor
         if op.returns_bool_result():
             self.getintbound(op).make_bool()
         if save:
             recentops = self.getrecentops(op.getopnum())
             recentops.add(op)
         if nextop:
-            self.emit_operation(nextop)
+            self.emit_extra(nextop)
 
     def getrecentops(self, opnum):
         if rop._OVF_FIRST <= opnum <= rop._OVF_LAST:
@@ -161,10 +164,9 @@
         # replace CALL_PURE with just CALL
         opnum = OpHelpers.call_for_descr(op.getdescr())
         newop = self.optimizer.replace_op_with(op, opnum)
-        self.emit_operation(newop)
-        self.optimize_CALL_PURE_I_callback(op)
+        return self.emit(newop, self.postprocess_call_pure)
 
-    def optimize_CALL_PURE_I_callback(self, op):
+    def postprocess_call_pure(self, op, oldop):
         self.call_pure_positions.append(
             len(self.optimizer._newoperations) - 1)
 
@@ -196,7 +198,7 @@
             # it was a CALL_PURE that was killed; so we also kill the
             # following GUARD_NO_EXCEPTION
             return
-        self.emit_operation(op)
+        return self.emit(op)
 
     def flush(self):
         assert self.postponed_op is None
@@ -242,3 +244,4 @@
 
 dispatch_opt = make_dispatcher_method(OptPure, 'optimize_',
                                       default=OptPure.optimize_default)
+dispatch_postprocess = make_dispatcher_method(OptPure, 'postprocess_')
diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py
--- a/rpython/jit/metainterp/optimizeopt/rewrite.py
+++ b/rpython/jit/metainterp/optimizeopt/rewrite.py
@@ -24,9 +24,6 @@
         self.loop_invariant_results = {}
         self.loop_invariant_producer = {}
 
-    def opt_default(self, op):
-        return op
-
     def setup(self):
         self.optimizer.optrewrite = self
 
@@ -103,7 +100,7 @@
                 self.make_equal_to(op, op.getarg(1))
                 return
 
-        return op
+        return self.emit(op)
 
     def optimize_INT_OR(self, op):
         b1 = self.getintbound(op.getarg(0))
@@ -113,7 +110,7 @@
         elif b2.equal(0):
             self.make_equal_to(op, op.getarg(0))
         else:
-            return op
+            return self.emit(op)
 
     def optimize_INT_SUB(self, op):
         arg1 = self.get_box_replacement(op.getarg(0))
@@ -124,18 +121,18 @@
             self.make_equal_to(op, arg1)
         elif b1.equal(0):
             op = self.replace_op_with(op, rop.INT_NEG, args=[arg2])
-            return op
+            return self.emit(op)
         elif arg1.same_box(arg2):
             self.make_constant_int(op, 0)
         else:
-            return op
+            return self.emit(op)
 
     def postprocess_INT_SUB(self, op, oldop):
         self.optimizer.pure_reverse(op)
 
     def optimize_INT_ADD(self, op):
         if self.is_raw_ptr(op.getarg(0)) or self.is_raw_ptr(op.getarg(1)):
-            return op
+            return self.emit(op)
         arg1 = self.get_box_replacement(op.getarg(0))
         b1 = self.getintbound(arg1)
         arg2 = self.get_box_replacement(op.getarg(1))
@@ -147,7 +144,7 @@
         elif b2.equal(0):
             self.make_equal_to(op, arg1)
         else:
-            return op
+            return self.emit(op)
 
     def postprocess_INT_ADD(self, op, oldop):
         self.optimizer.pure_reverse(op)
@@ -175,7 +172,7 @@
                         new_rhs = ConstInt(highest_bit(lh_info.getint()))
                         op = self.replace_op_with(op, rop.INT_LSHIFT, args=[rhs, new_rhs])
                         break
-            return op
+            return self.emit(op)
 
     def optimize_UINT_FLOORDIV(self, op):
         b2 = self.getintbound(op.getarg(1))
@@ -183,7 +180,7 @@
         if b2.is_constant() and b2.getint() == 1:
             self.make_equal_to(op, op.getarg(0))
         else:
-            return op
+            return self.emit(op)
 
     def optimize_INT_LSHIFT(self, op):
         b1 = self.getintbound(op.getarg(0))
@@ -194,7 +191,7 @@
         elif b1.is_constant() and b1.getint() == 0:
             self.make_constant_int(op, 0)
         else:
-            return op
+            return self.emit(op)
 
     def optimize_INT_RSHIFT(self, op):
         b1 = self.getintbound(op.getarg(0))
@@ -205,7 +202,7 @@
         elif b1.is_constant() and b1.getint() == 0:
             self.make_constant_int(op, 0)
         else:
-            return op
+            return self.emit(op)
 
     def optimize_INT_XOR(self, op):
         b1 = self.getintbound(op.getarg(0))
@@ -216,7 +213,7 @@
         elif b2.equal(0):
             self.make_equal_to(op, op.getarg(0))
         else:
-            return op
+            return self.emit(op)
 
     def optimize_FLOAT_MUL(self, op):
         arg1 = op.getarg(0)
@@ -234,8 +231,8 @@
                     return
                 elif v1.getfloat() == -1.0:
                     newop = self.replace_op_with(op, rop.FLOAT_NEG, args=[rhs])
-                    return newop
-        return op
+                    return self.emit(newop)
+        return self.emit(op)
 
     def postprocess_FLOAT_MUL(self, op, oldop):
         self.optimizer.pure_reverse(op)
@@ -259,10 +256,10 @@
                     c = ConstFloat(longlong.getfloatstorage(reciprocal))
                     newop = self.replace_op_with(op, rop.FLOAT_MUL,
                                                  args=[arg1, c])
-        return newop
+        return self.emit(newop)
 
     def optimize_FLOAT_NEG(self, op):
-        return op
+        return self.emit(op)
 
     def postprocess_FLOAT_NEG(self, op, oldop):
         self.optimizer.pure_reverse(op)
@@ -288,7 +285,7 @@
                                       'was proven to always fail' % r)
                 return
 
-        return op
+        return self.emit(op)
 
     def optimize_GUARD_ISNULL(self, op):
         info = self.getptrinfo(op.getarg(0))
@@ -299,7 +296,7 @@
                 r = self.optimizer.metainterp_sd.logger_ops.repr_of_resop(op)
                 raise InvalidLoop('A GUARD_ISNULL (%s) was proven to always '
                                   'fail' % r)
-        return op
+        return self.emit(op)
 
     def postprocess_GUARD_ISNULL(self, op, oldop):
         self.make_constant(op.getarg(0), self.optimizer.cpu.ts.CONST_NULL)
@@ -318,7 +315,7 @@
                 return
             if info.is_precise():
                 raise InvalidLoop()
-        return op
+        return self.emit(op)
 
     def optimize_GUARD_GC_TYPE(self, op):
         info = self.getptrinfo(op.getarg(0))
@@ -332,7 +329,7 @@
             if info.get_descr().get_type_id() != op.getarg(1).getint():
                 raise InvalidLoop("wrong GC types passed around!")
             return
-        return op
+        return self.emit(op)
 
     def _check_subclass(self, vtable1, vtable2):
         # checks that vtable1 is a subclass of vtable2
@@ -366,7 +363,7 @@
                 if self._check_subclass(info.get_descr().get_vtable(),
                                         op.getarg(1).getint()):
                     return
-        return op
+        return self.emit(op)
 
     def optimize_GUARD_NONNULL(self, op):
         opinfo = self.getptrinfo(op.getarg(0))
@@ -377,7 +374,7 @@
                 r = self.optimizer.metainterp_sd.logger_ops.repr_of_resop(op)
                 raise InvalidLoop('A GUARD_NONNULL (%s) was proven to always '
                                   'fail' % r)
-        return op
+        return self.emit(op)
 
     def postprocess_GUARD_NONNULL(self, op, oldop):
         self.make_nonnull(op.getarg(0))
@@ -486,8 +483,8 @@
                 # not put in short preambles guard_nonnull and guard_class
                 # on the same box.
                 self.optimizer.replace_guard(op, info)
-                return op
-        return op
+                return self.emit(op)
+        return self.emit(op)
 
     def postprocess_GUARD_CLASS(self, op, oldop):
         expectedclassbox = op.getarg(1)
@@ -525,7 +522,7 @@
         # there is no reason to have a separate operation for this
         newop = self.replace_op_with(op,
                                      OpHelpers.call_for_descr(op.getdescr()))
-        return op
+        return self.emit(op)
 
     def postprocess_CALL_LOOPINVARIANT_I(self, op, oldop):
         key = make_hashable_int(op.getarg(0).getint())
@@ -549,7 +546,7 @@
                 return
             opnum = OpHelpers.call_for_type(op.type)
             op = op.copy_and_change(opnum, args=op.getarglist()[1:])
-        return op
+        return self.emit(op)
 
     def _optimize_nullness(self, op, box, expect_nonnull):
         info = self.getnullness(box)
@@ -558,7 +555,7 @@
         elif info == INFO_NULL:
             self.make_constant_int(op, not expect_nonnull)
         else:
-            return op
+            return self.emit(op)
 
     def optimize_INT_IS_TRUE(self, op):
         if (not self.is_raw_ptr(op.getarg(0)) and
@@ -605,7 +602,7 @@
                         # class is different
                         self.make_constant_int(op, expect_isnot)
                         return
-            return op
+            return self.emit(op)
 
     def optimize_PTR_EQ(self, op):
         return self._optimize_oois_ooisnot(op, False, False)
@@ -627,7 +624,7 @@
         oopspecindex = effectinfo.oopspecindex
         if oopspecindex == EffectInfo.OS_ARRAYCOPY:
             return self._optimize_CALL_ARRAYCOPY(op)
-        return op
+        return self.emit(op)
 
     def _optimize_CALL_ARRAYCOPY(self, op):
         length = self.get_constant_box(op.getarg(5))
@@ -648,7 +645,7 @@
             dest_start = dest_start_box.getint()
             arraydescr = extrainfo.write_descrs_arrays[0]
             if arraydescr.is_array_of_structs():
-                return op       # not supported right now
+                return self.emit(op)       # not supported right now
 
             # XXX fish fish fish
             for index in range(length.getint()):
@@ -676,7 +673,7 @@
                                          descr=arraydescr)
                     self.optimizer.send_extra_operation(newop)
             return None
-        return op
+        return self.emit(op)
 
     def optimize_CALL_PURE_I(self, op):
         # this removes a CALL_PURE with all constant arguments.
@@ -686,7 +683,7 @@
             self.make_constant(op, result)
             self.last_emitted_operation = REMOVED
             return
-        return op
+        return self.emit(op)
 
     optimize_CALL_PURE_R = optimize_CALL_PURE_I
     optimize_CALL_PURE_F = optimize_CALL_PURE_I
@@ -697,7 +694,7 @@
             # it was a CALL_PURE or a CALL_LOOPINVARIANT that was killed;
             # so we also kill the following GUARD_NO_EXCEPTION
             return
-        return op
+        return self.emit(op)
 
     def optimize_GUARD_FUTURE_CONDITION(self, op):
         self.optimizer.notice_guard_future_condition(op)
@@ -719,15 +716,15 @@
             if val & (val - 1) == 0 and val > 0: # val == 2**shift
                 op = self.replace_op_with(op, rop.INT_RSHIFT,
                             args = [op.getarg(0), ConstInt(highest_bit(val))])
-        return op
+        return self.emit(op)
 
     def optimize_CAST_PTR_TO_INT(self, op):
         self.optimizer.pure_reverse(op)
-        return op
+        return self.emit(op)
 
     def optimize_CAST_INT_TO_PTR(self, op):
         self.optimizer.pure_reverse(op)
-        return op
+        return self.emit(op)
 
     def optimize_SAME_AS_I(self, op):
         self.make_equal_to(op, op.getarg(0))
@@ -735,6 +732,6 @@
     optimize_SAME_AS_F = optimize_SAME_AS_I
 
 dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_',
-        default=OptRewrite.opt_default)
+                                      default=OptRewrite.emit)
 optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD')
 dispatch_postprocess = make_dispatcher_method(OptRewrite, 'postprocess_')
diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py
--- a/rpython/jit/metainterp/optimizeopt/virtualize.py
+++ b/rpython/jit/metainterp/optimizeopt/virtualize.py
@@ -15,9 +15,6 @@
     _last_guard_not_forced_2 = None
     _finish_guard_op = None
 
-    def opt_default(self, op):
-        return op
-
     def make_virtual(self, known_class, source_op, descr):
         opinfo = info.InstancePtrInfo(descr, known_class, is_virtual=True)
         opinfo.init_fields(descr, 0)
@@ -59,19 +56,19 @@
     def optimize_GUARD_NO_EXCEPTION(self, op):
         if self.last_emitted_operation is REMOVED:
             return
-        return op
+        return self.emit(op)
 
     def optimize_GUARD_NOT_FORCED(self, op):
         if self.last_emitted_operation is REMOVED:
             return
-        return op
+        return self.emit(op)
 
     def optimize_GUARD_NOT_FORCED_2(self, op):
         self._last_guard_not_forced_2 = op
 
     def optimize_FINISH(self, op):
         self._finish_guard_op = self._last_guard_not_forced_2
-        return op
+        return self.emit(op)
 
     def postprocess_FINISH(self, op, oldop):
         guard_op = self._finish_guard_op
@@ -87,7 +84,7 @@
         if oopspecindex == EffectInfo.OS_JIT_FORCE_VIRTUAL:
             if self._optimize_JIT_FORCE_VIRTUAL(op):
                 return
-        return op
+        return self.emit(op)
     optimize_CALL_MAY_FORCE_R = optimize_CALL_MAY_FORCE_I
     optimize_CALL_MAY_FORCE_F = optimize_CALL_MAY_FORCE_I
     optimize_CALL_MAY_FORCE_N = optimize_CALL_MAY_FORCE_I
@@ -99,7 +96,7 @@
             opinfo = self.getptrinfo(op.getarg(2))
             if opinfo and opinfo.is_virtual():
                 return
-        return op
+        return self.emit(op)
 
     def optimize_VIRTUAL_REF(self, op):
         # get some constants
@@ -120,7 +117,7 @@
         vrefvalue.setfield(descr_virtual_token, newop, token)
         vrefvalue.setfield(descr_forced, newop,
                            self.optimizer.cpu.ts.CONST_NULLREF)
-        return token
+        return self.emit(token)
 
     def optimize_VIRTUAL_REF_FINISH(self, op):
         # This operation is used in two cases.  In normal cases, it
@@ -183,7 +180,7 @@
             self.make_equal_to(op, fieldop)
         else:
             self.make_nonnull(op.getarg(0))
-            return op
+            return self.emit(op)
     optimize_GETFIELD_GC_R = optimize_GETFIELD_GC_I
     optimize_GETFIELD_GC_F = optimize_GETFIELD_GC_I
 
@@ -201,7 +198,7 @@
                             self.get_box_replacement(op.getarg(1)))
         else:
             self.make_nonnull(struct)
-            return op
+            return self.emit(op)
 
     def optimize_NEW_WITH_VTABLE(self, op):
         known_class = ConstInt(op.getdescr().get_vtable())
@@ -215,14 +212,14 @@
         if sizebox is not None:
             self.make_varray(op.getdescr(), sizebox.getint(), op)
         else:
-            return op
+            return self.emit(op)
 
     def optimize_NEW_ARRAY_CLEAR(self, op):
         sizebox = self.get_constant_box(op.getarg(0))
         if sizebox is not None:
             self.make_varray(op.getdescr(), sizebox.getint(), op, clear=True)
         else:
-            return op
+            return self.emit(op)
 
     def optimize_CALL_N(self, op):
         effectinfo = op.getdescr().get_extra_info()
@@ -236,14 +233,14 @@
             if info and info.is_virtual():
                 return
         else:
-            return op
+            return self.emit(op)
     optimize_CALL_R = optimize_CALL_N
     optimize_CALL_I = optimize_CALL_N
 
     def do_RAW_MALLOC_VARSIZE_CHAR(self, op):
         sizebox = self.get_constant_box(op.getarg(1))
         if sizebox is None:
-            return op
+            return self.emit(op)
         self.make_virtual_raw_memory(sizebox.getint(), op)
         self.last_emitted_operation = REMOVED
 
@@ -251,7 +248,7 @@
         opinfo = self.getrawptrinfo(op.getarg(1))
         if opinfo and opinfo.is_virtual():
             return
-        return op
+        return self.emit(op)
 
     def optimize_INT_ADD(self, op):
         opinfo = self.getrawptrinfo(op.getarg(0), create=False)
@@ -264,7 +261,7 @@
                 isinstance(opinfo, info.RawSlicePtrInfo)):
                 self.make_virtual_raw_slice(offset, opinfo, op)
                 return
-        return op
+        return self.emit(op)
 
     def optimize_ARRAYLEN_GC(self, op):
         opinfo = self.getptrinfo(op.getarg(0))
@@ -272,7 +269,7 @@
             self.make_constant_int(op, opinfo.getlength())
         else:
             self.make_nonnull(op.getarg(0))
-            return op
+            return self.emit(op)
 
     def optimize_GETARRAYITEM_GC_I(self, op):
         opinfo = self.getptrinfo(op.getarg(0))
@@ -286,7 +283,7 @@
                 self.make_equal_to(op, item)
                 return
         self.make_nonnull(op.getarg(0))
-        return op
+        return self.emit(op)
     optimize_GETARRAYITEM_GC_R = optimize_GETARRAYITEM_GC_I
     optimize_GETARRAYITEM_GC_F = optimize_GETARRAYITEM_GC_I
 
@@ -306,7 +303,7 @@
                                self.get_box_replacement(op.getarg(2)))
                 return
         self.make_nonnull(op.getarg(0))
-        return op
+        return self.emit(op)
 
     def _unpack_arrayitem_raw_op(self, op, indexbox):
         index = indexbox.getint()
@@ -331,7 +328,7 @@
                     self.make_equal_to(op, itemvalue)
                     return
         self.make_nonnull(op.getarg(0))
-        return op
+        return self.emit(op)
     optimize_GETARRAYITEM_RAW_F = optimize_GETARRAYITEM_RAW_I
 
     def optimize_SETARRAYITEM_RAW(self, op):
@@ -347,7 +344,7 @@
                 except InvalidRawOperation:
                     pass
         self.make_nonnull(op.getarg(0))
-        return op
+        return self.emit(op)
 
     def _unpack_raw_load_store_op(self, op, offsetbox):
         offset = offsetbox.getint()
@@ -369,7 +366,7 @@
                 else:
                     self.make_equal_to(op, itemop)
                     return
-        return op
+        return self.emit(op)
     optimize_RAW_LOAD_F = optimize_RAW_LOAD_I
 
     def optimize_RAW_STORE(self, op):
@@ -383,7 +380,7 @@
                     return
                 except InvalidRawOperation:
                     pass
-        return op
+        return self.emit(op)
 
     def optimize_GETINTERIORFIELD_GC_I(self, op):
         opinfo = self.getptrinfo(op.getarg(0))
@@ -399,7 +396,7 @@
                 self.make_equal_to(op, fld)
                 return
         self.make_nonnull(op.getarg(0))
-        return op
+        return self.emit(op)
     optimize_GETINTERIORFIELD_GC_R = optimize_GETINTERIORFIELD_GC_I
     optimize_GETINTERIORFIELD_GC_F = optimize_GETINTERIORFIELD_GC_I
 
@@ -413,11 +410,11 @@
                                        self.get_box_replacement(op.getarg(2)))
                 return
         self.make_nonnull(op.getarg(0))
-        return op
+        return self.emit(op)
 
 
 dispatch_opt = make_dispatcher_method(OptVirtualize, 'optimize_',
-        default=OptVirtualize.opt_default)
+                                      default=OptVirtualize.emit)
 
 OptVirtualize.propagate_forward = dispatch_opt
 dispatch_postprocess = make_dispatcher_method(OptVirtualize, 'postprocess_')
diff --git a/rpython/jit/metainterp/optimizeopt/vstring.py b/rpython/jit/metainterp/optimizeopt/vstring.py
--- a/rpython/jit/metainterp/optimizeopt/vstring.py
+++ b/rpython/jit/metainterp/optimizeopt/vstring.py
@@ -97,7 +97,7 @@
         newop = ResOperation(self.mode.NEWSTR, [lengthbox])
         if not we_are_translated():
             newop.name = 'FORCE'
-        optforce.emit_operation(newop)
+        optforce.emit_extra(newop)
         newop = optforce.getlastop()
         newop.set_forwarded(self)
         op = optforce.get_box_replacement(op)
@@ -120,7 +120,7 @@
         lengthop = ResOperation(mode.STRLEN, [op])
         lengthop.set_forwarded(self.getlenbound(mode))
         self.lgtop = lengthop
-        string_optimizer.emit_operation(lengthop)
+        string_optimizer.emit_extra(lengthop)
         return lengthop
 
     def make_guards(self, op, short, optimizer):
@@ -204,7 +204,7 @@
                 op = ResOperation(mode.STRSETITEM, [targetbox,
                                                     offsetbox,
                                                     charbox])
-                string_optimizer.emit_operation(op)
+                string_optimizer.emit_extra(op)
             offsetbox = _int_add(string_optimizer, offsetbox, CONST_1)
         return offsetbox
 
@@ -356,7 +356,7 @@
                                                   mode)
             srcoffsetbox = _int_add(string_optimizer, srcoffsetbox, CONST_1)
             assert not isinstance(targetbox, Const)# ConstPtr never makes sense
-            string_optimizer.emit_operation(ResOperation(mode.STRSETITEM,
+            string_optimizer.emit_extra(ResOperation(mode.STRSETITEM,
                     [targetbox, offsetbox, charbox]))
             offsetbox = _int_add(string_optimizer, offsetbox, CONST_1)
     else:
@@ -368,7 +368,7 @@
         op = ResOperation(mode.COPYSTRCONTENT, [srcbox, targetbox,
                                                 srcoffsetbox, offsetbox,
                                                 lengthbox])
-        string_optimizer.emit_operation(op)
+        string_optimizer.emit_extra(op)
         offsetbox = nextoffsetbox
     return offsetbox
 
@@ -412,7 +412,7 @@
     else:
         resbox = string_optimizer.replace_op_with(resbox, mode.STRGETITEM,
                                                   [strbox, indexbox])
-    string_optimizer.emit_operation(resbox)
+    string_optimizer.emit_extra(resbox)
     return resbox
 
 
@@ -422,6 +422,12 @@
     def setup(self):
         self.optimizer.optstring = self
 
+    def propagate_forward(self, op):
+        return dispatch_opt(self, op)
+
+    def propagate_postprocess(self, op, oldop):
+        return dispatch_postprocess(self, op, oldop)
+
     def make_vstring_plain(self, op, mode, length):
         vvalue = VStringPlainInfo(mode, True, length)
         op = self.replace_op_with(op, op.getopnum())
@@ -441,9 +447,9 @@
         return vvalue
 
     def optimize_NEWSTR(self, op):
-        self._optimize_NEWSTR(op, mode_string)
+        return self._optimize_NEWSTR(op, mode_string)
     def optimize_NEWUNICODE(self, op):
-        self._optimize_NEWSTR(op, mode_unicode)
+        return self._optimize_NEWSTR(op, mode_unicode)
 
     def _optimize_NEWSTR(self, op, mode):
         length_box = self.get_constant_box(op.getarg(0))
@@ -452,11 +458,13 @@
             self.make_vstring_plain(op, mode, length_box.getint())
         else:
             self.make_nonnull_str(op, mode)
-            self.emit_operation(op)
-            self._optimize_NEWSTR_callback(op, mode)
+            return self.emit(op)
 
-    def _optimize_NEWSTR_callback(self, op, mode):
-        self.pure_from_args(mode.STRLEN, [op], op.getarg(0))
+    def postprocess_NEWSTR(self, op, oldop):
+        self.pure_from_args(mode_string.STRLEN, [op], op.getarg(0))
+
+    def postprocess_NEWUNICODE(self, op, oldop):
+        self.pure_from_args(mode_unicode.STRLEN, [op], op.getarg(0))
 
     def optimize_STRSETITEM(self, op):
         opinfo = self.getptrinfo(op.getarg(0))
@@ -467,17 +475,17 @@
             indexbox = self.get_constant_box(op.getarg(1))
             if indexbox is not None:
                 opinfo.strsetitem(indexbox.getint(),
-                              self.get_box_replacement(op.getarg(2)))
+                                  self.get_box_replacement(op.getarg(2)))
                 return
         self.make_nonnull(op.getarg(0))
-        self.emit_operation(op)
+        return self.emit(op)
 
     optimize_UNICODESETITEM = optimize_STRSETITEM
 
     def optimize_STRGETITEM(self, op):
-        self._optimize_STRGETITEM(op, mode_string)
+        return self._optimize_STRGETITEM(op, mode_string)
     def optimize_UNICODEGETITEM(self, op):
-        self._optimize_STRGETITEM(op, mode_unicode)
+        return self._optimize_STRGETITEM(op, mode_unicode)
 
     def _optimize_STRGETITEM(self, op, mode):
         self.strgetitem(op, op.getarg(0), op.getarg(1), mode)
@@ -517,9 +525,9 @@
         return _strgetitem(self, s, index, mode, op)
 
     def optimize_STRLEN(self, op):
-        self._optimize_STRLEN(op, mode_string)
+        return self._optimize_STRLEN(op, mode_string)
     def optimize_UNICODELEN(self, op):
-        self._optimize_STRLEN(op, mode_unicode)
+        return self._optimize_STRLEN(op, mode_unicode)
 
     def _optimize_STRLEN(self, op, mode):
         opinfo = self.getptrinfo(op.getarg(0))
@@ -528,13 +536,13 @@
             if lgtop is not None:
                 self.make_equal_to(op, lgtop)
                 return
-        self.emit_operation(op)
+        return self.emit(op)
 
     def optimize_COPYSTRCONTENT(self, op):
-        self._optimize_COPYSTRCONTENT(op, mode_string)
+        return self._optimize_COPYSTRCONTENT(op, mode_string)
 
     def optimize_COPYUNICODECONTENT(self, op):
-        self._optimize_COPYSTRCONTENT(op, mode_unicode)
+        return self._optimize_COPYSTRCONTENT(op, mode_unicode)
 
     def _optimize_COPYSTRCONTENT(self, op, mode):
         # args: src dst srcstart dststart length
@@ -569,7 +577,7 @@
                         op.getarg(1), ConstInt(index + dst_start),
                         vresult,
                     ])
-                    self.emit_operation(new_op)
+                    self.emit_extra(new_op)
         else:
             copy_str_content(self, op.getarg(0), op.getarg(1), op.getarg(2),
                              op.getarg(3), op.getarg(4), mode,
@@ -584,13 +592,15 @@
         if oopspecindex != EffectInfo.OS_NONE:
             for value, meth in opt_call_oopspec_ops:
                 if oopspecindex == value:      # a match with the OS_STR_xxx
-                    if meth(self, op, mode_string):
-                        return
+                    handled, newop = meth(self, op, mode_string)
+                    if handled:
+                        return newop
                     break
                 if oopspecindex == value + EffectInfo._OS_offset_uni:
                     # a match with the OS_UNI_xxx
-                    if meth(self, op, mode_unicode):
-                        return
+                    handled, newop = meth(self, op, mode_unicode)
+                    if handled:
+                        return newop
                     break
             if oopspecindex == EffectInfo.OS_STR2UNICODE:
                 if self.opt_call_str_STR2UNICODE(op):
@@ -598,7 +608,7 @@
             if oopspecindex == EffectInfo.OS_SHRINK_ARRAY:
                 if self.opt_call_SHRINK_ARRAY(op):
                     return
-        self.emit_operation(op)
+        return self.emit(op)
     optimize_CALL_R = optimize_CALL_I
     optimize_CALL_F = optimize_CALL_I
     optimize_CALL_N = optimize_CALL_I
@@ -610,7 +620,7 @@
     def optimize_GUARD_NO_EXCEPTION(self, op):
         if self.last_emitted_operation is REMOVED:
             return
-        self.emit_operation(op)
+        return self.emit(op)
 
     def opt_call_str_STR2UNICODE(self, op):
         # Constant-fold unicode("constant string").
@@ -638,7 +648,7 @@
                                  self.get_box_replacement(op.getarg(1)),
                                  self.get_box_replacement(op.getarg(2)))
         self.last_emitted_operation = REMOVED
-        return True
+        return True, None
 
     def opt_call_stroruni_STR_SLICE(self, op, mode):
         self.make_nonnull_str(op.getarg(1), mode)
@@ -651,7 +661,7 @@
             value = self.make_vstring_plain(op, mode, -1)
             value.setup_slice(vstr._chars, vstart.getint(),
                               vstop.getint())
-            return True
+            return True, None
         #
         startbox = op.getarg(2)
         strbox = op.getarg(1)
@@ -664,7 +674,7 @@
         #
         self.make_vstring_slice(op, strbox, startbox, mode, lengthbox)
         self.last_emitted_operation = REMOVED
-        return True
+        return True, None
 
     @specialize.arg(2)
     def opt_call_stroruni_STR_EQUAL(self, op, mode):
@@ -687,25 +697,28 @@
             l1box.value != l2box.value):
             # statically known to have a different length
             self.make_constant(op, CONST_0)
-            return True
+            return True, None
         #
-        if self.handle_str_equal_level1(arg1, arg2, op, mode):
-            return True
-        if self.handle_str_equal_level1(arg2, arg1, op, mode):
-            return True
-        if self.handle_str_equal_level2(arg1, arg2, op, mode):
-            return True
-        if self.handle_str_equal_level2(arg2, arg1, op, mode):
-            return True
+        handled, result = self.handle_str_equal_level1(arg1, arg2, op, mode)
+        if handled:
+            return True, result
+        handled, result = self.handle_str_equal_level1(arg2, arg1, op, mode)
+        if handled:
+            return True, result
+        handled, result = self.handle_str_equal_level2(arg1, arg2, op, mode)
+        if handled:
+            return True, result
+        handled, result = self.handle_str_equal_level2(arg2, arg1, op, mode)
+        if handled:
+            return True, result
         #
         if i1 and i1.is_nonnull() and i2 and i2.is_nonnull():
             if l1box is not None and l2box is not None and l1box.same_box(l2box):
                 do = EffectInfo.OS_STREQ_LENGTHOK
             else:
                 do = EffectInfo.OS_STREQ_NONNULL
-            self.generate_modified_call(do, [arg1, arg2], op, mode)
-            return True
-        return False
+            return True, self.generate_modified_call(do, [arg1, arg2], op, mode)
+        return False, None
 
     def handle_str_equal_level1(self, arg1, arg2, resultop, mode):
         i1 = self.getptrinfo(arg1)
@@ -728,7 +741,7 @@
                                               [lengthbox, CONST_0],
                                               descr=DONT_CHANGE)
                     seo(op)
-                    return True
+                    return True, None
             if l2box.value == 1:
                 if i1:
                     l1box = i1.getstrlen(arg1, self, mode, False)
@@ -742,30 +755,28 @@
                     op = self.optimizer.replace_op_with(resultop, rop.INT_EQ,
                                 [vchar1, vchar2], descr=DONT_CHANGE)
                     seo(op)
-                    return True
+                    return True, None
                 if isinstance(i1, VStringSliceInfo):
                     vchar = self.strgetitem(None, arg2, optimizer.CONST_0,
                                             mode)
                     do = EffectInfo.OS_STREQ_SLICE_CHAR
-                    self.generate_modified_call(do, [i1.s, i1.start,
-                                                     i1.lgtop, vchar],
-                                                     resultop, mode)
-                    return True
+                    return True, self.generate_modified_call(do, [i1.s, i1.start,
+                                                                  i1.lgtop, vchar],
+                                                             resultop, mode)
         #
         if i2 and i2.is_null():
             if i1 and i1.is_nonnull():
                 self.make_constant(resultop, CONST_0)
-                return True
+                return True, None
             if i1 and i1.is_null():
                 self.make_constant(resultop, CONST_1)
-                return True
+                return True, None
             op = self.optimizer.replace_op_with(resultop, rop.PTR_EQ,
                                                 [arg1, llhelper.CONST_NULL],
                                                 descr=DONT_CHANGE)
-            self.emit_operation(op)
-            return True
+            return True, self.emit(op)
         #
-        return False
+        return False, None
 
     def handle_str_equal_level2(self, arg1, arg2, resultbox, mode):
         i1 = self.getptrinfo(arg1)
@@ -782,25 +793,23 @@
                         do = EffectInfo.OS_STREQ_NONNULL_CHAR
                     else:
                         do = EffectInfo.OS_STREQ_CHECKNULL_CHAR
-                    self.generate_modified_call(do, [arg1, vchar],
-                                                resultbox, mode)
-                    return True
+                    return True, self.generate_modified_call(do, [arg1, vchar],
+                                                             resultbox, mode)
             #
         if isinstance(i1, VStringSliceInfo) and i1.is_virtual():
             if i2 and i2.is_nonnull():
                 do = EffectInfo.OS_STREQ_SLICE_NONNULL
             else:
                 do = EffectInfo.OS_STREQ_SLICE_CHECKNULL
-            self.generate_modified_call(do, [i1.s, i1.start, i1.lgtop,
-                                             arg2], resultbox, mode)
-            return True
-        return False
+            return True, self.generate_modified_call(do, [i1.s, i1.start, i1.lgtop,
+                                                          arg2], resultbox, mode)
+        return False, None
 
     def opt_call_stroruni_STR_CMP(self, op, mode):
         i1 = self.getptrinfo(op.getarg(1))
         i2 = self.getptrinfo(op.getarg(2))
         if not i1 or not i2:
-            return False
+            return False, None
         l1box = i1.getstrlen(None, self, mode, False)
         l2box = i2.getstrlen(None, self, mode, False)
         if (l1box is not None and l2box is not None and
@@ -814,8 +823,8 @@
             op = self.replace_op_with(op, rop.INT_SUB, [char1, char2],
                                       descr=DONT_CHANGE)
             seo(op)
-            return True
-        return False
+            return True, None
+        return False, None
 
     def opt_call_SHRINK_ARRAY(self, op):
         i1 = self.getptrinfo(op.getarg(1))
@@ -838,14 +847,12 @@
         op = self.optimizer.replace_op_with(result, rop.CALL_I,
                                             [ConstInt(func)] + args,
                                             descr=calldescr)
-        self.emit_operation(op)
-
-    def propagate_forward(self, op):
-        dispatch_opt(self, op)
+        return self.emit(op)
 
 
 dispatch_opt = make_dispatcher_method(OptString, 'optimize_',
-        default=OptString.emit_operation)
+                                      default=OptString.emit)
+dispatch_postprocess = make_dispatcher_method(OptString, 'postprocess_')
 
 
 def _findall_call_oopspec():


More information about the pypy-commit mailing list