[pypy-commit] pypy slim-down-resumedescr: A branch to try and slim the guard resop descr

fijal noreply at buildbot.pypy.org
Wed Dec 24 11:56:01 CET 2014


Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: slim-down-resumedescr
Changeset: r75100:f5afc6c7549d
Date: 2014-12-24 12:47 +0200
http://bitbucket.org/pypy/pypy/changeset/f5afc6c7549d/

Log:	A branch to try and slim the guard resop descr

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
@@ -1479,15 +1479,15 @@
             assert kind == 'v'
         return lltype.nullptr(rclass.OBJECTPTR.TO)
 
-    def _prepare_resume_from_failure(self, opnum, dont_change_position,
-                                     deadframe):
+    def _prepare_resume_from_failure(self, opnum, deadframe):
         from rpython.jit.metainterp.resoperation import rop
         #
-        if opnum == rop.GUARD_TRUE:
+        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.
-            if not dont_change_position:
-                self.position = self.jitcode.follow_jump(self.position)
+            self.position = self.jitcode.follow_jump(self.position)
         #
         elif opnum == rop.GUARD_FALSE:
             # Produced directly by some goto_if_not_xxx() opcode that jumped,
@@ -1517,8 +1517,7 @@
         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.
-            if not dont_change_position:
-                return get_llexception(self.cpu, OverflowError())
+            return get_llexception(self.cpu, OverflowError())
         #
         elif opnum == rop.GUARD_OVERFLOW:
             # Produced by int_xxx_ovf().  The pc is just after the opcode.
@@ -1649,13 +1648,9 @@
         resumedescr,
         deadframe,
         all_virtuals)
-    if isinstance(resumedescr, ResumeAtPositionDescr):
-        dont_change_position = True
-    else:
-        dont_change_position = False
 
     current_exc = blackholeinterp._prepare_resume_from_failure(
-        resumedescr.guard_opnum, dont_change_position, deadframe)
+        resumedescr.guard_opnum, deadframe)
 
     _run_forever(blackholeinterp, current_exc)
 
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
@@ -479,22 +479,36 @@
     return d
 
 class ResumeDescr(AbstractFailDescr):
-    pass
+    _attrs_ = ()
 
 class ResumeGuardDescr(ResumeDescr):
-    # this class also gets the following attributes stored by resume.py code
-    # XXX move all of unused stuff to guard_op, now that we can have
-    #     a separate class, so it does not survive that long
-    rd_snapshot = None
-    rd_frame_info_list = None
+    _attrs_ = ('rd_numb', 'rd_count', 'rd_consts', 'rd_virtuals',
+               'rd_frame_info_list', 'rd_pendingfields', 'status')
+    
     rd_numb = lltype.nullptr(NUMBERING)
     rd_count = 0
     rd_consts = None
     rd_virtuals = None
+    rd_frame_info_list = None
     rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO)
 
     status = r_uint(0)
 
+    def clone(self):
+        new = self.__class__()
+        new.rd_frame_info_list = self.rd_frame_info_list
+        return new
+
+    def copy_all_attributes_from(self, other):
+        assert isinstance(other, ResumeGuardDescr)
+        self.rd_count = other.rd_count
+        self.rd_consts = other.rd_consts
+        self.rd_frame_info_list = other.rd_frame_info_list
+        self.rd_pendingfields = other.rd_pendingfields
+        self.rd_virtuals = other.rd_virtuals
+        self.rd_numb = other.rd_numb
+        # we don't copy status
+
     ST_BUSY_FLAG    = 0x01     # if set, busy tracing from the guard
     ST_TYPE_MASK    = 0x06     # mask for the type (TY_xxx)
     ST_SHIFT        = 3        # in "status >> ST_SHIFT" is stored:
@@ -509,31 +523,12 @@
     def store_final_boxes(self, guard_op, boxes, metainterp_sd):
         guard_op.setfailargs(boxes)
         self.rd_count = len(boxes)
-        self.guard_opnum = guard_op.getopnum()
         #
         if metainterp_sd.warmrunnerdesc is not None:   # for tests
             jitcounter = metainterp_sd.warmrunnerdesc.jitcounter
             hash = jitcounter.fetch_next_hash()
             self.status = hash & self.ST_SHIFT_MASK
 
-    def make_a_counter_per_value(self, guard_value_op):
-        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
-        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)
-
     def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd):
         if self.must_compile(deadframe, metainterp_sd, jitdriver_sd):
             self.start_compiling()
@@ -632,32 +627,62 @@
                                self, inputargs, new_loop.operations,
                                new_loop.original_jitcell_token)
 
-    def copy_all_attributes_into(self, res):
-        # XXX a bit ugly to have to list them all here
-        res.rd_snapshot = self.rd_snapshot
-        res.rd_frame_info_list = self.rd_frame_info_list
-        res.rd_numb = self.rd_numb
-        res.rd_consts = self.rd_consts
-        res.rd_virtuals = self.rd_virtuals
-        res.rd_pendingfields = self.rd_pendingfields
-        res.rd_count = self.rd_count
+    def make_a_counter_per_value(self, guard_value_op):
+        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
+        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)
 
-    def _clone_if_mutable(self):
-        res = ResumeGuardDescr()
-        self.copy_all_attributes_into(res)
-        return res
+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):
-    def _clone_if_mutable(self):
-        res = ResumeGuardNotInvalidated()
-        self.copy_all_attributes_into(res)
-        return res
+    guard_opnum = rop.GUARD_NOT_INVALIDATED
 
 class ResumeAtPositionDescr(ResumeGuardDescr):
-    def _clone_if_mutable(self):
-        res = ResumeAtPositionDescr()
-        self.copy_all_attributes_into(res)
-        return res
+    guard_opnum = rop.GUARD_FUTURE_CONDITION
 
 class AllVirtuals:
     llopaque = True
@@ -678,11 +703,19 @@
 
 
 class ResumeGuardForcedDescr(ResumeGuardDescr):
+    guard_opnum = rop.GUARD_NOT_FORCED
 
-    def __init__(self, metainterp_sd, jitdriver_sd):
+    def _init(self, metainterp_sd, jitdriver_sd):
+        # to please the annotator
         self.metainterp_sd = metainterp_sd
         self.jitdriver_sd = jitdriver_sd
 
+    def clone(self):
+        new = ResumeGuardForcedDescr()
+        new._init(self.metainterp_sd, self.jitdriver_sd)
+        new.rd_frame_info_list = self.rd_frame_info_list
+        return new
+
     def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd):
         # Failures of a GUARD_NOT_FORCED are never compiled, but
         # always just blackholed.  First fish for the data saved when
@@ -740,13 +773,6 @@
         hidden_all_virtuals = obj.hide(metainterp_sd.cpu)
         metainterp_sd.cpu.set_savedata_ref(deadframe, hidden_all_virtuals)
 
-    def _clone_if_mutable(self):
-        res = ResumeGuardForcedDescr(self.metainterp_sd,
-                                     self.jitdriver_sd)
-        self.copy_all_attributes_into(res)
-        return res
-
-
 class ResumeFromInterpDescr(ResumeDescr):
     def __init__(self, original_greenkey):
         self.original_greenkey = original_greenkey
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
@@ -134,14 +134,6 @@
     def repr_of_descr(self):
         return '%r' % (self,)
 
-    def _clone_if_mutable(self):
-        return self
-    def clone_if_mutable(self):
-        clone = self._clone_if_mutable()
-        if not we_are_translated():
-            assert clone.__class__ is self.__class__
-        return clone
-
     def hide(self, cpu):
         descr_ptr = cpu.ts.cast_instance_to_base_ref(self)
         return cpu.ts.cast_to_ref(descr_ptr)
@@ -159,6 +151,8 @@
     index = -1
     final_descr = False
 
+    _attrs_ = ()
+
     def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd):
         raise NotImplementedError
     def compile_and_attach(self, metainterp, new_loop):
diff --git a/rpython/jit/metainterp/inliner.py b/rpython/jit/metainterp/inliner.py
--- a/rpython/jit/metainterp/inliner.py
+++ b/rpython/jit/metainterp/inliner.py
@@ -1,5 +1,6 @@
 from rpython.jit.metainterp.history import Const
 from rpython.jit.metainterp.resume import Snapshot
+from rpython.jit.metainterp.resoperation import GuardResOp
 
 
 class Inliner(object):
