[pypy-commit] pypy default: Merge share-guard-info

fijal noreply at buildbot.pypy.org
Sat Oct 3 11:03:28 CEST 2015


Author: fijal
Branch: 
Changeset: r79945:054840779e3e
Date: 2015-10-03 11:03 +0200
http://bitbucket.org/pypy/pypy/changeset/054840779e3e/

Log:	Merge share-guard-info

	This branch shares guard resume descr wherever possible during the
	backend. Saves quite a bit of memory and also time when tracing

diff too long, truncating to 2000 out of 2705 lines

diff --git a/pypy/module/micronumpy/support.py b/pypy/module/micronumpy/support.py
--- a/pypy/module/micronumpy/support.py
+++ b/pypy/module/micronumpy/support.py
@@ -39,7 +39,10 @@
 def product_check(s):
     i = 1
     for x in s:
-        i = ovfcheck(i * x)
+        try:
+            i = ovfcheck(i * x)
+        except OverflowError:
+            raise
     return i
 
 def check_and_adjust_index(space, index, size, axis):
diff --git a/pypy/objspace/std/intobject.py b/pypy/objspace/std/intobject.py
--- a/pypy/objspace/std/intobject.py
+++ b/pypy/objspace/std/intobject.py
@@ -249,11 +249,17 @@
     ix = 1
     while iw > 0:
         if iw & 1:
-            ix = ovfcheck(ix * temp)
+            try:
+                ix = ovfcheck(ix * temp)
+            except OverflowError:
+                raise
         iw >>= 1   # Shift exponent down by 1 bit
         if iw == 0:
             break
-        temp = ovfcheck(temp * temp) # Square the value of temp
+        try:
+            temp = ovfcheck(temp * temp) # Square the value of temp
+        except OverflowError:
+            raise
         if iz:
             # If we did a multiplication, perform a modulo
             ix %= iz
diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py
--- a/rpython/jit/backend/arm/regalloc.py
+++ b/rpython/jit/backend/arm/regalloc.py
@@ -671,6 +671,8 @@
         a0, a1 = boxes
         imm_a1 = check_imm_box(a1)
         l0 = self.make_sure_var_in_reg(a0, boxes)
+        op.getdescr().make_a_counter_per_value(op,
+            self.cpu.all_reg_indexes[l0.value])
         if not imm_a1:
             l1 = self.make_sure_var_in_reg(a1, boxes)
         else:
diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -40,6 +40,10 @@
         self.inputargs = map(mapping, inputargs)
         self.operations = []
         for op in operations:
+            if op.getopnum() == rop.GUARD_VALUE:
+                # we don't care about the value 13 here, because we gonna
+                # fish it from the extra slot on frame anyway
+                op.getdescr().make_a_counter_per_value(op, 13)
             if op.getdescr() is not None:
                 if op.is_guard() or op.getopnum() == rop.FINISH:
                     newdescr = op.getdescr()
@@ -372,6 +376,18 @@
         except ExecutionFinished, e:
             return e.deadframe
 
+    def get_value_direct(self, deadframe, tp, index):
+        v = deadframe._extra_value
+        if tp == 'i':
+            assert lltype.typeOf(v) == lltype.Signed
+        elif tp == 'r':
+            assert lltype.typeOf(v) == llmemory.GCREF
+        elif tp == 'f':
+            assert lltype.typeOf(v) == longlong.FLOATSTORAGE
+        else:
+            assert False
+        return v
+
     def get_int_value(self, deadframe, index):
         v = deadframe._values[index]
         assert lltype.typeOf(v) == lltype.Signed
@@ -775,11 +791,13 @@
     _TYPE = llmemory.GCREF
 
     def __init__(self, latest_descr, values,
-                 last_exception=None, saved_data=None):
+                 last_exception=None, saved_data=None,
+                 extra_value=None):
         self._latest_descr = latest_descr
         self._values = values
         self._last_exception = last_exception
         self._saved_data = saved_data
+        self._extra_value = extra_value
 
 
 class LLFrame(object):
@@ -872,7 +890,7 @@
 
     # -----------------------------------------------------
 
-    def fail_guard(self, descr, saved_data=None):
+    def fail_guard(self, descr, saved_data=None, extra_value=None):
         values = []
         for box in self.current_op.getfailargs():
             if box is not None:
@@ -887,7 +905,7 @@
         else:
             raise ExecutionFinished(LLDeadFrame(descr, values,
                                                 self.last_exception,
-                                                saved_data))
+                                                saved_data, extra_value))
 
     def execute_force_spill(self, _, arg):
         pass
@@ -909,7 +927,7 @@
 
     def execute_guard_value(self, descr, arg1, arg2):
         if arg1 != arg2:
-            self.fail_guard(descr)
+            self.fail_guard(descr, extra_value=arg1)
 
     def execute_guard_nonnull(self, descr, arg):
         if not arg:
@@ -1028,7 +1046,6 @@
     def execute_guard_overflow(self, descr):
         if not self.overflow_flag:
             self.fail_guard(descr)
-        return lltype.nullptr(llmemory.GCREF.TO) # I think it's fine....
 
     def execute_jump(self, descr, *args):
         raise Jump(descr._llgraph_target, args)
diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py
--- a/rpython/jit/backend/llsupport/llmodel.py
+++ b/rpython/jit/backend/llsupport/llmodel.py
@@ -389,20 +389,40 @@
         descr = self.get_latest_descr(deadframe)
         return rffi.cast(lltype.Signed, descr.rd_locs[index]) * WORD
 
+    @specialize.arg(2)
+    def get_value_direct(self, deadframe, tp, index):
+        if tp == 'i':
+            return self.get_int_value_direct(deadframe, index * WORD)
+        elif tp == 'r':
+            return self.get_ref_value_direct(deadframe, index * WORD)
+        elif tp == 'f':
+            return self.get_float_value_direct(deadframe, index * WORD)
+        else:
+            assert False
+
     def get_int_value(self, deadframe, index):
         pos = self._decode_pos(deadframe, index)
+        return self.get_int_value_direct(deadframe, pos)
+
+    def get_int_value_direct(self, deadframe, pos):
         descr = self.gc_ll_descr.getframedescrs(self).arraydescr
         ofs = self.unpack_arraydescr(descr)
         return self.read_int_at_mem(deadframe, pos + ofs, WORD, 1)
 
     def get_ref_value(self, deadframe, index):
         pos = self._decode_pos(deadframe, index)
+        return self.get_ref_value_direct(deadframe, pos)
+
+    def get_ref_value_direct(self, deadframe, pos):
         descr = self.gc_ll_descr.getframedescrs(self).arraydescr
         ofs = self.unpack_arraydescr(descr)
         return self.read_ref_at_mem(deadframe, pos + ofs)
 
     def get_float_value(self, deadframe, index):
         pos = self._decode_pos(deadframe, index)
+        return self.get_float_value_direct(deadframe, pos)
+
+    def get_float_value_direct(self, deadframe, pos):
         descr = self.gc_ll_descr.getframedescrs(self).arraydescr
         ofs = self.unpack_arraydescr(descr)
         return self.read_float_at_mem(deadframe, pos + ofs)
diff --git a/rpython/jit/backend/test/test_random.py b/rpython/jit/backend/test/test_random.py
--- a/rpython/jit/backend/test/test_random.py
+++ b/rpython/jit/backend/test/test_random.py
@@ -22,6 +22,8 @@
         self.operations = subops
 
 class FakeMetaInterp(object):
+    ovf_flag = False
+    
     def execute_raised(self, exc, constant=False):
         self._got_exc = exc
 
@@ -365,9 +367,9 @@
     def produce_into(self, builder, r):
         fail_subset = builder.subset_of_intvars(r)
         original_intvars = builder.intvars[:]
+        builder.fakemetainterp.ovf_flag = False
         super(AbstractOvfOperation, self).produce_into(builder, r)
-        if builder.fakemetainterp._got_exc:   # overflow detected
-            assert isinstance(builder.fakemetainterp._got_exc, OverflowError)
+        if builder.fakemetainterp.ovf_flag:   # overflow detected
             op = ResOperation(rop.GUARD_OVERFLOW, [])
             # the overflowed result should not be used any more, but can
             # be used on the failure path: recompute fail_subset including
diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -424,6 +424,8 @@
 
     def consider_guard_value(self, op):
         x = self.make_sure_var_in_reg(op.getarg(0))
+        loc = self.assembler.cpu.all_reg_indexes[x.value]
+        op.getdescr().make_a_counter_per_value(op, loc)
         y = self.loc(op.getarg(1))
         self.perform_guard(op, [x, y], None)
 
diff --git a/rpython/jit/codewriter/codewriter.py b/rpython/jit/codewriter/codewriter.py
--- a/rpython/jit/codewriter/codewriter.py
+++ b/rpython/jit/codewriter/codewriter.py
@@ -48,7 +48,7 @@
         # which means mostly producing a linear list of operations and
         # inserting jumps or conditional jumps.  This is a list of tuples
         # of the shape ("opname", arg1, ..., argN) or (Label(...),).
-        ssarepr = flatten_graph(graph, regallocs)
+        ssarepr = flatten_graph(graph, regallocs, cpu=self.callcontrol.cpu)
         #
         # step 3b: compute the liveness around certain operations
         compute_liveness(ssarepr)
diff --git a/rpython/jit/codewriter/flatten.py b/rpython/jit/codewriter/flatten.py
--- a/rpython/jit/codewriter/flatten.py
+++ b/rpython/jit/codewriter/flatten.py
@@ -1,4 +1,4 @@
-from rpython.flowspace.model import Variable, Constant
+from rpython.flowspace.model import Variable, Constant, c_last_exception
 from rpython.jit.metainterp.history import AbstractDescr, getkind
 from rpython.rtyper.lltypesystem import lltype
 
@@ -60,10 +60,11 @@
 
 # ____________________________________________________________
 
-def flatten_graph(graph, regallocs, _include_all_exc_links=False):
+def flatten_graph(graph, regallocs, _include_all_exc_links=False,
+                  cpu=None):
     """Flatten the graph into an SSARepr, with already-computed register
     allocations.  'regallocs' in a dict {kind: RegAlloc}."""