@@ -26,21 +27,16 @@
                 newop.setfailargs([self.inline_arg(a) for a in args])
             else:
                 newop.setfailargs([])
+            assert isinstance(newop, GuardResOp)
+            newop.rd_snapshot = self.inline_snapshot(newop.rd_snapshot)
 
         if newop.result and not ignore_result:
             old_result = newop.result
             newop.result = newop.result.clonebox()
             self.argmap[old_result] = newop.result
 
-        self.inline_descr_inplace(newop.getdescr())
-
         return newop
 
-    def inline_descr_inplace(self, descr):
-        from rpython.jit.metainterp.compile import ResumeGuardDescr
-        if isinstance(descr, ResumeGuardDescr):
-            descr.rd_snapshot = self.inline_snapshot(descr.rd_snapshot)
-
     def inline_arg(self, arg):
         if arg is None:
             return None
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
@@ -7,7 +7,8 @@
                                                      IntLowerBound, MININT,\
                                                      MAXINT
 from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method
-from rpython.jit.metainterp.resoperation import rop, ResOperation, AbstractResOp
+from rpython.jit.metainterp.resoperation import rop, ResOperation,\
+     AbstractResOp, GuardResOp
 from rpython.jit.metainterp.typesystem import llhelper
 from rpython.tool.pairtype import extendabletype
 from rpython.rlib.debug import debug_print
@@ -735,6 +736,11 @@
         while i > 0:
             i -= 1
             if self._newoperations[i] is old_op:
+                # a bit of dance to make sure we copy all the attrs on
+                # an already emitted descr
+                newdescr = new_op.getdescr()
+                olddescr = old_op.getdescr()
+                newdescr.copy_all_attributes_from(olddescr)
                 self._newoperations[i] = new_op
                 break
         else:
@@ -744,7 +750,9 @@
         assert pendingfields is not None
         descr = op.getdescr()
         assert isinstance(descr, compile.ResumeGuardDescr)
-        modifier = resume.ResumeDataVirtualAdder(descr, self.resumedata_memo)
+        assert isinstance(op, GuardResOp)
+        modifier = resume.ResumeDataVirtualAdder(descr, op,
+                                                 self.resumedata_memo)
         try:
             newboxes = modifier.finish(self, pendingfields)
             if len(newboxes) > self.metainterp_sd.options.failargs_limit:
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
@@ -312,15 +312,11 @@
                 if not previous_classbox.same_constant(expected_classbox):
                     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()
             op = old_guard_op.copy_and_change(rop.GUARD_VALUE,
-                                      args = [old_guard_op.getarg(0), op.getarg(1)])
+                        args = [old_guard_op.getarg(0), op.getarg(1)],
+                        descr = descr)
             self.optimizer.replaces_guard[op] = old_guard_op
-            # hack hack hack.  Change the guard_opnum on
-            # new_guard_op.getdescr() so that when resuming,
-            # the operation is not skipped by pyjitpl.py.
-            descr = op.getdescr()
-            assert isinstance(descr, compile.ResumeGuardDescr)
-            descr.guard_opnum = rop.GUARD_VALUE
             descr.make_a_counter_per_value(op)
             # to be safe
             if isinstance(value, PtrOptValue):
@@ -364,15 +360,11 @@
             if old_guard_op.getopnum() == rop.GUARD_NONNULL:
                 # it was a guard_nonnull, which we replace with a
                 # guard_nonnull_class.
+                descr = compile.ResumeGuardNonnullClassDescr()
                 op = old_guard_op.copy_and_change (rop.GUARD_NONNULL_CLASS,
-                                         args = [old_guard_op.getarg(0), op.getarg(1)])
+                            args = [old_guard_op.getarg(0), op.getarg(1)],
+                            descr=descr)
                 self.optimizer.replaces_guard[op] = old_guard_op
-                # hack hack hack.  Change the guard_opnum on
-                # new_guard_op.getdescr() so that when resuming,
-                # the operation is not skipped by pyjitpl.py.
-                descr = op.getdescr()
-                assert isinstance(descr, compile.ResumeGuardDescr)
-                descr.guard_opnum = rop.GUARD_NONNULL_CLASS
         self.emit_operation(op)
         value.make_constant_class(expectedclassbox, op)
 
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
@@ -24,7 +24,7 @@
     fi0 = resume.FrameInfo(None, "code0", 11)
     fdescr.rd_frame_info_list = resume.FrameInfo(fi0, "code1", 33)
     snapshot0 = resume.Snapshot(None, [b0])
-    fdescr.rd_snapshot = resume.Snapshot(snapshot0, [b1])
+    op.rd_snapshot = resume.Snapshot(snapshot0, [b1])
     #
     opt.store_final_boxes_in_guard(op, [])
     if op.getfailargs() == [b0, b1]:
@@ -97,7 +97,8 @@
     enable_opts = "intbounds:rewrite:virtualize:string:earlyforce:pure:heap"
 
     def optimize_loop(self, ops, optops, call_pure_results=None):
-        loop = self.parse(ops)
+                
+        loop = self.parse(ops, postprocess=self.postprocess)
         token = JitCellToken()
         loop.operations = [ResOperation(rop.LABEL, loop.inputargs, None, descr=TargetToken(token))] + \
                           loop.operations
@@ -108,42 +109,6 @@
         print '\n'.join([str(o) for o in loop.operations])
         self.assert_equal(loop, expected)
 
-    def setup_method(self, meth=None):
-        class FailDescr(compile.ResumeGuardDescr):
-            oparse = None
-            def _oparser_uses_descr_of_guard(self, oparse, fail_args):
-                # typically called 3 times: once when parsing 'ops',
-                # once when parsing 'preamble', once when parsing 'expected'.
-                self.oparse = oparse
-                self.rd_frame_info_list, self.rd_snapshot = snapshot(fail_args)
-            def _clone_if_mutable(self):
-                assert self is fdescr
-                return fdescr2
-            def __repr__(self):
-                if self is fdescr:
-                    return 'fdescr'
-                if self is fdescr2:
-                    return 'fdescr2'
-                return compile.ResumeGuardDescr.__repr__(self)
-        #
-        def snapshot(fail_args, got=[]):
-            if not got:    # only the first time, i.e. when parsing 'ops'
-                rd_frame_info_list = resume.FrameInfo(None, "code", 11)
-                rd_snapshot = resume.Snapshot(None, fail_args)
-                got.append(rd_frame_info_list)
-                got.append(rd_snapshot)
-            return got
-        #
-        fdescr = instantiate(FailDescr)
-        self.namespace['fdescr'] = fdescr
-        fdescr2 = instantiate(FailDescr)
-        self.namespace['fdescr2'] = fdescr2
-
-    def teardown_method(self, meth):
-        self.namespace.pop('fdescr', None)
-        self.namespace.pop('fdescr2', None)
-
-
 
 class BaseTestOptimizeBasic(BaseTestBasic):
 
@@ -2065,14 +2030,14 @@
     def test_merge_guard_nonnull_guard_class(self):
         ops = """
         [p1, i0, i1, i2, p2]
-        guard_nonnull(p1, descr=fdescr) [i0]
+        guard_nonnull(p1) [i0]
         i3 = int_add(i1, i2)
         guard_class(p1, ConstClass(node_vtable)) [i1]
         jump(p2, i0, i1, i3, p2)
         """
         expected = """
         [p1, i0, i1, i2, p2]
-        guard_nonnull_class(p1, ConstClass(node_vtable), descr=fdescr) [i0]
+        guard_nonnull_class(p1, ConstClass(node_vtable)) [i0]
         i3 = int_add(i1, i2)
         jump(p2, i0, i1, i3, p2)
         """
@@ -2082,14 +2047,14 @@
     def test_merge_guard_nonnull_guard_value(self):
         ops = """
         [p1, i0, i1, i2, p2]
-        guard_nonnull(p1, descr=fdescr) [i0]
+        guard_nonnull(p1) [i0]
         i3 = int_add(i1, i2)
         guard_value(p1, ConstPtr(myptr)) [i1]
         jump(p2, i0, i1, i3, p2)
         """
         expected = """
         [p1, i0, i1, i2, p2]
-        guard_value(p1, ConstPtr(myptr), descr=fdescr) [i0]
+        guard_value(p1, ConstPtr(myptr)) [i0]
         i3 = int_add(i1, i2)
         jump(p2, i0, i1, i3, p2)
         """
@@ -2099,7 +2064,7 @@
     def test_merge_guard_nonnull_guard_class_guard_value(self):
         ops = """
         [p1, i0, i1, i2, p2]
-        guard_nonnull(p1, descr=fdescr) [i0]
+        guard_nonnull(p1) [i0]
         i3 = int_add(i1, i2)
         guard_class(p1, ConstClass(node_vtable)) [i2]
         i4 = int_sub(i3, 1)
@@ -2108,7 +2073,7 @@
         """
         expected = """
         [p1, i0, i1, i2, p2]
-        guard_value(p1, ConstPtr(myptr), descr=fdescr) [i0]
+        guard_value(p1, ConstPtr(myptr)) [i0]
         i3 = int_add(i1, i2)
         i4 = int_sub(i3, 1)
         jump(p2, i0, i1, i4, p2)
@@ -2527,7 +2492,7 @@
         reader = ResumeDataFakeReader(fdescr, fail_args,
                                       MyMetaInterp(self.cpu))
         boxes = reader.consume_boxes()
-        self._verify_fail_args(boxes, fdescr.oparse, expectedtext)
+        self._verify_fail_args(boxes, self.oparse, expectedtext)
 
     def test_expand_fail_1(self):
         ops = """
@@ -2538,12 +2503,12 @@
         i4 = getfield_gc(p1, descr=valuedescr)
         #
         i2 = int_add(10, 5)
-        guard_true(i1, descr=fdescr) [i2, i4]
+        guard_true(i1) [i2, i4]
         jump(i1, i4)
         """
         expected = """
         [i1, i3]
-        guard_true(i1, descr=fdescr) [i3]
+        guard_true(i1) [i3]
         jump(1, i3)
         """
         self.optimize_loop(ops, expected)
@@ -2555,12 +2520,12 @@
         p1 = new_with_vtable(ConstClass(node_vtable))
         setfield_gc(p1, i2, descr=valuedescr)
         setfield_gc(p1, p1, descr=nextdescr)
-        guard_true(i1, descr=fdescr) [p1]
+        guard_true(i1) [p1]
         jump(i1, i2)
         """
         expected = """
         [i1, i2]
-        guard_true(i1, descr=fdescr) [i2]
+        guard_true(i1) [i2]
         jump(1, i2)
         """
         self.optimize_loop(ops, expected)
@@ -2577,12 +2542,12 @@
         setfield_gc(p1, p2, descr=nextdescr)
         setfield_gc(p2, i2, descr=valuedescr)
         setfield_gc(p2, p3, descr=nextdescr)
-        guard_true(i1, descr=fdescr) [i3, p1]
+        guard_true(i1) [i3, p1]
         jump(i2, i1, i3, p3)
         """
         expected = """
         [i1, i2, i3, p3]
-        guard_true(i1, descr=fdescr) [i3, i2, p3]
+        guard_true(i1) [i3, i2, p3]
         jump(i2, 1, i3, p3)
         """
         self.optimize_loop(ops, expected)
@@ -2594,7 +2559,6 @@
     def test_expand_fail_4(self):
         for arg in ['p1', 'i2,p1', 'p1,p2', 'p2,p1',
                     'i2,p1,p2', 'i2,p2,p1']:
-            self.setup_method() # humpf
             ops = """
             [i1, i2, i3]
             p1 = new_with_vtable(ConstClass(node_vtable))
@@ -2604,12 +2568,12 @@
             setfield_gc(p1, i2, descr=valuedescr)
             setfield_gc(p1, p2, descr=nextdescr)
             setfield_gc(p2, i2, descr=valuedescr)
-            guard_true(i1, descr=fdescr) [i4, i3, %s]
+            guard_true(i1) [i4, i3, %s]
             jump(i1, i2, i3)
             """
             expected = """
             [i1, i2, i3]
-            guard_true(i1, descr=fdescr) [i3, i2]
+            guard_true(i1) [i3, i2]
             jump(1, i2, i3)
             """
             self.optimize_loop(ops % arg, expected)
@@ -2627,12 +2591,12 @@
         setfield_gc(p1, p2, descr=nextdescr)
         setfield_gc(p2, i2, descr=valuedescr)
         setfield_gc(p2, p1, descr=nextdescr)      # a cycle
-        guard_true(i1, descr=fdescr) [i3, i4, p1, p2]
+        guard_true(i1) [i3, i4, p1, p2]
         jump(i2, i1, i3, i4)
         """
         expected = """
         [i1, i2, i3, i4]
-        guard_true(i1, descr=fdescr) [i3, i4, i2]
+        guard_true(i1) [i3, i4, i2]
         jump(i2, 1, i3, i4)
         """
         self.optimize_loop(ops, expected)
@@ -2644,14 +2608,14 @@
     def test_expand_fail_6(self):
         ops = """
         [p0, i0, i1]
-        guard_true(i0, descr=fdescr) [p0]
+        guard_true(i0) [p0]
         p1 = new_with_vtable(ConstClass(node_vtable))
         setfield_gc(p1, i1, descr=valuedescr)
         jump(p1, i1, i1)
         """
         expected = """
         [i1b, i0, i1]
-        guard_true(i0, descr=fdescr) [i1b]
+        guard_true(i0) [i1b]
         jump(i1, i1, i1)
         """
         py.test.skip("XXX")
@@ -2667,13 +2631,13 @@
         p1 = new_array(3, descr=arraydescr)
         setarrayitem_gc(p1, 1, i1, descr=arraydescr)
         setarrayitem_gc(p1, 0, 25, descr=arraydescr)
-        guard_true(i1, descr=fdescr) [p1]
+        guard_true(i1) [p1]
         i2 = getarrayitem_gc(p1, 1, descr=arraydescr)
         jump(i2)
         """
         expected = """
         [i1]
-        guard_true(i1, descr=fdescr) [i1]
+        guard_true(i1) [i1]
         jump(1)
         """
         self.optimize_loop(ops, expected)
@@ -2687,14 +2651,14 @@
         p2 = new(descr=ssize)
         setfield_gc(p2, i1, descr=adescr)
         setfield_gc(p2, p1, descr=bdescr)
-        guard_true(i1, descr=fdescr) [p2]
+        guard_true(i1) [p2]
         i3 = getfield_gc(p2, descr=adescr)
         p3 = getfield_gc(p2, descr=bdescr)
         jump(i3, p3)
         """
         expected = """
         [i1, p1]
-        guard_true(i1, descr=fdescr) [i1, p1]
+        guard_true(i1) [i1, p1]
         jump(1, p1)
         """
         self.optimize_loop(ops, expected)
@@ -2711,7 +2675,7 @@
         setfield_gc(p5s, i2, descr=adescr)
         setfield_gc(p5s, p7v, descr=bdescr)
         setarrayitem_gc(p1a, 1, p5s, descr=arraydescr2)
-        guard_true(i1, descr=fdescr) [p1a]
+        guard_true(i1) [p1a]
         p2s = new(descr=ssize)
         p3v = new_with_vtable(ConstClass(node_vtable))
         p4a = new_array(2, descr=arraydescr2)
@@ -2723,7 +2687,7 @@
         """
         expected = """
         [i1, ia, iv, pnull, i2]