-    flattener = GraphFlattener(graph, regallocs, _include_all_exc_links)
+    flattener = GraphFlattener(graph, regallocs, _include_all_exc_links, cpu)
     flattener.enforce_input_args()
     flattener.generate_ssa_form()
     return flattener.ssarepr
@@ -71,9 +72,11 @@
 
 class GraphFlattener(object):
 
-    def __init__(self, graph, regallocs, _include_all_exc_links=False):
+    def __init__(self, graph, regallocs, _include_all_exc_links=False,
+                 cpu=None):
         self.graph = graph
         self.regallocs = regallocs
+        self.cpu = cpu
         self._include_all_exc_links = _include_all_exc_links
         self.registers = {}
         if graph:
@@ -100,7 +103,7 @@
         self.seen_blocks = {}
         self.make_bytecode_block(self.graph.startblock)
 
-    def make_bytecode_block(self, block):
+    def make_bytecode_block(self, block, handling_ovf=False):
         if block.exits == ():
             self.make_return(block.inputargs)
             return
@@ -114,9 +117,15 @@
         #
         operations = block.operations
         for i, op in enumerate(operations):
+            if '_ovf' in op.opname:
+                if (len(block.exits) not in (2, 3) or
+                    block.exitswitch is not c_last_exception):
+                    raise Exception("detected a block containing ovfcheck()"
+                                    " but no OverflowError is caught, this"
+                                    " is not legal in jitted blocks")
             self.serialize_op(op)
         #
-        self.insert_exits(block)
+        self.insert_exits(block, handling_ovf)
 
     def make_return(self, args):
         if len(args) == 1:
@@ -136,16 +145,16 @@
             raise Exception("?")
         self.emitline("---")
 
-    def make_link(self, link):
+    def make_link(self, link, handling_ovf):
         if (link.target.exits == ()
             and link.last_exception not in link.args
             and link.last_exc_value not in link.args):
             self.make_return(link.args)     # optimization only
             return
         self.insert_renamings(link)
-        self.make_bytecode_block(link.target)
+        self.make_bytecode_block(link.target, handling_ovf)
 
-    def make_exception_link(self, link):
+    def make_exception_link(self, link, handling_ovf):
         # Like make_link(), but also introduces the 'last_exception' and
         # 'last_exc_value' as variables if needed.  Also check if the link
         # is jumping directly to the re-raising exception block.
@@ -153,54 +162,74 @@
         assert link.last_exc_value is not None
         if link.target.operations == () and link.args == [link.last_exception,
                                                           link.last_exc_value]:
-            self.emitline("reraise")
+            if handling_ovf:
+                exc_data = self.cpu.rtyper.exceptiondata
+                ll_ovf = exc_data.get_standard_ll_exc_instance_by_class(
+                    OverflowError)
+                c = Constant(ll_ovf, concretetype=lltype.typeOf(ll_ovf))
+                self.emitline("raise", c)
+            else:
+                self.emitline("reraise")
             self.emitline("---")
             return   # done
-        self.make_link(link)
+        self.make_link(link, handling_ovf)
 
-    def insert_exits(self, block):
+    def insert_exits(self, block, handling_ovf=False):
         if len(block.exits) == 1:
             # A single link, fall-through
             link = block.exits[0]
             assert link.exitcase in (None, False, True)
             # the cases False or True should not really occur, but can show
             # up in the manually hacked graphs for generators...
-            self.make_link(link)
+            self.make_link(link, handling_ovf)
         #
         elif block.canraise:
             # An exception block. See test_exc_exitswitch in test_flatten.py
             # for an example of what kind of code this makes.
             index = -1
-            while True:
-                lastopname = block.operations[index].opname
-                if lastopname != '-live-':
-                    break
-                index -= 1
+            opname = block.operations[index].opname
+            if '_ovf' in opname:
+                # ovf checking operation as a lat thing, -live- should be
+                # one before it
+                line = self.popline()
+                self.emitline(opname[:7] + '_jump_if_ovf',
+                              TLabel(block.exits[1]), *line[1:])
+                assert len(block.exits) in (2, 3)
+                self.make_link(block.exits[0], False)
+                self.emitline(Label(block.exits[1]))
+                self.make_exception_link(block.exits[1], True)
+                if len(block.exits) == 3:
+                    assert block.exits[2].exitcase is Exception
+                    self.make_exception_link(block.exits[2], False)
+                return
+            else:
+                while True:
+                    lastopname = block.operations[index].opname
+                    if lastopname != '-live-':
+                        break
+                    index -= 1
             assert block.exits[0].exitcase is None # is this always True?
             #
             if not self._include_all_exc_links:
                 if index == -1:
                     # cannot raise: the last instruction is not
                     # actually a '-live-'
-                    self.make_link(block.exits[0])
+                    self.make_link(block.exits[0], False)
                     return
             #
             self.emitline('catch_exception', TLabel(block.exits[0]))
-            self.make_link(block.exits[0])
+            self.make_link(block.exits[0], False)
             self.emitline(Label(block.exits[0]))
             for link in block.exits[1:]:
-                if (link.exitcase is Exception or
-                    (link.exitcase is OverflowError and
-                     lastopname.startswith('int_') and
-                     lastopname.endswith('_ovf'))):
+                if link.exitcase is Exception:
                     # this link captures all exceptions
-                    self.make_exception_link(link)
+                    self.make_exception_link(link, False)
                     break
                 self.emitline('goto_if_exception_mismatch',
                               Constant(link.llexitcase,
                                        lltype.typeOf(link.llexitcase)),
                               TLabel(link))
-                self.make_exception_link(link)
+                self.make_exception_link(link, False)
                 self.emitline(Label(link))
             else:
                 # no link captures all exceptions, so we have to put a reraise
@@ -216,29 +245,26 @@
             if linkfalse.llexitcase == True:
                 linkfalse, linktrue = linktrue, linkfalse
             opname = 'goto_if_not'
-            livebefore = False
             if isinstance(block.exitswitch, tuple):
                 # special case produced by jtransform.optimize_goto_if_not()
                 opname = 'goto_if_not_' + block.exitswitch[0]
                 opargs = block.exitswitch[1:]
                 if opargs[-1] == '-live-before':
-                    livebefore = True
                     opargs = opargs[:-1]
             else:
                 assert block.exitswitch.concretetype == lltype.Bool
                 opargs = [block.exitswitch]
             #
             lst = self.flatten_list(opargs) + [TLabel(linkfalse)]
-            if livebefore:
-                self.emitline('-live-')
+            self.emitline('-live-')
             self.emitline(opname, *lst)
-            if not livebefore:
-                self.emitline('-live-', TLabel(linkfalse))
+            #if not livebefore:
+            #    self.emitline('-live-', TLabel(linkfalse))
             # true path:
-            self.make_link(linktrue)
+            self.make_link(linktrue, handling_ovf)
             # false path:
             self.emitline(Label(linkfalse))
-            self.make_link(linkfalse)
+            self.make_link(linkfalse, handling_ovf)
         #
         else:
             # A switch.
@@ -261,7 +287,7 @@
                                     switchdict)
             # emit the default path
             if block.exits[-1].exitcase == 'default':
-                self.make_link(block.exits[-1])
+                self.make_link(block.exits[-1], handling_ovf)
             else:
                 self.emitline("unreachable")
                 self.emitline("---")
@@ -275,7 +301,7 @@
                 # if the switched value doesn't match any case.
                 self.emitline(Label(switch))
                 self.emitline('-live-')
-                self.make_link(switch)
+                self.make_link(switch, handling_ovf)
 
     def insert_renamings(self, link):
         renamings = {}
@@ -323,6 +349,9 @@
     def emitline(self, *line):
         self.ssarepr.insns.append(line)
 
+    def popline(self):
+        return self.ssarepr.insns.pop()
+
     def flatten_list(self, arglist):
         args = []
         for v in arglist:
diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -8,7 +8,8 @@
 from rpython.jit.metainterp.history import getkind
 from rpython.jit.metainterp.typesystem import deref, arrayItem
 from rpython.jit.metainterp.blackhole import BlackholeInterpreter
-from rpython.flowspace.model import SpaceOperation, Variable, Constant
+from rpython.flowspace.model import SpaceOperation, Variable, Constant,\
+     c_last_exception
 from rpython.rlib import objectmodel
 from rpython.rlib.jit import _we_are_jitted
 from rpython.rlib.rgc import lltype_is_gc
@@ -211,8 +212,8 @@
                 # ok! optimize this case
                 block.operations.remove(op)
                 block.exitswitch = (op.opname,) + tuple(op.args)
-                if op.opname in ('ptr_iszero', 'ptr_nonzero'):
-                    block.exitswitch += ('-live-before',)
+                #if op.opname in ('ptr_iszero', 'ptr_nonzero'):
+                block.exitswitch += ('-live-before',)
                 # if the variable escape to the next block along a link,
                 # replace it with a constant, because we know its value
                 for link in block.exits:
@@ -333,13 +334,13 @@
     def rewrite_op_int_add_ovf(self, op):
         op0 = self._rewrite_symmetric(op)
         op1 = SpaceOperation('-live-', [], None)
-        return [op0, op1]
+        return [op1, op0]
 
     rewrite_op_int_mul_ovf = rewrite_op_int_add_ovf
 
     def rewrite_op_int_sub_ovf(self, op):
         op1 = SpaceOperation('-live-', [], None)
-        return [op, op1]
+        return [op1, op]
 
     def _noop_rewrite(self, op):
         return op
diff --git a/rpython/jit/codewriter/test/test_codewriter.py b/rpython/jit/codewriter/test/test_codewriter.py
--- a/rpython/jit/codewriter/test/test_codewriter.py
+++ b/rpython/jit/codewriter/test/test_codewriter.py
@@ -76,11 +76,11 @@
     assert jitcode.num_regs_i() == 2
     assert jitcode.num_regs_r() == 0
     assert jitcode.num_regs_f() == 0