-        guard_true(i1, descr=fdescr) [ia, iv, i2]
+        guard_true(i1) [ia, iv, i2]
         jump(1, 1, i2, NULL, i2)
         """
         py.test.skip("XXX")
@@ -2749,14 +2713,14 @@
         p2 = new_with_vtable(ConstClass(node_vtable))
         setfield_gc(p2, i2, descr=valuedescr)
         setfield_gc(p1, p2, descr=nextdescr)
-        guard_true(i3, descr=fdescr) []
+        guard_true(i3) []
         i4 = int_neg(i2)
         setfield_gc(p1, NULL, descr=nextdescr)
         jump(p1, i2, i4)
         """
         expected = """
         [p1, i2, i3]
-        guard_true(i3, descr=fdescr) [p1, i2]
+        guard_true(i3) [p1, i2]
         i4 = int_neg(i2)
         setfield_gc(p1, NULL, descr=nextdescr)
         jump(p1, i2, i4)
@@ -2774,14 +2738,14 @@
         p2 = new_with_vtable(ConstClass(node_vtable))
         setfield_gc(p2, i2, descr=valuedescr)
         setfield_gc(ConstPtr(myptr), p2, descr=nextdescr)
-        guard_true(i3, descr=fdescr) []
+        guard_true(i3) []
         i4 = int_neg(i2)
         setfield_gc(ConstPtr(myptr), NULL, descr=nextdescr)
         jump(i2, i4)
         """
         expected = """
         [i2, i3]
-        guard_true(i3, descr=fdescr) [i2]
+        guard_true(i3) [i2]
         i4 = int_neg(i2)
         setfield_gc(ConstPtr(myptr), NULL, descr=nextdescr)
         jump(i2, i4)
@@ -3096,7 +3060,7 @@
         p2 = virtual_ref(p1, 2)
         setfield_gc(p0, p2, descr=nextdescr)
         call_may_force(i1, descr=mayforcevirtdescr)
-        guard_not_forced(descr=fdescr) [p2, p1]
+        guard_not_forced() [p2, p1]
         virtual_ref_finish(p2, p1)
         setfield_gc(p0, NULL, descr=nextdescr)
         jump(p0, i1)
@@ -3111,7 +3075,7 @@
         setfield_gc(p0, p2, descr=nextdescr)
         #
         call_may_force(i1, descr=mayforcevirtdescr)
-        guard_not_forced(descr=fdescr) [p2, i1]
+        guard_not_forced() [p2, i1]
         #
         setfield_gc(p0, NULL, descr=nextdescr)
         p1 = new_with_vtable(ConstClass(node_vtable))
@@ -3142,7 +3106,7 @@
         p2 = virtual_ref(p1, 2)
         setfield_gc(p0, p2, descr=refdescr)
         call(i1, descr=nonwritedescr)
-        guard_no_exception(descr=fdescr) [p2, p1]
+        guard_no_exception() [p2, p1]
         virtual_ref_finish(p2, p1)
         setfield_gc(p0, NULL, descr=refdescr)
         jump(p0, i1)
@@ -3151,7 +3115,7 @@
         [p0, i1]
         p3 = force_token()
         call(i1, descr=nonwritedescr)
-        guard_no_exception(descr=fdescr) [p3, i1, p0]
+        guard_no_exception() [p3, i1, p0]
         setfield_gc(p0, NULL, descr=refdescr)
         jump(p0, i1)
         """
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
@@ -45,7 +45,7 @@
 
     def optimize_loop(self, ops, expected, expected_preamble=None,
                       call_pure_results=None, expected_short=None):
-        loop = self.parse(ops)
+        loop = self.parse(ops, postprocess=self.postprocess)
         if expected != "crash!":
             expected = self.parse(expected)
         if expected_preamble:
@@ -96,41 +96,6 @@
 
 
 class OptimizeOptTest(BaseTestWithUnroll):
-    def setup_method(self, meth=None):
-        class FailDescr(compile.ResumeGuardDescr):
-            oparse = None
-            def _oparser_uses_descr_of_guard(self, oparse, fail_args):
-                # typically called 3 times: once when parsing 'ops',
-                # once when parsing 'preamble', once when parsing 'expected'.
-                self.oparse = oparse
-                self.rd_frame_info_list, self.rd_snapshot = snapshot(fail_args)
-            def _clone_if_mutable(self):
-                assert self is fdescr
-                return fdescr2
-            def __repr__(self):
-                if self is fdescr:
-                    return 'fdescr'
-                if self is fdescr2:
-                    return 'fdescr2'
-                return compile.ResumeGuardDescr.__repr__(self)
-        #
-        def snapshot(fail_args, got=[]):
-            if not got:    # only the first time, i.e. when parsing 'ops'
-                rd_frame_info_list = resume.FrameInfo(None, "code", 11)
-                rd_snapshot = resume.Snapshot(None, fail_args)
-                got.append(rd_frame_info_list)
-                got.append(rd_snapshot)
-            return got
-        #
-        fdescr = instantiate(FailDescr)
-        self.namespace['fdescr'] = fdescr
-        fdescr2 = instantiate(FailDescr)
-        self.namespace['fdescr2'] = fdescr2
-
-    def teardown_method(self, meth):
-        self.namespace.pop('fdescr', None)
-        self.namespace.pop('fdescr2', None)
-
     def test_simple(self):
         ops = """
         []
@@ -3004,20 +2969,20 @@
     def test_merge_guard_nonnull_guard_class(self):
         ops = """
         [p1, i0, i1, i2, p2]
-        guard_nonnull(p1, descr=fdescr) [i0]
+        guard_nonnull(p1) [i0]
         i3 = int_add(i1, i2)
         guard_class(p1, ConstClass(node_vtable)) [i1]
         jump(p2, i0, i1, i3, p2)
         """
         preamble = """
         [p1, i0, i1, i2, p2]
-        guard_nonnull_class(p1, ConstClass(node_vtable), descr=fdescr) [i0]
+        guard_nonnull_class(p1, ConstClass(node_vtable)) [i0]
         i3 = int_add(i1, i2)
         jump(p2, i0, i1, i3)
         """
         expected = """
         [p2, i0, i1, i2]
-        guard_nonnull_class(p2, ConstClass(node_vtable), descr=fdescr2) [i0]
+        guard_nonnull_class(p2, ConstClass(node_vtable)) [i0]
         i3 = int_add(i1, i2)
         jump(p2, i0, i1, i3)
         """
@@ -3027,20 +2992,20 @@
     def test_merge_guard_nonnull_guard_value(self):
         ops = """
         [p1, i0, i1, i2, p2]
-        guard_nonnull(p1, descr=fdescr) [i0]
+        guard_nonnull(p1) [i0]
         i3 = int_add(i1, i2)
         guard_value(p1, ConstPtr(myptr)) [i1]
         jump(p2, i0, i1, i3, p2)
         """
         preamble = """
         [p1, i0, i1, i2, p2]
-        guard_value(p1, ConstPtr(myptr), descr=fdescr) [i0]
+        guard_value(p1, ConstPtr(myptr)) [i0]
         i3 = int_add(i1, i2)
         jump(p2, i0, i1, i3)
         """
         expected = """
         [p2, i0, i1, i2]
-        guard_value(p2, ConstPtr(myptr), descr=fdescr2) [i0]
+        guard_value(p2, ConstPtr(myptr)) [i0]
         i3 = int_add(i1, i2)
         jump(ConstPtr(myptr), i0, i1, i3)
         """
@@ -3050,7 +3015,7 @@
     def test_merge_guard_nonnull_guard_class_guard_value(self):
         ops = """
         [p1, i0, i1, i2, p2]
-        guard_nonnull(p1, descr=fdescr) [i0]
+        guard_nonnull(p1) [i0]
         i3 = int_add(i1, i2)
         guard_class(p1, ConstClass(node_vtable)) [i2]
         i4 = int_sub(i3, 1)
@@ -3059,14 +3024,14 @@
         """
         preamble = """
         [p1, i0, i1, i2, p2]
-        guard_value(p1, ConstPtr(myptr), descr=fdescr) [i0]
+        guard_value(p1, ConstPtr(myptr)) [i0]
         i3 = int_add(i1, i2)
         i4 = int_sub(i3, 1)
         jump(p2, i0, i1, i4)
         """
         expected = """
         [p2, i0, i1, i2]
-        guard_value(p2, ConstPtr(myptr), descr=fdescr2) [i0]
+        guard_value(p2, ConstPtr(myptr)) [i0]
         i3 = int_add(i1, i2)
         i4 = int_sub(i3, 1)
         jump(ConstPtr(myptr), i0, i1, i4)
@@ -3860,7 +3825,7 @@
         p2 = virtual_ref(p1, 2)
         setfield_gc(p0, p2, descr=nextdescr)
         call_may_force(i1, descr=mayforcevirtdescr)
-        guard_not_forced(descr=fdescr) [p2, p1]
+        guard_not_forced() [p2, p1]
         virtual_ref_finish(p2, p1)
         setfield_gc(p0, NULL, descr=nextdescr)
         jump(p0, i1)
@@ -3875,7 +3840,7 @@
         setfield_gc(p0, p2, descr=nextdescr)
         #
         call_may_force(i1, descr=mayforcevirtdescr)
-        guard_not_forced(descr=fdescr2) [p2, i1]
+        guard_not_forced() [p2, i1]
         #
         setfield_gc(p0, NULL, descr=nextdescr)
         p1 = new_with_vtable(ConstClass(node_vtable))
@@ -3906,7 +3871,7 @@
         p2 = virtual_ref(p1, 2)
         setfield_gc(p0, p2, descr=refdescr)
         call(i1, descr=nonwritedescr)
-        guard_no_exception(descr=fdescr) [p2, p1]
+        guard_no_exception() [p2, p1]
         virtual_ref_finish(p2, p1)
         setfield_gc(p0, NULL, descr=refdescr)
         escape()
@@ -3916,7 +3881,7 @@
         [p0, i1]
         p3 = force_token()
         call(i1, descr=nonwritedescr)
-        guard_no_exception(descr=fdescr) [p3, i1, p0]
+        guard_no_exception() [p3, i1, p0]
         setfield_gc(p0, NULL, descr=refdescr)
         escape()
         jump(p0, i1)
@@ -3925,7 +3890,7 @@
         [p0, i1]
         p3 = force_token()
         call(i1, descr=nonwritedescr)
-        guard_no_exception(descr=fdescr2) [p3, i1, p0]
+        guard_no_exception() [p3, i1, p0]
         setfield_gc(p0, NULL, descr=refdescr)
         escape()
         jump(p0, i1)
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py b/rpython/jit/metainterp/optimizeopt/test/test_util.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_util.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py
@@ -8,12 +8,13 @@
 from rpython.jit.backend.llgraph import runner
 from rpython.jit.metainterp.history import (BoxInt, BoxPtr, ConstInt, ConstPtr,
                                          Const, TreeLoop, AbstractDescr,
-                                         JitCellToken, TargetToken)
+                                         JitCellToken, TargetToken,
+    BasicFinalDescr)
 from rpython.jit.metainterp.optimizeopt.util import sort_descrs, equaloplists
 from rpython.jit.metainterp.optimize import InvalidLoop
 from rpython.jit.codewriter.effectinfo import EffectInfo
 from rpython.jit.codewriter.heaptracker import register_known_gctype, adr2int
-from rpython.jit.tool.oparser import parse, pure_parse
+from rpython.jit.tool.oparser import OpParser, pure_parse
 from rpython.jit.metainterp.quasiimmut import QuasiImmutDescr
 from rpython.jit.metainterp import compile, resume, history
 from rpython.jit.metainterp.jitprof import EmptyProfiler
@@ -348,40 +349,46 @@
     def store_final_boxes(self, op, boxes, metainterp_sd):
         op.setfailargs(boxes)
     def __eq__(self, other):
-        return type(self) is type(other)      # xxx obscure
-    def clone_if_mutable(self):
-        res = Storage(self.metainterp_sd, self.original_greenkey)
-        self.copy_all_attributes_into(res)
-        return res
+        return True # screw this
+        #return type(self) is type(other)      # xxx obscure
 
 def _sortboxes(boxes):
     _kind2count = {history.INT: 1, history.REF: 2, history.FLOAT: 3}
     return sorted(boxes, key=lambda box: _kind2count[box.type])
 
+final_descr = BasicFinalDescr()
+
 class BaseTest(object):
 
-    def parse(self, s, boxkinds=None, want_fail_descr=True):
+    def parse(self, s, boxkinds=None, want_fail_descr=True, postprocess=None):
         if want_fail_descr:
             invent_fail_descr = self.invent_fail_descr
         else:
             invent_fail_descr = lambda *args: None
-        return parse(s, self.cpu, self.namespace,
-                     type_system=self.type_system,
-                     boxkinds=boxkinds,
-                     invent_fail_descr=invent_fail_descr)
+        self.oparse = OpParser(s, self.cpu, self.namespace, 'lltype',
+                               boxkinds,
+                               invent_fail_descr, False, postprocess)
+        return self.oparse.parse()
+
+    def postprocess(self, op):
+        if op.is_guard():
+            op.rd_snapshot = resume.Snapshot(None, op.getfailargs())
+            op.getdescr().rd_frame_info_list = resume.FrameInfo(None, "code", 11)
 
     def add_guard_future_condition(self, res):
         # invent a GUARD_FUTURE_CONDITION to not have to change all tests
         if res.operations[-1].getopnum() == rop.JUMP:
-            guard = ResOperation(rop.GUARD_FUTURE_CONDITION, [], None, descr=self.invent_fail_descr(None, -1, []))
+            guard = ResOperation(rop.GUARD_FUTURE_CONDITION, [], None, descr=self.invent_fail_descr(None, rop.GUARD_FUTURE_CONDITION, []))
+            guard.rd_snapshot = resume.Snapshot(None, [])
             res.operations.insert(-1, guard)
 
     def invent_fail_descr(self, model, opnum, fail_args):
-        if fail_args is None:
-            return None
-        descr = Storage()
-        descr.rd_frame_info_list = resume.FrameInfo(None, "code", 11)
-        descr.rd_snapshot = resume.Snapshot(None, _sortboxes(fail_args))
+        if rop._GUARD_FIRST <= opnum <= rop._GUARD_LAST:
+            descr = Storage()
+            descr.guard_opnum = opnum
+            descr.rd_frame_info_list = resume.FrameInfo(None, "code", 11)
+        else:
+            descr = final_descr
         return descr
 
     def assert_equal(self, optimized, expected, text_right=None):
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py
@@ -15,6 +15,7 @@
 from rpython.jit.metainterp.history import TreeLoop, JitCellToken
 from rpython.jit.metainterp.optimizeopt.test.test_optimizeopt import FakeMetaInterpStaticData
 from rpython.jit.metainterp.resoperation import ResOperation, rop
+from rpython.jit.metainterp import resume
 
 class BaseTestGenerateGuards(BaseTest):
 
@@ -804,8 +805,9 @@
     def optimize_bridge(self, loops, bridge, expected, expected_target='Loop', **boxvalues):
         if isinstance(loops, str):
             loops = (loops, )
-        loops = [self.parse(loop) for loop in loops]
-        bridge = self.parse(bridge)
+        loops = [self.parse(loop, postprocess=self.postprocess)
+                 for loop in loops]
+        bridge = self.parse(bridge, postprocess=self.postprocess)
         self.add_guard_future_condition(bridge)
         for loop in loops:
             loop.preamble = self.unroll_and_optimize(loop)
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_zdisable_opts.py b/rpython/jit/metainterp/optimizeopt/test/test_zdisable_opts.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_zdisable_opts.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_zdisable_opts.py
@@ -13,7 +13,7 @@
 
         def optimize_loop(self, ops, expected, expected_preamble=None,
                           call_pure_results=None, expected_short=None):
-            loop = self.parse(ops)
+            loop = self.parse(ops, postprocess=self.postprocess)
             if expected != "crash!":
                 expected = self.parse(expected)
             if expected_preamble:
diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py
--- a/rpython/jit/metainterp/optimizeopt/unroll.py
+++ b/rpython/jit/metainterp/optimizeopt/unroll.py
@@ -1,6 +1,5 @@
 import sys
 
-from rpython.jit.metainterp.compile import ResumeGuardDescr
 from rpython.jit.metainterp.history import TargetToken, JitCellToken, Const
 from rpython.jit.metainterp.inliner import Inliner
 from rpython.jit.metainterp.optimize import InvalidLoop
@@ -8,7 +7,7 @@
 from rpython.jit.metainterp.optimizeopt.optimizer import Optimizer, Optimization
 from rpython.jit.metainterp.optimizeopt.virtualstate import (VirtualStateConstructor,
         ShortBoxes, BadVirtualState, VirtualStatesCantMatch)
-from rpython.jit.metainterp.resoperation import rop, ResOperation
+from rpython.jit.metainterp.resoperation import rop, ResOperation, GuardResOp
 from rpython.jit.metainterp.resume import Snapshot
 from rpython.rlib.debug import debug_print, debug_start, debug_stop
 
@@ -560,7 +559,10 @@
 
             for guard in extra_guards:
                 if guard.is_guard():
-                    descr = patchguardop.getdescr().clone_if_mutable()
+                    descr = patchguardop.getdescr().clone()
+                    assert isinstance(guard, GuardResOp)
+                    assert isinstance(patchguardop, GuardResOp)
+                    guard.rd_snapshot = patchguardop.rd_snapshot
                     guard.setdescr(descr)
                 self.optimizer.send_extra_operation(guard)
 