-    assert jitcode._live_vars(5) == '%i0 %i1'
+    assert jitcode._live_vars(0) == '%i0 %i1'
     #
     from rpython.jit.codewriter.jitcode import MissingLiveness
     for i in range(len(jitcode.code)+1):
-        if i != 5:
+        if i != 0:
             py.test.raises(MissingLiveness, jitcode._live_vars, i)
 
 def test_call():
diff --git a/rpython/jit/codewriter/test/test_flatten.py b/rpython/jit/codewriter/test/test_flatten.py
--- a/rpython/jit/codewriter/test/test_flatten.py
+++ b/rpython/jit/codewriter/test/test_flatten.py
@@ -140,6 +140,7 @@
 
     def encoding_test(self, func, args, expected,
                       transform=False, liveness=False, cc=None, jd=None):
+        
         graphs = self.make_graphs(func, args)
         #graphs[0].show()
         if transform:
@@ -147,7 +148,8 @@
             cc = cc or FakeCallControl()
             transform_graph(graphs[0], FakeCPU(self.rtyper), cc, jd)
         ssarepr = flatten_graph(graphs[0], fake_regallocs(),
-                                _include_all_exc_links=not transform)
+                                _include_all_exc_links=not transform,
+                                cpu=FakeCPU(self.rtyper))
         if liveness:
             from rpython.jit.codewriter.liveness import compute_liveness
             compute_liveness(ssarepr)