@@ -590,7 +592,10 @@
             if newop.is_guard():
                 if not patchguardop:
                     raise InvalidLoop("would like to have short preamble, but it has a guard and there's no guard_future_condition")
-                descr = patchguardop.getdescr().clone_if_mutable()
+                descr = patchguardop.getdescr().clone()
+                assert isinstance(newop, GuardResOp)
+                assert isinstance(patchguardop, GuardResOp)
+                newop.rd_snapshot = patchguardop.rd_snapshot
                 newop.setdescr(descr)
             self.optimizer.send_extra_operation(newop)
             if shop.result in assumed_classes:
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
@@ -12,7 +12,7 @@
 from rpython.jit.metainterp.jitprof import EmptyProfiler
 from rpython.jit.metainterp.logger import Logger
 from rpython.jit.metainterp.optimizeopt.util import args_dict
-from rpython.jit.metainterp.resoperation import rop
+from rpython.jit.metainterp.resoperation import rop, GuardResOp
 from rpython.rlib import nonconst, rstack
 from rpython.rlib.debug import debug_start, debug_stop, debug_print
 from rpython.rlib.debug import have_debug_prints, make_sure_not_resized
@@ -1875,22 +1875,45 @@
         else:
             moreargs = list(extraargs)
         if opnum == rop.GUARD_NOT_FORCED or opnum == rop.GUARD_NOT_FORCED_2:
-            resumedescr = compile.ResumeGuardForcedDescr(self.staticdata,
-                                                         self.jitdriver_sd)
+            resumedescr = compile.ResumeGuardForcedDescr()
+            resumedescr._init(self.staticdata, self.jitdriver_sd)
         elif opnum == rop.GUARD_NOT_INVALIDATED:
             resumedescr = compile.ResumeGuardNotInvalidated()
         elif opnum == rop.GUARD_FUTURE_CONDITION:
             resumedescr = compile.ResumeAtPositionDescr()
+        elif opnum == rop.GUARD_VALUE:
+            resumedescr = compile.ResumeGuardValueDescr()
+        elif opnum == rop.GUARD_NONNULL:
+            resumedescr = compile.ResumeGuardNonnullDescr()
+        elif opnum == rop.GUARD_ISNULL:
+            resumedescr = compile.ResumeGuardIsnullDescr()
+        elif opnum == rop.GUARD_NONNULL_CLASS:
+            resumedescr = compile.ResumeGuardNonnullClassDescr()
+        elif opnum == rop.GUARD_CLASS:
+            resumedescr = compile.ResumeGuardClassDescr()
+        elif opnum == rop.GUARD_TRUE:
+            resumedescr = compile.ResumeGuardTrueDescr()
+        elif opnum == rop.GUARD_FALSE:
+            resumedescr = compile.ResumeGuardFalseDescr()
+        elif opnum == rop.GUARD_EXCEPTION:
+            resumedescr = compile.ResumeGuardExceptionDescr()
+        elif opnum == rop.GUARD_NO_EXCEPTION:
+            resumedescr = compile.ResumeGuardNoExceptionDescr()
+        elif opnum == rop.GUARD_OVERFLOW:
+            resumedescr = compile.ResumeGuardOverflowDescr()
+        elif opnum == rop.GUARD_NO_OVERFLOW:
+            resumedescr = compile.ResumeGuardNoOverflowDescr()
         else:
-            resumedescr = compile.ResumeGuardDescr()
+            assert False
         guard_op = self.history.record(opnum, moreargs, None, descr=resumedescr)
-        self.capture_resumedata(resumedescr, resumepc)
+        assert isinstance(guard_op, GuardResOp)
+        self.capture_resumedata(guard_op, resumedescr, resumepc)
         self.staticdata.profiler.count_ops(opnum, Counters.GUARDS)
         # count
         self.attach_debug_info(guard_op)
         return guard_op
 
-    def capture_resumedata(self, resumedescr, resumepc=-1):
+    def capture_resumedata(self, guard_op, resumedescr, resumepc=-1):
         virtualizable_boxes = None
         if (self.jitdriver_sd.virtualizable_info is not None or
             self.jitdriver_sd.greenfield_info is not None):
@@ -1902,7 +1925,7 @@
             if resumepc >= 0:
                 frame.pc = resumepc
         resume.capture_resumedata(self.framestack, virtualizable_boxes,
-                                  self.virtualref_boxes, resumedescr)
+                                  self.virtualref_boxes, resumedescr, guard_op)
         if self.framestack:
             self.framestack[-1].pc = saved_pc
 
@@ -2163,13 +2186,8 @@
         self.seen_loop_header_for_jdindex = -1
         if isinstance(key, compile.ResumeAtPositionDescr):
             self.seen_loop_header_for_jdindex = self.jitdriver_sd.index
-            dont_change_position = True
-        else:
-            dont_change_position = False
         try:
-            self.prepare_resume_from_failure(key.guard_opnum,
-                                             dont_change_position,
-                                             deadframe)
+            self.prepare_resume_from_failure(key.guard_opnum, deadframe)
             if self.resumekey_original_loop_token is None:   # very rare case
                 raise SwitchToBlackhole(Counters.ABORT_BRIDGE)
             self.interpret()
@@ -2312,12 +2330,12 @@
             else: assert 0
         self.jitdriver_sd.warmstate.execute_assembler(loop_token, *args)
 
-    def prepare_resume_from_failure(self, opnum, dont_change_position,
-                                    deadframe):
+    def prepare_resume_from_failure(self, opnum, deadframe):
         frame = self.framestack[-1]
-        if opnum == rop.GUARD_TRUE:     # a goto_if_not that jumps only now
-            if not dont_change_position:
-                frame.pc = frame.jitcode.follow_jump(frame.pc)
+        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:
@@ -2341,12 +2359,11 @@
             pass # XXX we want to do something special in resume descr,
                  # but not now
         elif opnum == rop.GUARD_NO_OVERFLOW:   # an overflow now detected
-            if not dont_change_position:
-                self.execute_raised(OverflowError(), constant=True)
-                try:
-                    self.finishframe_exception()
-                except ChangeFrame:
-                    pass
+            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:
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
@@ -91,8 +91,6 @@
     def clone(self):
         args = self.getarglist()
         descr = self.getdescr()
-        if descr is not None:
-            descr = descr.clone_if_mutable()
         op = ResOperation(self.getopnum(), args[:], self.result, descr)
         if not we_are_translated():
             op.name = self.name
@@ -217,6 +215,8 @@
 
     _fail_args = None
 
+    rd_snapshot = None
+
     def getfailargs(self):
         return self._fail_args
 
@@ -225,12 +225,20 @@
 
     def copy_and_change(self, opnum, args=None, result=None, descr=None):
         newop = AbstractResOp.copy_and_change(self, opnum, args, result, descr)
+        assert isinstance(newop, GuardResOp)
         newop.setfailargs(self.getfailargs())
+        newop.rd_snapshot = self.rd_snapshot
         return newop
 
     def clone(self):
         newop = AbstractResOp.clone(self)
+        assert isinstance(newop, GuardResOp)
         newop.setfailargs(self.getfailargs())
+        newop.rd_snapshot = self.rd_snapshot
+        descr = self.getdescr()
+        if descr is not None: # for short preamble which is a mess
+            newdescr = descr.clone()
+            newop.setdescr(newdescr)
         return newop
 
 # ============
diff --git a/rpython/jit/metainterp/resume.py b/rpython/jit/metainterp/resume.py
--- a/rpython/jit/metainterp/resume.py
+++ b/rpython/jit/metainterp/resume.py
@@ -55,7 +55,7 @@
                                          back.get_list_of_active_boxes(True))
 
 def capture_resumedata(framestack, virtualizable_boxes, virtualref_boxes,
-                       storage):
+                       storage, snapshot_storage):
     n = len(framestack) - 1
     if virtualizable_boxes is not None:
         boxes = virtualref_boxes + virtualizable_boxes
@@ -70,10 +70,10 @@
         snapshot = Snapshot(top.parent_resumedata_snapshot,
                             top.get_list_of_active_boxes(False))
         snapshot = Snapshot(snapshot, boxes)
-        storage.rd_snapshot = snapshot
+        snapshot_storage.rd_snapshot = snapshot
     else:
         storage.rd_frame_info_list = None
-        storage.rd_snapshot = Snapshot(None, boxes)
+        snapshot_storage.rd_snapshot = Snapshot(None, boxes)
 
 #
 # The following is equivalent to the RPython-level declaration:
@@ -270,8 +270,9 @@
 
 class ResumeDataVirtualAdder(VirtualVisitor):
 
-    def __init__(self, storage, memo):
+    def __init__(self, storage, snapshot_storage, memo):
         self.storage = storage
+        self.snapshot_storage = snapshot_storage
         self.memo = memo
 
     def make_virtual_info(self, value, fieldnums):
@@ -357,13 +358,13 @@
         storage = self.storage
         # make sure that nobody attached resume data to this guard yet
         assert not storage.rd_numb
-        snapshot = storage.rd_snapshot
+        snapshot = self.snapshot_storage.rd_snapshot
         assert snapshot is not None # is that true?
         numb, liveboxes_from_env, v = self.memo.number(optimizer, snapshot)
         self.liveboxes_from_env = liveboxes_from_env
         self.liveboxes = {}
         storage.rd_numb = numb
-        storage.rd_snapshot = None
+        self.snapshot_storage.rd_snapshot = None
 
         # collect liveboxes and virtuals
         n = len(liveboxes_from_env) - v
diff --git a/rpython/jit/metainterp/test/test_resume.py b/rpython/jit/metainterp/test/test_resume.py
--- a/rpython/jit/metainterp/test/test_resume.py
+++ b/rpython/jit/metainterp/test/test_resume.py
@@ -123,7 +123,7 @@
     class FakeVirtualValue(AbstractVirtualValue):
         def visitor_dispatch_virtual_type(self, *args):
             return FakeVInfo()
-    modifier = ResumeDataVirtualAdder(None, None)
+    modifier = ResumeDataVirtualAdder(None, None, None)
     v1 = FakeVirtualValue(None, None)
     vinfo1 = modifier.make_virtual_info(v1, [1, 2, 4])
     vinfo2 = modifier.make_virtual_info(v1, [1, 2, 4])
@@ -542,7 +542,7 @@
     fs = [FakeFrame("code0", 0, b1, c1, b2)]
 
     storage = Storage()
-    capture_resumedata(fs, None, [], storage)
+    capture_resumedata(fs, None, [], storage, storage)
 
     assert fs[0].parent_resumedata_snapshot is None
     assert fs[0].parent_resumedata_frame_info_list is None
@@ -558,7 +558,7 @@
     fs = [FakeFrame("code0", 0, b1, c1, b2),
           FakeFrame("code1", 3, b3, c2, b1),
           FakeFrame("code2", 9, c3, b2)]
-    capture_resumedata(fs, None, [], storage)
+    capture_resumedata(fs, None, [], storage, storage)
 
     frame_info_list = storage.rd_frame_info_list
     assert frame_info_list.prev is fs[2].parent_resumedata_frame_info_list
@@ -588,7 +588,7 @@
     fs[2].pc = 15
     vbs = [b1, b2]
     vrs = [b3]
-    capture_resumedata(fs, vbs, vrs, storage)
+    capture_resumedata(fs, vbs, vrs, storage, storage)
 
     frame_info_list = storage.rd_frame_info_list
     assert frame_info_list.prev is fs[2].parent_resumedata_frame_info_list
@@ -616,9 +616,9 @@
     fs = [FakeFrame("code0", 0, b1, c1, b2),
           FakeFrame("code1", 3, b3, c2, b1),
           FakeFrame("code2", 9, c3, b2)]
-    capture_resumedata(fs, None, [], storage)
+    capture_resumedata(fs, None, [], storage, storage)
     memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
-    modifier = ResumeDataVirtualAdder(storage, memo)
+    modifier = ResumeDataVirtualAdder(storage, storage, memo)
     liveboxes = modifier.finish(FakeOptimizer({}))
     metainterp = MyMetaInterp()
 
@@ -640,7 +640,7 @@
     fs = [FakeFrame("code0", 0, b1, c1, b2),
           FakeFrame("code1", 3, b3, c2, b1),
           FakeFrame("code2", 9, c3, b2)]
-    capture_resumedata(fs, [b4], [], storage)
+    capture_resumedata(fs, [b4], [], storage, storage)
     memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
     modifier = ResumeDataVirtualAdder(storage, memo)
     liveboxes = modifier.finish(FakeOptimizer({}))
@@ -665,10 +665,10 @@
     fs = [FakeFrame("code0", 0, b1, c1, b2),
           FakeFrame("code1", 3, b3, c2, b1),
           FakeFrame("code2", 9, c3, b2)]
-    capture_resumedata(fs, None, [], storage)
+    capture_resumedata(fs, None, [], storage, storage)
     storage2 = Storage()
     fs = fs[:-1] + [FakeFrame("code2", 10, c3, b2, b4)]
-    capture_resumedata(fs, None, [], storage2)
+    capture_resumedata(fs, None, [], storage2, storage2)
     
     memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
     modifier = ResumeDataVirtualAdder(storage, memo)
@@ -728,10 +728,10 @@
     fs = [FakeFrame("code0", 0, b1, c1, b2),
           FakeFrame("code1", 3, b3, c2, b1),
           FakeFrame("code2", 9, c3, b2)]
-    capture_resumedata(fs, None, [], storage)
+    capture_resumedata(fs, None, [], storage, storage)
     storage2 = Storage()
     fs = fs[:-1] + [FakeFrame("code2", 10, c3, b2, b4)]
-    capture_resumedata(fs, None, [], storage2)
+    capture_resumedata(fs, None, [], storage2, storage2)
     
     memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
     values = {b2: virtual_value(b2, b5, c4)}
@@ -788,7 +788,7 @@
                       LLtypeMixin.nodebox.constbox()]
     storage = Storage()
     fs = [FakeFrame("code0", 0, c1, b2, b3)]
-    capture_resumedata(fs, None, [], storage)
+    capture_resumedata(fs, None, [], storage, storage)
     
     memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
     values = {b2: virtual_value(b2, b5, c4)}
@@ -800,7 +800,7 @@
 
     storage2 = Storage()
     fs = [FakeFrame("code0", 0, b1, b4, b2)]
-    capture_resumedata(fs, None, [], storage2)
+    capture_resumedata(fs, None, [], storage2, storage2)
     values[b4] = virtual_value(b4, b6, c4)
     modifier = ResumeDataVirtualAdder(storage2, memo)
     liveboxes = modifier.finish(FakeOptimizer(values))
@@ -814,7 +814,7 @@
     b1, b2, b3 = [BoxPtr(), BoxPtr(), BoxInt()]
     storage = Storage()
     fs = [FakeFrame("code0", 0, b1, b2)]
-    capture_resumedata(fs, None, [], storage)
+    capture_resumedata(fs, None, [], storage, storage)
     
     memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
     v1 = virtual_value(b1, b3, None)
@@ -1022,7 +1022,7 @@
 def test_register_virtual_fields():
     b1, b2 = BoxInt(), BoxInt()
     vbox = BoxPtr()
-    modifier = ResumeDataVirtualAdder(None, None)
+    modifier = ResumeDataVirtualAdder(None, None, None)
     modifier.liveboxes_from_env = {}
     modifier.liveboxes = {}
     modifier.vfieldboxes = {}
@@ -1031,7 +1031,7 @@
                                   b2: UNASSIGNED}
     assert modifier.vfieldboxes == {vbox: [b1, b2]}
 
-    modifier = ResumeDataVirtualAdder(None, None)
+    modifier = ResumeDataVirtualAdder(None, None, None)
     modifier.liveboxes_from_env = {vbox: tag(0, TAGVIRTUAL)}
     modifier.liveboxes = {}
     modifier.vfieldboxes = {}
@@ -1061,7 +1061,7 @@
     b1s, b2s, b3s = [ConstInt(sys.maxint), ConstInt(2**16), ConstInt(-65)]
     storage = make_storage(b1s, b2s, b3s)
     memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())    
-    modifier = ResumeDataVirtualAdder(storage, memo)
+    modifier = ResumeDataVirtualAdder(storage, storage, memo)
     liveboxes = modifier.finish(FakeOptimizer({}))
     assert storage.rd_snapshot is None
     cpu = MyCPU([])