@@ -169,8 +171,8 @@
             return n + 1
         self.encoding_test(f, [10], """
             int_gt %i0, $0 -> %i1
+            -live-
             goto_if_not %i1, L1
-            -live- L1
             int_copy %i0 -> %i2
             int_sub %i2, $3 -> %i3
             int_copy %i3 -> %i4
@@ -194,8 +196,8 @@
             int_copy %i1 -> %i3
             L1:
             int_gt %i2, $0 -> %i4
+            -live-
             goto_if_not %i4, L2
-            -live- L2
             int_copy %i2 -> %i5
             int_copy %i3 -> %i6
             int_add %i6, %i5 -> %i7
@@ -218,8 +220,8 @@
             int_copy %i0 -> %i2
             int_copy %i1 -> %i3
             L1:
+            -live-
             goto_if_not_int_gt %i2, $0, L2
-            -live- L2
             int_copy %i2 -> %i4
             int_copy %i3 -> %i5
             int_add %i5, %i4 -> %i6
@@ -457,8 +459,8 @@
         # note that 'goto_if_not_int_is_true' is not the same thing
         # as just 'goto_if_not', because the last one expects a boolean
         self.encoding_test(f, [7], """
+            -live-
             goto_if_not_int_is_true %i0, L1
-            -live- L1
             int_return $False
             ---
             L1:
@@ -523,8 +525,8 @@
             else:
                 return m2
         self.encoding_test(f, [4, 5, 6], """
+            -live- %i0, %i1, %i2
             goto_if_not_int_is_true %i0, L1
-            -live- %i1, %i2, L1
             int_return %i1
             ---
             L1:
@@ -538,15 +540,59 @@
             except OverflowError:
                 return 42
         self.encoding_test(f, [7, 2], """
-            int_add_ovf %i0, %i1 -> %i2
-            -live- %i2
-            catch_exception L1
+            -live- %i0, %i1
+            int_add_jump_if_ovf L1, %i0, %i1 -> %i2
             int_return %i2
             ---
             L1:
             int_return $42
         """, transform=True, liveness=True)
 
+    def test_multiple_int_add_ovf(self):
+        def f(i, j):
+            try:
+                ovfcheck(j + i)
+                return ovfcheck(i + j)
+            except OverflowError:
+                return 42
+        self.encoding_test(f, [7, 2], """
+            -live- %i0, %i1
+            int_add_jump_if_ovf L1, %i1, %i0 -> %i2
+            int_copy %i1 -> %i3
+            int_copy %i0 -> %i4
+            -live- %i3, %i4
+            int_add_jump_if_ovf L2, %i4, %i3 -> %i5
+            int_return %i5
+            ---
+            L2:
+            int_return $42
+            ---
+            L1:
+            int_return $42
+        """, transform=True, liveness=True)
+
+    def test_ovfcheck_no_catch(self):
+        def f(i, j):
+            return ovfcheck(i + j)
+        err = py.test.raises(Exception, "self.encoding_test(f, [7, 2], '',"
+                             "transform=True, liveness=True)")
+        assert "ovfcheck()" in str(err)
+
+    def test_ovfcheck_reraise(self):
+        def f(i, j):
+            try:
+                ovfcheck(j + i)
+            except OverflowError:
+                raise
+        self.encoding_test(f, [7, 2], """
+            -live- %i0, %i1
+            int_add_jump_if_ovf L1, %i1, %i0 -> %i2
+            void_return
+            ---
+            L1:
+            raise $<* struct object>
+        """, transform=True, liveness=True)
+
     def test_residual_call_raising(self):
         @dont_look_inside
         def g(i, j):
diff --git a/rpython/jit/codewriter/test/test_jtransform.py b/rpython/jit/codewriter/test/test_jtransform.py
--- a/rpython/jit/codewriter/test/test_jtransform.py
+++ b/rpython/jit/codewriter/test/test_jtransform.py
@@ -15,7 +15,7 @@
         for prod in result:
             yield tuple(prod)
 
-from rpython.flowspace.model import FunctionGraph, Block, Link
+from rpython.flowspace.model import FunctionGraph, Block, Link, c_last_exception
 from rpython.flowspace.model import SpaceOperation, Variable, Constant
 from rpython.rtyper.lltypesystem import lltype, llmemory, rstr, rffi
 from rpython.rtyper import rclass
@@ -187,7 +187,7 @@
     res = Transformer().optimize_goto_if_not(block)
     assert res == True
     assert block.operations == [sp1, sp2]
-    assert block.exitswitch == ('int_gt', v1, v2)
+    assert block.exitswitch == ('int_gt', v1, v2, '-live-before')
     assert block.exits == exits
 
 def test_optimize_goto_if_not__incoming():
@@ -211,7 +211,7 @@
     res = Transformer().optimize_goto_if_not(block)
     assert res == True
     assert block.operations == []
-    assert block.exitswitch == ('int_gt', v1, v2)
+    assert block.exitswitch == ('int_gt', v1, v2, '-live-before')
     assert block.exits == exits
     assert exits[1].args == [const(True)]
 
@@ -235,7 +235,7 @@
         res = Transformer().optimize_goto_if_not(block)
         assert res == True
         assert block.operations == []
-        assert block.exitswitch == (opname, v1, v2)
+        assert block.exitswitch == (opname, v1, v2, '-live-before')
         assert block.exits == exits
 
 def test_optimize_goto_if_not__ptr_iszero():
@@ -287,7 +287,7 @@
         for v2 in [varoftype(lltype.Signed), const(43)]:
             op = SpaceOperation('int_add_nonneg_ovf', [v1, v2], v3)
             oplist = Transformer(FakeCPU()).rewrite_operation(op)
-            op0, op1 = oplist
+            op1, op0 = oplist
             assert op0.opname == 'int_add_ovf'
             if isinstance(v1, Constant) and isinstance(v2, Variable):
                 assert op0.args == [v2, v1]
diff --git a/rpython/jit/codewriter/test/test_regalloc.py b/rpython/jit/codewriter/test/test_regalloc.py
--- a/rpython/jit/codewriter/test/test_regalloc.py
+++ b/rpython/jit/codewriter/test/test_regalloc.py
@@ -63,8 +63,8 @@
         self.check_assembler(graph, """
             L1:
             int_gt %i0, $0 -> %i2
+            -live-
             goto_if_not %i2, L2
-            -live- L2
             int_add %i1, %i0 -> %i1
             int_sub %i0, $1 -> %i0
             goto L1
@@ -82,8 +82,8 @@
         self.check_assembler(graph, """
             L1:
             int_gt %i0, $0 -> %i2
+            -live-
             goto_if_not %i2, L2
-            -live- L2
             int_push %i1
             int_copy %i0 -> %i1
             int_pop -> %i0
@@ -102,8 +102,8 @@
         self.check_assembler(graph, """
             L1:
             int_gt %i0, $0 -> %i0
+            -live-
             goto_if_not %i0, L2
-            -live- L2
             int_copy %i1 -> %i0
             int_copy $2 -> %i1
             goto L1
@@ -121,8 +121,8 @@
         self.check_assembler(graph, """
             L1:
             int_gt %i0, $0 -> %i3
+            -live-
             goto_if_not %i3, L2
-            -live- L2
             int_push %i1
             int_copy %i2 -> %i1
             int_copy %i0 -> %i2
@@ -142,8 +142,8 @@
         self.check_assembler(graph, """
             L1:
             int_gt %i0, $0 -> %i3
+            -live-
             goto_if_not %i3, L2
-            -live- L2
             int_copy %i2 -> %i1
             goto L1
             ---
@@ -236,8 +236,8 @@
         self.check_assembler(graph, """
             int_lshift %i0, %i1 -> %i2
             int_rshift %i2, %i1 -> %i1
+            -live-
             goto_if_not_int_ne %i1, %i0, L1
-            -live- L1
             raise $<* struct object>
             ---
             L1:
diff --git a/rpython/jit/metainterp/blackhole.py b/rpython/jit/metainterp/blackhole.py
--- a/rpython/jit/metainterp/blackhole.py
+++ b/rpython/jit/metainterp/blackhole.py
@@ -212,6 +212,20 @@
                 assert lltype.typeOf(result) is longlong.FLOATSTORAGE
                 self.registers_f[ord(code[position])] = result
                 position += 1
+            elif resulttype == "iL":
+                result, new_position = result
+                if new_position != -1:
+                    position = new_position
+                    next_argcode = next_argcode + 2
+                else:
+                    assert argcodes[next_argcode] == '>'
+                    assert argcodes[next_argcode + 1] == 'i'
+                    next_argcode = next_argcode + 2
+                    if lltype.typeOf(result) is lltype.Bool:
+                        result = int(result)
+                    assert lltype.typeOf(result) is lltype.Signed
+                    self.registers_i[ord(code[position])] = result
+                    position += 1
             elif resulttype == 'L':
                 assert result >= 0
                 position = result
@@ -394,17 +408,26 @@
     def bhimpl_int_mul(a, b):
         return intmask(a * b)
 
-    @arguments("i", "i", returns="i")
-    def bhimpl_int_add_ovf(a, b):
-        return ovfcheck(a + b)
+    @arguments("L", "i", "i", returns="iL")
+    def bhimpl_int_add_jump_if_ovf(label, a, b):
+        try:
+            return ovfcheck(a + b), -1
+        except OverflowError:
+            return 0, label
 
-    @arguments("i", "i", returns="i")
-    def bhimpl_int_sub_ovf(a, b):
-        return ovfcheck(a - b)
+    @arguments("L", "i", "i", returns="iL")
+    def bhimpl_int_sub_jump_if_ovf(label, a, b):
+        try:
+            return ovfcheck(a - b), -1
+        except OverflowError:
+            return 0, label
 
-    @arguments("i", "i", returns="i")
-    def bhimpl_int_mul_ovf(a, b):
-        return ovfcheck(a * b)
+    @arguments("L", "i", "i", returns="iL")
+    def bhimpl_int_mul_jump_if_ovf(label, a, b):
+        try:
+            return ovfcheck(a * b), -1
+        except OverflowError:
+            return 0, label
 
     @arguments("i", "i", returns="i")
     def bhimpl_int_floordiv(a, b):
@@ -1465,57 +1488,9 @@
             assert kind == 'v'
         return lltype.nullptr(rclass.OBJECTPTR.TO)
 
-    def _prepare_resume_from_failure(self, opnum, deadframe):
-        from rpython.jit.metainterp.resoperation import rop
-        #
-        if opnum == rop.GUARD_FUTURE_CONDITION:
-            pass
-        elif opnum == rop.GUARD_TRUE:
-            # Produced directly by some goto_if_not_xxx() opcode that did not
-            # jump, but which must now jump.  The pc is just after the opcode.
-            self.position = self.jitcode.follow_jump(self.position)
-        #
-        elif opnum == rop.GUARD_FALSE:
-            # Produced directly by some goto_if_not_xxx() opcode that jumped,
-            # but which must no longer jump.  The pc is just after the opcode.
-            pass
-        #
-        elif opnum == rop.GUARD_VALUE or opnum == rop.GUARD_CLASS:
-            # Produced by guard_class(), xxx_guard_value(), or a few other
-            # opcodes like switch().  The pc is at the start of the opcode
-            # (so it will be redone).
-            pass
-        #
-        elif (opnum == rop.GUARD_NONNULL or
-              opnum == rop.GUARD_ISNULL or
-              opnum == rop.GUARD_NONNULL_CLASS):
-            # Produced by goto_if_not_ptr_{non,is}zero().  The pc is at the
-            # start of the opcode (so it will be redone); this is needed
-            # because of GUARD_NONNULL_CLASS.
-            pass
-        #
-        elif (opnum == rop.GUARD_NO_EXCEPTION or
-              opnum == rop.GUARD_EXCEPTION or
-              opnum == rop.GUARD_NOT_FORCED):
-            return lltype.cast_opaque_ptr(rclass.OBJECTPTR,
-                                          self.cpu.grab_exc_value(deadframe))
-        #
-        elif opnum == rop.GUARD_NO_OVERFLOW:
-            # Produced by int_xxx_ovf().  The pc is just after the opcode.
-            # We get here because it did not used to overflow, but now it does.
-            return get_llexception(self.cpu, OverflowError())
-        #
-        elif opnum == rop.GUARD_OVERFLOW:
-            # Produced by int_xxx_ovf().  The pc is just after the opcode.
-            # We get here because it used to overflow, but now it no longer
-            # does.
-            pass
-        elif opnum == rop.GUARD_NOT_INVALIDATED:
-            pass
-        else:
-            from rpython.jit.metainterp.resoperation import opname
-            raise NotImplementedError(opname[opnum])
-        return lltype.nullptr(rclass.OBJECTPTR.TO)
+    def _prepare_resume_from_failure(self, deadframe):
+        return lltype.cast_opaque_ptr(rclass.OBJECTPTR,
+                                        self.cpu.grab_exc_value(deadframe))
 
     # connect the return of values from the called frame to the
     # 'xxx_call_yyy' instructions from the caller frame
@@ -1641,8 +1616,7 @@
         deadframe,
         all_virtuals)
 
-    current_exc = blackholeinterp._prepare_resume_from_failure(
-        resumedescr.guard_opnum, deadframe)
+    current_exc = blackholeinterp._prepare_resume_from_failure(deadframe)
 
     _run_forever(blackholeinterp, current_exc)
 resume_in_blackhole._dont_inline_ = True
diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py
--- a/rpython/jit/metainterp/compile.py
+++ b/rpython/jit/metainterp/compile.py
@@ -767,12 +767,15 @@
             # fetch the actual value of the guard_value, possibly turning
             # it to an integer
             if typetag == self.TY_INT:
-                intval = metainterp_sd.cpu.get_int_value(deadframe, index)
+                intval = metainterp_sd.cpu.get_value_direct(deadframe, 'i',
+                                                            index)
             elif typetag == self.TY_REF:
-                refval = metainterp_sd.cpu.get_ref_value(deadframe, index)
+                refval = metainterp_sd.cpu.get_value_direct(deadframe, 'r',
+                                                            index)
                 intval = lltype.cast_ptr_to_int(refval)
             elif typetag == self.TY_FLOAT:
-                floatval = metainterp_sd.cpu.get_float_value(deadframe, index)
+                floatval = metainterp_sd.cpu.get_value_direct(deadframe, 'f',
+                                                              index)
                 intval = longlong.gethash_fast(floatval)
             else:
                 assert 0, typetag
@@ -788,11 +791,6 @@
         increment = jitdriver_sd.warmstate.increment_trace_eagerness
         return jitcounter.tick(hash, increment)
 
-    def get_index_of_guard_value(self):
-        if (self.status & self.ST_TYPE_MASK) == 0:
-            return -1
-        return intmask(self.status >> self.ST_SHIFT)
-
     def start_compiling(self):
         # start tracing and compiling from this guard.
         self.status |= self.ST_BUSY_FLAG
@@ -819,62 +817,24 @@
                                new_loop.original_jitcell_token,
                                metainterp.box_names_memo)
 
-    def make_a_counter_per_value(self, guard_value_op):
+    def make_a_counter_per_value(self, guard_value_op, index):
         assert guard_value_op.getopnum() == rop.GUARD_VALUE
         box = guard_value_op.getarg(0)
-        try:
-            i = guard_value_op.getfailargs().index(box)
-        except ValueError:
-            return     # xxx probably very rare
+        if box.type == history.INT:
+            ty = self.TY_INT
+        elif box.type == history.REF:
+            ty = self.TY_REF
+        elif box.type == history.FLOAT:
+            ty = self.TY_FLOAT
         else:
-            if box.type == history.INT:
-                ty = self.TY_INT
-            elif box.type == history.REF:
-                ty = self.TY_REF
-            elif box.type == history.FLOAT:
-                ty = self.TY_FLOAT
-            else:
-                assert 0, box.type
-            self.status = ty | (r_uint(i) << self.ST_SHIFT)
+            assert 0, box.type
+        self.status = ty | (r_uint(index) << self.ST_SHIFT)
 
-class ResumeGuardNonnullDescr(ResumeGuardDescr):
-    guard_opnum = rop.GUARD_NONNULL
-
-class ResumeGuardIsnullDescr(ResumeGuardDescr):
-    guard_opnum = rop.GUARD_ISNULL
-
-class ResumeGuardClassDescr(ResumeGuardDescr):
-    guard_opnum = rop.GUARD_CLASS
-
-class ResumeGuardTrueDescr(ResumeGuardDescr):
-    guard_opnum = rop.GUARD_TRUE
-
-class ResumeGuardFalseDescr(ResumeGuardDescr):
-    guard_opnum = rop.GUARD_FALSE
-
-class ResumeGuardNonnullClassDescr(ResumeGuardDescr):
-    guard_opnum = rop.GUARD_NONNULL_CLASS
-
-class ResumeGuardExceptionDescr(ResumeGuardDescr):
-    guard_opnum = rop.GUARD_EXCEPTION
-
-class ResumeGuardNoExceptionDescr(ResumeGuardDescr):
-    guard_opnum = rop.GUARD_NO_EXCEPTION
-
-class ResumeGuardOverflowDescr(ResumeGuardDescr):
-    guard_opnum = rop.GUARD_OVERFLOW
-
-class ResumeGuardNoOverflowDescr(ResumeGuardDescr):
-    guard_opnum = rop.GUARD_NO_OVERFLOW
-
-class ResumeGuardValueDescr(ResumeGuardDescr):
-    guard_opnum = rop.GUARD_VALUE
-
-class ResumeGuardNotInvalidated(ResumeGuardDescr):
-    guard_opnum = rop.GUARD_NOT_INVALIDATED
+class ResumeGuardExcDescr(ResumeGuardDescr):
+    pass
 
 class ResumeAtPositionDescr(ResumeGuardDescr):
-    guard_opnum = rop.GUARD_FUTURE_CONDITION
+    pass
 
 class AllVirtuals:
     llopaque = True
@@ -895,8 +855,6 @@
 
 
 class ResumeGuardForcedDescr(ResumeGuardDescr):
-    guard_opnum = rop.GUARD_NOT_FORCED
-
     def _init(self, metainterp_sd, jitdriver_sd):
         # to please the annotator
         self.metainterp_sd = metainterp_sd
@@ -959,37 +917,13 @@
     if opnum == rop.GUARD_NOT_FORCED or opnum == rop.GUARD_NOT_FORCED_2:
         resumedescr = ResumeGuardForcedDescr()
         resumedescr._init(optimizer.metainterp_sd, optimizer.jitdriver_sd)
-    elif opnum == rop.GUARD_NOT_INVALIDATED:
-        resumedescr = ResumeGuardNotInvalidated()
-    elif opnum == rop.GUARD_FUTURE_CONDITION:
-        resumedescr = ResumeAtPositionDescr()
-    elif opnum == rop.GUARD_VALUE:
-        resumedescr = ResumeGuardValueDescr()
-    elif opnum == rop.GUARD_NONNULL:
-        resumedescr = ResumeGuardNonnullDescr()
-    elif opnum == rop.GUARD_ISNULL:
-        resumedescr = ResumeGuardIsnullDescr()
-    elif opnum == rop.GUARD_NONNULL_CLASS:
-        resumedescr = ResumeGuardNonnullClassDescr()
-    elif opnum == rop.GUARD_CLASS:
-        resumedescr = ResumeGuardClassDescr()
-    elif opnum == rop.GUARD_TRUE:
-        resumedescr = ResumeGuardTrueDescr()
-    elif opnum == rop.GUARD_FALSE:
-        resumedescr = ResumeGuardFalseDescr()
-    elif opnum == rop.GUARD_EXCEPTION:
-        resumedescr = ResumeGuardExceptionDescr()
-    elif opnum == rop.GUARD_NO_EXCEPTION:
-        resumedescr = ResumeGuardNoExceptionDescr()
-    elif opnum == rop.GUARD_OVERFLOW:
-        resumedescr = ResumeGuardOverflowDescr()
-    elif opnum == rop.GUARD_NO_OVERFLOW:
-        resumedescr = ResumeGuardNoOverflowDescr()
     elif opnum in (rop.GUARD_IS_OBJECT, rop.GUARD_SUBCLASS, rop.GUARD_GC_TYPE):
         # note - this only happens in tests
         resumedescr = ResumeAtPositionDescr()
+    elif opnum in (rop.GUARD_EXCEPTION, rop.GUARD_NO_EXCEPTION):
+        resumedescr = ResumeGuardExcDescr()
     else:
-        assert False
+        resumedescr = ResumeGuardDescr()
     return resumedescr
 
 class ResumeFromInterpDescr(ResumeDescr):
diff --git a/rpython/jit/metainterp/executor.py b/rpython/jit/metainterp/executor.py
--- a/rpython/jit/metainterp/executor.py
+++ b/rpython/jit/metainterp/executor.py
@@ -253,7 +253,7 @@
         z = ovfcheck(a + b)
     except OverflowError:
         assert metainterp is not None
-        metainterp.execute_raised(OverflowError(), constant=True)
+        metainterp.ovf_flag = True
         z = 0
     return z
 
@@ -264,7 +264,7 @@
         z = ovfcheck(a - b)
     except OverflowError:
         assert metainterp is not None
-        metainterp.execute_raised(OverflowError(), constant=True)
+        metainterp.ovf_flag = True
         z = 0
     return z
 
@@ -275,7 +275,7 @@
         z = ovfcheck(a * b)
     except OverflowError:
         assert metainterp is not None
-        metainterp.execute_raised(OverflowError(), constant=True)
+        metainterp.ovf_flag = True
         z = 0
     return z
 
diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py
--- a/rpython/jit/metainterp/history.py
+++ b/rpython/jit/metainterp/history.py
@@ -157,6 +157,9 @@
     def __init__(self, identifier=None):
         self.identifier = identifier      # for testing
 
+    def make_a_counter_per_value(self, op, index):
+        pass # for testing
+
 
 @specialize.argtype(0)
 def newconst(value):
@@ -540,6 +543,9 @@
     def check_consistency_of_branch(operations, seen, check_descr=True):
         "NOT_RPYTHON"
         for num, op in enumerate(operations):
+            if op.is_ovf():
+                assert operations[num + 1].getopnum() in (rop.GUARD_NO_OVERFLOW,
+                                                          rop.GUARD_OVERFLOW)
             for i in range(op.numargs()):
                 box = op.getarg(i)
                 if not isinstance(box, Const):
@@ -750,7 +756,6 @@
         return tokens
 
     def check_history(self, expected=None, **check):
-        return
         insns = {}
         for op in self.operations:
             opname = op.getopname()
diff --git a/rpython/jit/metainterp/jitprof.py b/rpython/jit/metainterp/jitprof.py
--- a/rpython/jit/metainterp/jitprof.py
+++ b/rpython/jit/metainterp/jitprof.py
@@ -143,6 +143,7 @@
         self._print_intline("guards", cnt[Counters.GUARDS])
         self._print_intline("opt ops", cnt[Counters.OPT_OPS])
         self._print_intline("opt guards", cnt[Counters.OPT_GUARDS])
+        self._print_intline("opt guards shared", cnt[Counters.OPT_GUARDS_SHARED])
         self._print_intline("forcings", cnt[Counters.OPT_FORCINGS])
         self._print_intline("abort: trace too long",
                             cnt[Counters.ABORT_TOO_LONG])
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
@@ -11,7 +11,7 @@
 from rpython.jit.metainterp.optimizeopt.shortpreamble import PreambleOp
 from rpython.jit.metainterp.optimize import InvalidLoop
 from rpython.jit.metainterp.resoperation import rop, ResOperation, OpHelpers,\
-     AbstractResOp
+     AbstractResOp, GuardResOp
 from rpython.rlib.objectmodel import we_are_translated
 from rpython.jit.metainterp.optimizeopt import info
         
@@ -288,7 +288,7 @@
             cf = submap[index] = ArrayCachedField(index)
         return cf
 
-    def emit_operation(self, op):
+    def emit_operation(self, op):        
         self.emitting_operation(op)
         self.emit_postponed_op()
         if (op.is_comparison() or op.is_call_may_force()
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
@@ -104,6 +104,11 @@
         self.last_guard_pos = -1
 
     def mark_last_guard(self, optimizer):
+        if (optimizer.getlastop() is None or
+            not optimizer.getlastop().is_guard()):
+            # there can be a really emitted operation that's not a guard
+            # e.g. a setfield, ignore those
+            return
         self.last_guard_pos = len(optimizer._newoperations) - 1
         assert self.get_last_guard(optimizer).is_guard()
 
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
@@ -1,7 +1,6 @@
 from rpython.jit.metainterp import jitprof, resume, compile
 from rpython.jit.metainterp.executor import execute_nonspec_const
-from rpython.jit.metainterp.logger import LogOperations
-from rpython.jit.metainterp.history import Const, ConstInt, REF, ConstPtr
+from rpython.jit.metainterp.history import Const, ConstInt, ConstPtr
 from rpython.jit.metainterp.optimizeopt.intutils import IntBound,\
      ConstIntBound, MININT, MAXINT, IntUnbounded
 from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method
@@ -10,6 +9,7 @@
 from rpython.jit.metainterp.optimizeopt import info
 from rpython.jit.metainterp.typesystem import llhelper
 from rpython.rlib.objectmodel import specialize, we_are_translated
+from rpython.rlib.debug import debug_print
 
 
 
@@ -260,6 +260,8 @@
         self.optearlyforce = None
         self.optunroll = None
 
+        self._last_guard_op = None
+
         self.set_optimizations(optimizations)
         self.setup()
 
@@ -526,6 +528,7 @@
         if extra_jump:
             self.first_optimization.propagate_forward(ops[-1])
         self.resumedata_memo.update_counters(self.metainterp_sd.profiler)
+        
         return (BasicLoopInfo(newargs, self.quasi_immutable_deps),
                 self._newoperations)
 
@@ -566,6 +569,7 @@
             op.setarg(i, arg)
         self.metainterp_sd.profiler.count(jitprof.Counters.OPT_OPS)
         if op.is_guard():
+            assert isinstance(op, GuardResOp)
             self.metainterp_sd.profiler.count(jitprof.Counters.OPT_GUARDS)
             pendingfields = self.pendingfields
             self.pendingfields = None
@@ -574,20 +578,85 @@
                 del self.replaces_guard[orig_op]
                 return
             else:
-                guard_op = self.replace_op_with(op, op.getopnum())
-                op = self.store_final_boxes_in_guard(guard_op, pendingfields)
-                # for unrolling
-                for farg in op.getfailargs():
-                    if farg:
-                        self.force_box(farg)
+                op = self.emit_guard_operation(op, pendingfields)
         elif op.can_raise():
             self.exception_might_have_happened = True
+        if ((op.has_no_side_effect() or op.is_guard() or op.is_jit_debug() or
+             op.is_ovf()) and not self.is_call_pure_pure_canraise(op)):
+            pass
+        else:
+            self._last_guard_op = None
         self._really_emitted_operation = op
         self._newoperations.append(op)
 
+    def emit_guard_operation(self, op, pendingfields):
+        guard_op = self.replace_op_with(op, op.getopnum())
+        opnum = guard_op.getopnum()
+        if (self._last_guard_op and guard_op.getdescr() is None):
+            self.metainterp_sd.profiler.count_ops(opnum,
+                                            jitprof.Counters.OPT_GUARDS_SHARED)
+            op = self._copy_resume_data_from(guard_op,
+                                             self._last_guard_op)
+        else:
+            op = self.store_final_boxes_in_guard(guard_op, pendingfields)
+            self._last_guard_op = op
+            # for unrolling
+            for farg in op.getfailargs():
+                if farg:
+                    self.force_box(farg)
+        if op.getopnum() == rop.GUARD_EXCEPTION:
+            self._last_guard_op = None
+        return op
+
+    def potentially_change_ovf_op_to_no_ovf(self, op):
+        # if last emitted operations was int_xxx_ovf and we are not emitting
+        # a guard_no_overflow change to int_add
+        if op.getopnum() != rop.GUARD_NO_OVERFLOW:
+            return
+        if not self._newoperations:
+            # got optimized otherwise
+            return
+        op = self._newoperations[-1]
+        if not op.is_ovf():
+            return
+        newop = self.replace_op_with_no_ovf(op)
+        self._newoperations[-1] = newop
+
+    def replace_op_with_no_ovf(self, op):
+        if op.getopnum() == rop.INT_MUL_OVF:
+            return self.replace_op_with(op, rop.INT_MUL)
+        elif op.getopnum() == rop.INT_ADD_OVF:
+            return self.replace_op_with(op, rop.INT_ADD)
+        elif op.getopnum() == rop.INT_SUB_OVF:
+            return self.replace_op_with(op, rop.INT_SUB)
+        else:
+            assert False
+
+
+    def _copy_resume_data_from(self, guard_op, last_guard_op):
+        if guard_op.getopnum() in (rop.GUARD_NO_EXCEPTION, rop.GUARD_EXCEPTION):
+            assert last_guard_op.getopnum() == rop.GUARD_NOT_FORCED
+        descr = compile.invent_fail_descr_for_op(guard_op.getopnum(), self)
+        descr.copy_all_attributes_from(last_guard_op.getdescr())
+        guard_op.setdescr(descr)
+        descr.store_final_boxes(guard_op, last_guard_op.getfailargs(),
+                                self.metainterp_sd)
+        assert isinstance(guard_op, GuardResOp)
+        if guard_op.getopnum() == rop.GUARD_VALUE:
+            guard_op = self._maybe_replace_guard_value(guard_op, descr)
+        return guard_op
+
     def getlastop(self):
         return self._really_emitted_operation
 
+    def is_call_pure_pure_canraise(self, op):
+        if not op.is_call_pure():
+            return False
+        effectinfo = op.getdescr().get_extra_info()
+        if effectinfo.check_can_raise(ignore_memoryerror=True):
+            return True
+        return False
+
     def replace_guard_op(self, old_op_pos, new_op):
         old_op = self._newoperations[old_op_pos]
         assert old_op.is_guard()
@@ -625,24 +694,26 @@
         descr.store_final_boxes(op, newboxes, self.metainterp_sd)
         #
         if op.getopnum() == rop.GUARD_VALUE:
-            if op.getarg(0).type == 'i':
-                b = self.getintbound(op.getarg(0))
-                if b.is_bool():
-                    # 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:
-                        opnum = rop.GUARD_FALSE
-                    elif constvalue == 1:
-                        opnum = rop.GUARD_TRUE
-                    else:
-                        raise AssertionError("uh?")
-                    newop = self.replace_op_with(op, opnum, [op.getarg(0)], descr)
-                    return newop
-            # a real GUARD_VALUE.  Make it use one counter per value.
-            descr.make_a_counter_per_value(op)
+            op = self._maybe_replace_guard_value(op, descr)
+        return op
+
+    def _maybe_replace_guard_value(self, op, descr):
+        if op.getarg(0).type == 'i':
+            b = self.getintbound(op.getarg(0))
+            if b.is_bool():
+                # 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:
+                    opnum = rop.GUARD_FALSE
+                elif constvalue == 1:
+                    opnum = rop.GUARD_TRUE
+                else:
+                    raise AssertionError("uh?")
+                newop = self.replace_op_with(op, opnum, [op.getarg(0)], descr)
+                return newop
         return op
 
     def optimize_default(self, op):
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
@@ -401,7 +401,7 @@
                 r = self.optimizer.metainterp_sd.logger_ops.repr_of_resop(op)
                 raise InvalidLoop('A GUARD_VALUE (%s) was proven to '
                                   'always fail' % r)
-        descr = compile.ResumeGuardValueDescr()
+        descr = compile.ResumeGuardDescr()
         op = old_guard_op.copy_and_change(rop.GUARD_VALUE,
                          args = [old_guard_op.getarg(0), op.getarg(1)],
                          descr = descr)
@@ -411,7 +411,6 @@
         # not put in short preambles guard_xxx and guard_value
         # on the same box.
         self.optimizer.replace_guard(op, info)
-        descr.make_a_counter_per_value(op)
         # to be safe
         info.reset_last_guard_pos()
         return op
@@ -453,7 +452,7 @@
             if old_guard_op.getopnum() == rop.GUARD_NONNULL:
                 # it was a guard_nonnull, which we replace with a
                 # guard_nonnull_class.
-                descr = compile.ResumeGuardNonnullClassDescr()
+                descr = compile.ResumeGuardDescr()
                 op = old_guard_op.copy_and_change (rop.GUARD_NONNULL_CLASS,
                             args = [old_guard_op.getarg(0), op.getarg(1)],
                             descr=descr)
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -2022,6 +2022,7 @@
                        None)
 
     def test_merge_guard_class_guard_value(self):
+        py.test.skip("disabled")
         ops = """
         [p1, i0, i1, i2, p2]
         guard_class(p1, ConstClass(node_vtable)) [i0]
@@ -2055,6 +2056,7 @@
         self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS)
 
     def test_merge_guard_nonnull_guard_value(self):
+        py.test.skip("disabled")
         ops = """
         [p1, i0, i1, i2, p2]
         guard_nonnull(p1) [i0]
@@ -2072,6 +2074,7 @@
         self.check_expanded_fail_descr("i0", rop.GUARD_VALUE)
 
     def test_merge_guard_nonnull_guard_class_guard_value(self):
+        py.test.skip("disabled")        
         ops = """
         [p1, i0, i1, i2, p2]
         guard_nonnull(p1) [i0]
@@ -2502,7 +2505,6 @@
         if values is not None:
             fail_args = values
         fdescr = guard_op.getdescr()
-        assert fdescr.guard_opnum == guard_opnum
         reader = ResumeDataFakeReader(fdescr, fail_args,
                                       MyMetaInterp(self.cpu))
         boxes = reader.consume_boxes()
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -2967,6 +2967,7 @@
             assert "promote of a virtual" in exc.msg
 
     def test_merge_guard_class_guard_value(self):
+        py.test.skip("disabled")
         ops = """
         [p1, i0, i1, i2, p2]
         guard_class(p1, ConstClass(node_vtable)) [i0]
@@ -3012,6 +3013,7 @@
         #self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS)
 
     def test_merge_guard_nonnull_guard_value(self):
+        py.test.skip("disabled")
         ops = """
         [p1, i0, i1, i2, p2]
         guard_nonnull(p1) [i0]
@@ -3035,6 +3037,7 @@
         #self.check_expanded_fail_descr("i0", rop.GUARD_VALUE)
 
     def test_merge_guard_nonnull_guard_class_guard_value(self):
+        py.test.skip("disabled")
         ops = """
         [p1, i0, i1, i2, p2]
         guard_nonnull(p1) [i0]
diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -21,6 +21,7 @@
 from rpython.rlib.unroll import unrolling_iterable
 from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
 from rpython.rtyper import rclass
+from rpython.rlib.objectmodel import compute_unique_id
 
 
 
@@ -228,17 +229,23 @@
         ''' % (_opimpl, FASTPATHS_SAME_BOXES[_opimpl.split("_")[-1]], _opimpl.upper())
         ).compile()
 
-    for _opimpl in ['int_add_ovf', 'int_sub_ovf', 'int_mul_ovf']:
+    for (_opimpl, resop) in [
+            ('int_add_jump_if_ovf', 'INT_ADD_OVF'),
+            ('int_sub_jump_if_ovf', 'INT_SUB_OVF'),
+            ('int_mul_jump_if_ovf', 'INT_MUL_OVF')]:
         exec py.code.Source('''
-            @arguments("box", "box")
-            def opimpl_%s(self, b1, b2):
-                self.metainterp.clear_exception()
+            @arguments("label", "box", "box", "orgpc")
+            def opimpl_%s(self, lbl, b1, b2, orgpc):
+                self.metainterp.ovf_flag = False
                 resbox = self.execute(rop.%s, b1, b2)
-                self.make_result_of_lastop(resbox)  # same as execute_varargs()
                 if not isinstance(resbox, Const):
-                    self.metainterp.handle_possible_overflow_error()
+                    return self.handle_possible_overflow_error(lbl, orgpc,
+                                                               resbox)
+                elif self.metainterp.ovf_flag:
+                    self.pc = lbl
+                    return None # but don't emit GUARD_OVERFLOW
                 return resbox
-        ''' % (_opimpl, _opimpl.upper())).compile()
+        ''' % (_opimpl, resop)).compile()
 
     for _opimpl in ['int_is_true', 'int_is_zero', 'int_neg', 'int_invert',
                     'cast_float_to_int', 'cast_int_to_float',
@@ -329,37 +336,37 @@
     def opimpl_goto(self, target):
         self.pc = target
 
-    @arguments("box", "label")
-    def opimpl_goto_if_not(self, box, target):
+    @arguments("box", "label", "orgpc")
+    def opimpl_goto_if_not(self, box, target, orgpc):
         switchcase = box.getint()
         if switchcase:
             opnum = rop.GUARD_TRUE
         else:
             opnum = rop.GUARD_FALSE
-        self.metainterp.generate_guard(opnum, box)
+        self.metainterp.generate_guard(opnum, box, resumepc=orgpc)
         if not switchcase:
             self.pc = target
 
-    @arguments("box", "label")
-    def opimpl_goto_if_not_int_is_true(self, box, target):
+    @arguments("box", "label", "orgpc")
+    def opimpl_goto_if_not_int_is_true(self, box, target, orgpc):
         condbox = self.execute(rop.INT_IS_TRUE, box)
-        self.opimpl_goto_if_not(condbox, target)
+        self.opimpl_goto_if_not(condbox, target, orgpc)
 
-    @arguments("box", "label")
-    def opimpl_goto_if_not_int_is_zero(self, box, target):
+    @arguments("box", "label", "orgpc")
+    def opimpl_goto_if_not_int_is_zero(self, box, target, orgpc):
         condbox = self.execute(rop.INT_IS_ZERO, box)
-        self.opimpl_goto_if_not(condbox, target)
+        self.opimpl_goto_if_not(condbox, target, orgpc)
 
     for _opimpl in ['int_lt', 'int_le', 'int_eq', 'int_ne', 'int_gt', 'int_ge',
                     'ptr_eq', 'ptr_ne']:
         exec py.code.Source('''
-            @arguments("box", "box", "label")
-            def opimpl_goto_if_not_%s(self, b1, b2, target):
+            @arguments("box", "box", "label", "orgpc")
+            def opimpl_goto_if_not_%s(self, b1, b2, target, orgpc):
                 if b1 is b2:
                     condbox = %s
                 else:
                     condbox = self.execute(rop.%s, b1, b2)
-                self.opimpl_goto_if_not(condbox, target)
+                self.opimpl_goto_if_not(condbox, target, orgpc)
         ''' % (_opimpl, FASTPATHS_SAME_BOXES[_opimpl.split("_")[-1]], _opimpl.upper())
         ).compile()
 
@@ -418,7 +425,7 @@
                 assert box.getint() == 0
                 target = switchdict.dict[const1.getint()]
                 self.metainterp.generate_guard(rop.GUARD_FALSE, box,
-                                               resumepc=target)
+                                               resumepc=orgpc)
         else:
             # found one of the cases
             self.implement_guard_value(valuebox, orgpc)
@@ -1457,6 +1464,17 @@
     def setup_resume_at_op(self, pc):
         self.pc = pc
 
+    def handle_possible_overflow_error(self, label, orgpc, resbox):
+        if self.metainterp.ovf_flag:
+            self.metainterp.generate_guard(rop.GUARD_OVERFLOW, None,
+                                           resumepc=orgpc)
+            self.pc = label
+            return None
+        else:
+            self.metainterp.generate_guard(rop.GUARD_NO_OVERFLOW, None,
+                                           resumepc=orgpc)
+            return resbox
+
     def run_one_step(self):
         # Execute the frame forward.  This method contains a loop that leaves
         # whenever the 'opcode_implementations' (which is one of the 'opimpl_'
@@ -2022,7 +2040,7 @@
             moreargs = [box] + extraargs
         else:
             moreargs = list(extraargs)
-        if opnum == rop.GUARD_EXCEPTION or opnum == rop.GUARD_OVERFLOW:
+        if opnum == rop.GUARD_EXCEPTION:
             guard_op = self.history.record(opnum, moreargs,
                                            lltype.nullptr(llmemory.GCREF.TO))
         else:
@@ -2309,7 +2327,7 @@
         if isinstance(key, compile.ResumeAtPositionDescr):
             self.seen_loop_header_for_jdindex = self.jitdriver_sd.index
         try:
-            self.prepare_resume_from_failure(key.guard_opnum, deadframe)
+            self.prepare_resume_from_failure(deadframe, key)
             if self.resumekey_original_loop_token is None:   # very rare case
                 raise SwitchToBlackhole(Counters.ABORT_BRIDGE)
             self.interpret()
@@ -2452,22 +2470,9 @@
             else: assert 0
         self.jitdriver_sd.warmstate.execute_assembler(loop_token, *args)
 
-    def prepare_resume_from_failure(self, opnum, deadframe):
-        frame = self.framestack[-1]
-        if opnum == rop.GUARD_FUTURE_CONDITION:
-            pass
-        elif opnum == rop.GUARD_TRUE:     # a goto_if_not that jumps only now
-            frame.pc = frame.jitcode.follow_jump(frame.pc)
-        elif opnum == rop.GUARD_FALSE:     # a goto_if_not that stops jumping;
-            pass                  # or a switch that was in its "default" case
-        elif opnum == rop.GUARD_VALUE or opnum == rop.GUARD_CLASS:
-            pass        # the pc is already set to the *start* of the opcode
-        elif (opnum == rop.GUARD_NONNULL or
-              opnum == rop.GUARD_ISNULL or
-              opnum == rop.GUARD_NONNULL_CLASS):
-            pass        # the pc is already set to the *start* of the opcode
-        elif opnum == rop.GUARD_NO_EXCEPTION or opnum == rop.GUARD_EXCEPTION:
-            exception = self.cpu.grab_exc_value(deadframe)
+    def prepare_resume_from_failure(self, deadframe, resumedescr):
+        exception = self.cpu.grab_exc_value(deadframe)
+        if isinstance(resumedescr, compile.ResumeGuardExcDescr):
             if exception:
                 self.execute_ll_raised(lltype.cast_opaque_ptr(rclass.OBJECTPTR,
                                                               exception))
@@ -2477,20 +2482,8 @@
                 self.handle_possible_exception()
             except ChangeFrame:
                 pass
-        elif opnum == rop.GUARD_NOT_INVALIDATED:
-            pass # XXX we want to do something special in resume descr,
-                 # but not now
-        elif opnum == rop.GUARD_NO_OVERFLOW:   # an overflow now detected
-            self.execute_raised(OverflowError(), constant=True)
-            try:
-                self.finishframe_exception()
-            except ChangeFrame:
-                pass
-        elif opnum == rop.GUARD_OVERFLOW:      # no longer overflowing
-            self.clear_exception()
         else:
-            from rpython.jit.metainterp.resoperation import opname
-            raise NotImplementedError(opname[opnum])
+            assert not exception
 
     def get_procedure_token(self, greenkey, with_compiled_targets=False):
         JitCell = self.jitdriver_sd.warmstate.JitCell
@@ -2773,18 +2766,6 @@
         else:
             self.generate_guard(rop.GUARD_NO_EXCEPTION, None, [])
 
-    def handle_possible_overflow_error(self):
-        if self.last_exc_value:
-            op = self.generate_guard(rop.GUARD_OVERFLOW, None)
-            op.setref_base(lltype.cast_opaque_ptr(llmemory.GCREF,
-                                                  self.last_exc_value))
-            assert self.class_of_last_exc_is_const
-            self.last_exc_box = ConstPtr(
-                lltype.cast_opaque_ptr(llmemory.GCREF, self.last_exc_value))
-            self.finishframe_exception()
-        else:
-            self.generate_guard(rop.GUARD_NO_OVERFLOW, None)
-
     def assert_no_exception(self):
         assert not self.last_exc_value
 
@@ -3250,16 +3231,17 @@
                     print '-> %r' % (resultbox,)
                 assert argcodes[next_argcode] == '>'
                 result_argcode = argcodes[next_argcode + 1]
-                assert resultbox.type == {'i': history.INT,
-                                          'r': history.REF,
-                                          'f': history.FLOAT}[result_argcode]
+                if 'ovf' not in name:
+                    assert resultbox.type == {'i': history.INT,
+                                              'r': history.REF,
+                                              'f': history.FLOAT}[result_argcode]
         else:
             resultbox = unboundmethod(self, *args)
         #
         if resultbox is not None:
             self.make_result_of_lastop(resultbox)
         elif not we_are_translated():
-            assert self._result_argcode in 'v?'
+            assert self._result_argcode in 'v?' or 'ovf' in name
     #
     unboundmethod = getattr(MIFrame, 'opimpl_' + name).im_func
     argtypes = unrolling_iterable(unboundmethod.argtypes)
diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py
--- a/rpython/jit/metainterp/resoperation.py
+++ b/rpython/jit/metainterp/resoperation.py
@@ -236,6 +236,9 @@
         return (self.getopnum() == rop.GUARD_OVERFLOW or
                 self.getopnum() == rop.GUARD_NO_OVERFLOW)
 
+    def is_jit_debug(self):
+        return rop._JIT_DEBUG_FIRST <= self.getopnum() <= rop._JIT_DEBUG_LAST
+
     def is_always_pure(self):
         return rop._ALWAYS_PURE_FIRST <= self.getopnum() <= rop._ALWAYS_PURE_LAST
 
@@ -375,6 +378,7 @@
         newop.rd_frame_info_list = self.rd_frame_info_list
         return newop
 
+
 # ===========
 # type mixins
 # ===========
@@ -689,7 +693,7 @@
     'GUARD_NO_EXCEPTION/0d/n',   # may be called with an exception currently set
     'GUARD_EXCEPTION/1d/r',     # may be called with an exception currently set
     'GUARD_NO_OVERFLOW/0d/n',
-    'GUARD_OVERFLOW/0d/r',
+    'GUARD_OVERFLOW/0d/n',
     'GUARD_NOT_FORCED/0d/n',      # may be called with an exception currently set
     'GUARD_NOT_FORCED_2/0d/n',    # same as GUARD_NOT_FORCED, but for finish()
     'GUARD_NOT_INVALIDATED/0d/n',
@@ -806,10 +810,12 @@
     'UNICODESETITEM/3/n',
     'COND_CALL_GC_WB/1d/n',       # [objptr] (for the write barrier)
     'COND_CALL_GC_WB_ARRAY/2d/n', # [objptr, arrayindex] (write barr. for array)
+    '_JIT_DEBUG_FIRST',
     'DEBUG_MERGE_POINT/*/n',      # debugging only
     'ENTER_PORTAL_FRAME/2/n',     # debugging only
     'LEAVE_PORTAL_FRAME/1/n',     # debugging only
     'JIT_DEBUG/*/n',              # debugging only
+    '_JIT_DEBUG_LAST',
     'VIRTUAL_REF_FINISH/2/n',   # removed before it's passed to the backend
     'COPYSTRCONTENT/5/n',       # src, dst, srcstart, dststart, length
     'COPYUNICODECONTENT/5/n',
diff --git a/rpython/jit/metainterp/test/test_ajit.py b/rpython/jit/metainterp/test/test_ajit.py
--- a/rpython/jit/metainterp/test/test_ajit.py
+++ b/rpython/jit/metainterp/test/test_ajit.py
@@ -115,10 +115,13 @@
             while y > 0:
                 myjitdriver.can_enter_jit(x=x, y=y, res=res)
                 myjitdriver.jit_merge_point(x=x, y=y, res=res)
-                res += ovfcheck(x * x)
-                x += 1
-                res += ovfcheck(x * x)
-                y -= 1
+                try:
+                    res += ovfcheck(x * x)
+                    x += 1
+                    res += ovfcheck(x * x)
+                    y -= 1
+                except OverflowError:
+                    assert 0
             return res
         res = self.meta_interp(f, [6, 7])
         assert res == 1323
@@ -151,7 +154,10 @@
                 myjitdriver.can_enter_jit(x=x, y=y, res=res)
                 myjitdriver.jit_merge_point(x=x, y=y, res=res)
                 b = y * 2
-                res += ovfcheck(x * x) + b
+                try:
+                    res += ovfcheck(x * x) + b
+                except OverflowError:
+                    assert 0
                 y -= 1
             return res
         res = self.meta_interp(f, [6, 7])
@@ -230,8 +236,8 @@
         res = self.meta_interp(f, [6, 32, 16])
         assert res == 1692
         self.check_trace_count(3)
-        self.check_resops({'int_lt': 2, 'int_gt': 4, 'guard_false': 2,
-                           'guard_true': 4, 'int_sub': 4, 'jump': 3,
+        self.check_resops({'int_lt': 4, 'int_gt': 4, 'guard_false': 2,
+                           'guard_true': 6, 'int_sub': 4, 'jump': 3,
                            'int_mul': 3, 'int_add': 4})
 
     def test_loop_invariant_mul_ovf2(self):
@@ -400,7 +406,7 @@
             return externfn(n, n+1)
         res = self.interp_operations(f, [6])
         assert res == 42
-        self.check_operations_history(int_add=1, int_mul=0, call=1, guard_no_exception=0)
+        self.check_operations_history(int_add=1, int_mul=0, call_i=1, guard_no_exception=0)
 
     def test_residual_call_elidable(self):
         def externfn(x, y):
@@ -413,7 +419,7 @@
         assert res == 42
         # CALL_PURE is not recorded in the history if all-constant args
         self.check_operations_history(int_add=0, int_mul=0,
-                                      call=0, call_pure_i=0)
+                                      call_i=0, call_pure_i=0)
 
     def test_residual_call_elidable_1(self):
         @elidable
@@ -425,7 +431,7 @@
         assert res == 42
         # CALL_PURE is recorded in the history if not-all-constant args
         self.check_operations_history(int_add=1, int_mul=0,
-                                      call=0, call_pure_i=1)
+                                      call_i=0, call_pure_i=1)
 
     def test_residual_call_elidable_2(self):
         myjitdriver = JitDriver(greens = [], reds = ['n'])
@@ -653,11 +659,11 @@
         #
         res = self.meta_interp(f, [3, 6], repeat=7, function_threshold=0)
         assert res == 6 - 4 - 5
-        self.check_history(call=0)   # because the trace starts in the middle
+        self.check_history(call_n=0)   # because the trace starts in the middle
         #
         res = self.meta_interp(f, [60, 84], repeat=7)
         assert res == 84 - 61 - 62
-        self.check_history(call=1)   # because the trace starts immediately
+        self.check_history(call_n=1)   # because the trace starts immediately
 
     def test_unroll_one_loop_iteration(self):
         def unroll(code):
@@ -679,11 +685,11 @@
 
         res = self.meta_interp(f, [1, 4, 1], enable_opts="", inline=True)
         assert res == f(1, 4, 1)
-        self.check_history(call_assembler=0)
+        self.check_history(call_assembler_i=0)
 
         res = self.meta_interp(f, [1, 4, 2], enable_opts="", inline=True)
         assert res == f(1, 4, 2)
-        self.check_history(call_assembler=1)
+        self.check_history(call_assembler_i=1)
 
     def test_format(self):
         def f(n):
@@ -723,6 +729,7 @@
                 elif n == 7: a = 3
                 else:        a = 2
                 x = intmask(x * 10 + a)
+                #print "XXXXXXXXXXXXXXXX", x
                 i += 1
             return x
         res = self.meta_interp(f, [0], backendopt=True)
@@ -834,7 +841,7 @@
             return a.foo * x
         res = self.interp_operations(f, [42])
         assert res == 210
-        self.check_operations_history(getfield_gc=1)
+        self.check_operations_history(getfield_gc_i=1)
 
     def test_getfield_immutable(self):
         class A:
@@ -851,7 +858,7 @@
             return a.foo * x
         res = self.interp_operations(f, [42])
         assert res == 210
-        self.check_operations_history(getfield_gc=0)
+        self.check_operations_history(getfield_gc_i=0)
 
     def test_setfield_bool(self):
         class A:
@@ -882,6 +889,24 @@
         res = self.interp_operations(f, [1, sys.maxint])
         assert res == -42
 
+    def test_ovf_raise(self):
+        def g(x, y):
+            try:
+                return ovfcheck(x * y)
+            except OverflowError:
+                raise            
+        
+        def f(x, y):
+            try:
+                return g(x, y)
+            except OverflowError:
+                return 3
+
+        res = self.interp_operations(f, [sys.maxint, 2])
+        assert res == 3
+        res = self.interp_operations(f, [3, 2])
+        assert res == 6
+
     def test_int_sub_ovf(self):
         def f(x, y):
             try:
@@ -1356,7 +1381,7 @@
             return g(a, b)
         res = self.interp_operations(f, [3, 5])
         assert res == 8
-        self.check_operations_history(int_add=0, call=1)
+        self.check_operations_history(int_add=0, call_i=1)
 
     def test_listcomp(self):
         myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'lst'])
@@ -1380,7 +1405,7 @@
             return tup[1]
         res = self.interp_operations(f, [3, 5])
         assert res == 5
-        self.check_operations_history(setfield_gc=2, getfield_gc_pure=0)
+        self.check_operations_history(setfield_gc=2, getfield_gc_pure_i=0)
 
     def test_oosend_look_inside_only_one(self):
         class A:
@@ -1455,16 +1480,6 @@
         res = self.meta_interp(f, [299], listops=True)
         assert res == f(299)
         self.check_resops(guard_class=0, guard_value=6)
-        #
-        # The original 'guard_class' is rewritten to be directly 'guard_value'.
-        # Check that this rewrite does not interfere with the descr, which
-        # should be a full-fledged multivalued 'guard_value' descr.
-        if self.basic:
-            for loop in get_stats().get_all_loops():
-                for op in loop.get_operations():
-                    if op.getopname() == "guard_value":
-                        descr = op.getdescr()
-                        assert descr.get_index_of_guard_value() >= 0
 
     def test_merge_guardnonnull_guardclass(self):
         myjitdriver = JitDriver(greens = [], reds = ['x', 'l'])
@@ -1866,7 +1881,8 @@
         res = self.meta_interp(g, [6, 20])
         assert res == g(6, 20)
         self.check_trace_count(8)
-        self.check_resops(getarrayitem_gc_i=10)
+        # 6 extra from sharing guard data
+        self.check_resops(getarrayitem_gc_i=10 + 6)
 
     def test_multiple_specialied_versions_bridge(self):
         myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'z', 'res'])
@@ -2055,8 +2071,8 @@
         res = self.meta_interp(g, [3, 23])
         assert res == 7068153
         self.check_trace_count(6)
-        self.check_resops(guard_true=6, guard_class=2, int_mul=3,
-                          int_add=3, guard_false=3)
+        self.check_resops(guard_true=8, guard_class=2, int_mul=3,
+                          int_add=3, guard_false=4)
 
     def test_dont_trace_every_iteration(self):
         myjitdriver = JitDriver(greens = [], reds = ['a', 'b', 'i', 'sa'])
@@ -2079,7 +2095,7 @@
         self.check_enter_count(2)
 
     def test_current_trace_length(self):
-        myjitdriver = JitDriver(greens = ['g'], reds = ['x'])
+        myjitdriver = JitDriver(greens = ['g'], reds = ['x', 'l'])
         @dont_look_inside
         def residual():
             print "hi there"
@@ -2090,14 +2106,15 @@
                 residual()
                 y += 1
         def f(x, g):
+            l = []
             n = 0
             while x > 0:
-                myjitdriver.can_enter_jit(x=x, g=g)
-                myjitdriver.jit_merge_point(x=x, g=g)
+                myjitdriver.can_enter_jit(x=x, g=g, l=l)
+                myjitdriver.jit_merge_point(x=x, g=g, l=l)
                 loop(g)
                 x -= 1
-                n = current_trace_length()
-            return n
+                l.append(current_trace_length())
+            return l[-2] # not the blackholed version
         res = self.meta_interp(f, [5, 8])
         assert 14 < res < 42
         res = self.meta_interp(f, [5, 2])
@@ -2619,7 +2636,10 @@
                 node2.val = 7
                 if a >= 100:
                     sa += 1
-                sa += ovfcheck(i + i)
+                try:
+                    sa += ovfcheck(i + i)
+                except OverflowError:
+                    assert 0
                 node1 = A(i)
                 i += 1
         assert self.meta_interp(f, [20, 7]) == f(20, 7)
@@ -2638,7 +2658,7 @@
                 i += 1
             return sa
         assert self.meta_interp(f, [20]) == f(20)
-        self.check_resops(int_lt=4, int_le=0, int_ge=0, int_gt=2)
+        self.check_resops(int_lt=4, int_le=0, int_ge=0, int_gt=4)
 
     def test_intbounds_not_generalized1(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa'])
@@ -2655,7 +2675,7 @@
                 i += 1
             return sa
         assert self.meta_interp(f, [20]) == f(20)
-        self.check_resops(int_lt=6, int_le=2, int_ge=4, int_gt=3)
+        self.check_resops(int_lt=6, int_le=2, int_ge=4, int_gt=5)
 
 
     def test_intbounds_not_generalized2(self):
@@ -2676,7 +2696,7 @@
                 i += 1
             return sa
         assert self.meta_interp(f, [20]) == f(20)
-        self.check_resops(int_lt=4, int_le=3, int_ge=3, int_gt=2)
+        self.check_resops(int_lt=4, int_le=3, int_ge=3, int_gt=4)
 
     def test_retrace_limit1(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'a'])
@@ -3876,6 +3896,7 @@
 
 class TestLLtype(BaseLLtypeTests, LLJitMixin):
     def test_tagged(self):
+        py.test.skip("tagged unsupported")
         from rpython.rlib.objectmodel import UnboxedValue
         class Base(object):
             __slots__ = ()
@@ -3887,8 +3908,10 @@
                 return self.a > 0
 
             def dec(self):
-                return Int(self.a - 1)
-
+                try:
+                    return Int(self.a - 1)
+                except OverflowError:
+                    raise
 
         class Float(Base):
             def __init__(self, a):
@@ -3997,7 +4020,7 @@


More information about the pypy-commit mailing list