@@ -1075,14 +1075,14 @@
     b1s, b2s, b3s = [ConstInt(sys.maxint), ConstInt(2**16), ConstInt(-65)]
     storage = make_storage(b1s, b2s, b3s)
     memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
-    modifier = ResumeDataVirtualAdder(storage, memo)
+    modifier = ResumeDataVirtualAdder(storage, storage, memo)
     modifier.finish(FakeOptimizer({}))
     assert len(memo.consts) == 2
     assert storage.rd_consts is memo.consts
 
     b1s, b2s, b3s = [ConstInt(sys.maxint), ConstInt(2**17), ConstInt(-65)]
     storage2 = make_storage(b1s, b2s, b3s)
-    modifier2 = ResumeDataVirtualAdder(storage2, memo)
+    modifier2 = ResumeDataVirtualAdder(storage2, storage2, memo)
     modifier2.finish(FakeOptimizer({}))
     assert len(memo.consts) == 3    
     assert storage2.rd_consts is memo.consts
@@ -1137,7 +1137,7 @@
     b1s, b2s, b3s = [BoxInt(1), BoxInt(2), BoxInt(3)]
     storage = make_storage(b1s, b2s, b3s)
     memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
-    modifier = ResumeDataVirtualAdder(storage, memo)
+    modifier = ResumeDataVirtualAdder(storage, storage, memo)
     b1_2 = BoxInt()
     class FakeValue(object):
 
@@ -1169,7 +1169,7 @@
     b1s = ConstInt(111)
     storage = make_storage(b1s, b2s, b3s)
     memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())        
-    modifier = ResumeDataVirtualAdder(storage, memo)
+    modifier = ResumeDataVirtualAdder(storage, storage, memo)
     liveboxes = modifier.finish(FakeOptimizer({}))
     b2t, b3t = [BoxPtr(demo55o), BoxInt(33)]
     newboxes = _resume_remap(liveboxes, [b2s, b3s], b2t, b3t)
@@ -1190,7 +1190,7 @@
     c1s = ConstInt(111)
     storage = Storage()
     memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
-    modifier = ResumeDataVirtualAdder(storage, memo)
+    modifier = ResumeDataVirtualAdder(storage, storage, memo)
     modifier.liveboxes_from_env = {}
     modifier.liveboxes = {}
     modifier.vfieldboxes = {}
@@ -1273,7 +1273,7 @@
     c1s = ConstInt(111)
     storage = Storage()
     memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
-    modifier = ResumeDataVirtualAdder(storage, memo)
+    modifier = ResumeDataVirtualAdder(storage, storage, memo)
     modifier.liveboxes_from_env = {}
     modifier.liveboxes = {}
     modifier.vfieldboxes = {}
@@ -1321,7 +1321,7 @@
     c1s = ConstInt(111)
     storage = Storage()
     memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
-    modifier = ResumeDataVirtualAdder(storage, memo)
+    modifier = ResumeDataVirtualAdder(storage, storage, memo)
     modifier.liveboxes_from_env = {}
     modifier.liveboxes = {}
     modifier.vfieldboxes = {}
@@ -1364,7 +1364,7 @@
     b2s, b4s = [BoxPtr(), BoxPtr()]
     storage = Storage()
     memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
-    modifier = ResumeDataVirtualAdder(storage, memo)
+    modifier = ResumeDataVirtualAdder(storage, storage, memo)
     modifier.liveboxes_from_env = {}
     modifier.liveboxes = {}
     modifier.vfieldboxes = {}
@@ -1403,7 +1403,7 @@
     class Storage(object):
         pass
     storage = Storage()
-    modifier = ResumeDataVirtualAdder(storage, None)
+    modifier = ResumeDataVirtualAdder(storage, storage, None)
     modifier._add_pending_fields([])
     assert not storage.rd_pendingfields
     #
@@ -1411,7 +1411,7 @@
         pass
     field_a = FieldDescr()
     storage = Storage()
-    modifier = ResumeDataVirtualAdder(storage, None)
+    modifier = ResumeDataVirtualAdder(storage, storage, None)
     modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042),
                                    61: rffi.cast(rffi.SHORT, 1061)}
     modifier._add_pending_fields([(field_a, 42, 61, -1)])
@@ -1425,7 +1425,7 @@
     #
     array_a = FieldDescr()
     storage = Storage()
-    modifier = ResumeDataVirtualAdder(storage, None)
+    modifier = ResumeDataVirtualAdder(storage, storage, None)
     modifier.liveboxes_from_env = {42: rffi.cast(rffi.SHORT, 1042),
                                    61: rffi.cast(rffi.SHORT, 1061),
                                    62: rffi.cast(rffi.SHORT, 1062),
@@ -1506,7 +1506,7 @@
     metainterp_sd = FakeMetaInterpStaticData()
     metainterp_sd.options = options
     memo = ResumeDataLoopMemo(metainterp_sd)
-    modifier = ResumeDataVirtualAdder(None, memo)
+    modifier = ResumeDataVirtualAdder(None, None, memo)
 
     for i in range(5):
         assert not modifier._invalidation_needed(5, i)
diff --git a/rpython/jit/tool/oparser.py b/rpython/jit/tool/oparser.py
--- a/rpython/jit/tool/oparser.py
+++ b/rpython/jit/tool/oparser.py
@@ -61,9 +61,10 @@
 
     def __init__(self, input, cpu, namespace, type_system, boxkinds,
                  invent_fail_descr=default_fail_descr,
-                 nonstrict=False):
+                 nonstrict=False, postproces=None):
         self.input = input
         self.vars = {}
+        self._postproces = postproces
         self.cpu = cpu
         self._consts = namespace
         self.type_system = type_system
@@ -237,8 +238,6 @@
                     fail_args.append(fail_arg)
             if descr is None and self.invent_fail_descr:
                 descr = self.invent_fail_descr(self.model, opnum, fail_args)
-            if hasattr(descr, '_oparser_uses_descr_of_guard'):
-                descr._oparser_uses_descr_of_guard(self, fail_args)
         else:
             fail_args = None
             if opnum == rop.FINISH:
@@ -250,7 +249,7 @@
 
         return opnum, args, descr, fail_args
 
-    def create_op(self, opnum, args, result, descr):
+    def create_op(self, opnum, args, result, descr, fail_args):
         if opnum == ESCAPE_OP.OPNUM:
             op = ESCAPE_OP(result)
             op.initarglist(args)
@@ -262,7 +261,12 @@
             assert descr is None
             return op
         else:
-            return ResOperation(opnum, args, result, descr)
+            res = ResOperation(opnum, args, result, descr)
+            if fail_args is not None:
+                res.setfailargs(fail_args)
+            if self._postproces:
+                self._postproces(res)
+            return res
 
     def parse_result_op(self, line):
         res, op = line.split("=", 1)
@@ -273,16 +277,12 @@
             raise ParseError("Double assign to var %s in line: %s" % (res, line))
         rvar = self.box_for_var(res)
         self.vars[res] = rvar
-        res = self.create_op(opnum, args, rvar, descr)
-        if fail_args is not None:
-            res.setfailargs(fail_args)
+        res = self.create_op(opnum, args, rvar, descr, fail_args)
         return res
 
     def parse_op_no_result(self, line):
         opnum, args, descr, fail_args = self.parse_op(line)
-        res = self.create_op(opnum, args, None, descr)
-        if fail_args is not None:
-            res.setfailargs(fail_args)
+        res = self.create_op(opnum, args, None, descr, fail_args)
         return res
 
     def parse_next_op(self, line):
@@ -377,11 +377,12 @@
 
 def parse(input, cpu=None, namespace=None, type_system='lltype',
           boxkinds=None, invent_fail_descr=default_fail_descr,
-          no_namespace=False, nonstrict=False, OpParser=OpParser):
+          no_namespace=False, nonstrict=False, OpParser=OpParser,
+          postprocess=None):
     if namespace is None and not no_namespace:
         namespace = {}
     return OpParser(input, cpu, namespace, type_system, boxkinds,
-                    invent_fail_descr, nonstrict).parse()
+                    invent_fail_descr, nonstrict, postprocess).parse()
 
 def pure_parse(*args, **kwds):
     kwds['invent_fail_descr'] = None


More information about the pypy-commit mailing list