Commits

Maciej Fijalkowski  committed 3b467df

some progress on resop specialization

  • Participants
  • Parent commits 4547d65
  • Branches result-in-resops

Comments (0)

Files changed (21)

File pypy/jit/backend/llgraph/runner.py

 from pypy.rpython.ootypesystem import ootype
 from pypy.rpython.llinterp import LLInterpreter
 from pypy.jit.metainterp import history
-from pypy.jit.metainterp.history import REF, INT, FLOAT, STRUCT
+from pypy.jit.metainterp.resoperation import REF, INT, FLOAT, STRUCT
 from pypy.jit.metainterp.warmstate import unwrap
 from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.backend import model

File pypy/jit/metainterp/compile.py

 from pypy.conftest import option
 from pypy.tool.sourcetools import func_with_new_name
 
-from pypy.jit.metainterp.resoperation import ResOperation, rop, get_deep_immutable_oplist
+from pypy.jit.metainterp.resoperation import rop, get_deep_immutable_oplist
 from pypy.jit.metainterp.history import TreeLoop, Box, History, JitCellToken, TargetToken
 from pypy.jit.metainterp.history import AbstractFailDescr, BoxInt
 from pypy.jit.metainterp.history import BoxPtr, BoxObj, BoxFloat, Const, ConstInt

File pypy/jit/metainterp/executor.py

 from pypy.rlib.rarithmetic import ovfcheck, r_longlong, is_valid_int
 from pypy.rlib.rtimer import read_timestamp
 from pypy.rlib.unroll import unrolling_iterable
-from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, check_descr
-from pypy.jit.metainterp.history import INT, REF, FLOAT, VOID, AbstractDescr
+from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, check_descr,\
+     AbstractDescr
+from pypy.jit.metainterp.resoperation import INT, REF, FLOAT, VOID
 from pypy.jit.metainterp import resoperation
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop, create_resop
 from pypy.jit.metainterp.blackhole import BlackholeInterpreter, NULL
 from pypy.jit.codewriter import longlong
 
             name = 'bhimpl_' + key.lower()
             if hasattr(BlackholeInterpreter, name):
                 func = make_execute_function_with_boxes(
+                    value,
                     key.lower(),
                     getattr(BlackholeInterpreter, name).im_func)
                 if func is not None:
             #raise AssertionError("missing %r" % (key,))
     return execute_by_num_args
 
-def make_execute_function_with_boxes(name, func):
+def make_execute_function_with_boxes(opnum, name, func):
     # Make a wrapper for 'func'.  The func is a simple bhimpl_xxx function
     # from the BlackholeInterpreter class.  The wrapper is a new function
     # that receives and returns boxed values.
     if func.resulttype not in ('i', 'r', 'f', None):
         return None
     argtypes = unrolling_iterable(func.argtypes)
-    resulttype = func.resulttype
     #
     def do(cpu, _, *args):
         newargs = ()
         assert not args
         #
         result = func(*newargs)
-        ResOperation(opnum, orig_args, result, )
+        if has_descr:
+            return create_resop(opnum, orig_args[:-1], result, orig_args[-1])
+        else:
+            return create_resop(opnum, orig_args, result)
         #
-        if resulttype == 'i': return BoxInt(result)
-        if resulttype == 'r': return BoxPtr(result)
-        if resulttype == 'f': return BoxFloat(result)
-        return None
     #
     do.func_name = 'do_' + name
     return do

File pypy/jit/metainterp/heapcache.py

     def _output_indirection(self, box):
         return self.output_indirections.get(box, box)
 
-    def invalidate_caches(self, opnum, descr, argboxes):
-        self.mark_escaped(opnum, argboxes)
-        self.clear_caches(opnum, descr, argboxes)
+    def invalidate_caches(self, op):
+        self.mark_escaped(op)
+        self.clear_caches(op)
 
-    def mark_escaped(self, opnum, argboxes):
+    def mark_escaped(self, op):
+        opnum = op.getopnum()
         if opnum == rop.SETFIELD_GC:
             assert len(argboxes) == 2
             box, valuebox = argboxes
               opnum != rop.MARK_OPAQUE_PTR and
               opnum != rop.PTR_EQ and
               opnum != rop.PTR_NE):
-            idx = 0
-            for box in argboxes:
-                # setarrayitem_gc don't escape its first argument
-                if not (idx == 0 and opnum in [rop.SETARRAYITEM_GC]):
-                    self._escape(box)
-                idx += 1
+            op.foreach_arg(self._escape)
 
-    def _escape(self, box):
-        if box in self.new_boxes:
-            self.new_boxes[box] = False
-        if box in self.dependencies:
-            deps = self.dependencies[box]
-            del self.dependencies[box]
+    def _escape(self, opnum, idx, source):
+        # setarrayitem_gc don't escape its first argument
+        if idx == 0 and opnum == rop.SETARRAYITEM_GC:
+            return
+        if source in self.new_boxes:
+            self.new_boxes[source] = False
+        if source in self.dependencies:
+            deps = self.dependencies[source]
+            del self.dependencies[source]
             for dep in deps:
                 self._escape(dep)
 
-    def clear_caches(self, opnum, descr, argboxes):
+    def clear_caches(self, op):
+        opnum = op.getopnum()
         if (opnum == rop.SETFIELD_GC or
             opnum == rop.SETARRAYITEM_GC or
             opnum == rop.SETFIELD_RAW or

File pypy/jit/metainterp/history.py

 
 from pypy.conftest import option
 
-from pypy.jit.metainterp.resoperation import ResOperation, rop, AbstractValue
+from pypy.jit.metainterp.resoperation import rop, AbstractValue, INT, REF,\
+     FLOAT
+
 from pypy.jit.codewriter import heaptracker, longlong
 import weakref
 
 # ____________________________________________________________
 
-INT   = 'i'
-REF   = 'r'
-FLOAT = 'f'
-STRUCT = 's'
-HOLE  = '_'
-VOID  = 'v'
-
 FAILARGS_LIMIT = 1000
 
 def getkind(TYPE, supports_floats=True,
     def __repr__(self):
         return 'Const(%s)' % self._getrepr_()
 
+    def is_constant(self):
+        return True
+
 
 class ConstInt(Const):
     type = INT
         self.inputargs = None
         self.operations = []
 
-    def record(self, opnum, argboxes, resbox, descr=None):
-        op = ResOperation(opnum, argboxes, resbox, descr)
+    def record(self, op):
         self.operations.append(op)
-        return op
 
     def substitute_operation(self, position, opnum, argboxes, descr=None):
         resbox = self.operations[position].result

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

 from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
 from pypy.jit.metainterp.optimizeopt.vstring import VAbstractStringValue
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop
 
 class OptEarlyForce(Optimization):
     def propagate_forward(self, op):

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

 from pypy.jit.codewriter.effectinfo import EffectInfo
 from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
 from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop
 from pypy.rlib import clibffi, libffi
 from pypy.rlib.debug import debug_print
 from pypy.rlib.libffi import Func

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

 from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, MODE_ARRAY
 from pypy.jit.metainterp.history import ConstInt, Const
 from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop
 from pypy.rlib.objectmodel import we_are_translated
 
 

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

 from pypy.rlib.rarithmetic import ovfcheck, LONG_BIT, maxint, is_valid_int
 from pypy.rlib.objectmodel import we_are_translated
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop, create_resop
 from pypy.jit.metainterp.history import BoxInt, ConstInt
 MAXINT = maxint
 MININT = -maxint - 1

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

                                                      IntLowerBound, MININT, MAXINT
 from pypy.jit.metainterp.optimizeopt.util import (make_dispatcher_method,
     args_dict)
-from pypy.jit.metainterp.resoperation import rop, ResOperation, AbstractResOp
+from pypy.jit.metainterp.resoperation import rop, AbstractResOp
 from pypy.jit.metainterp.typesystem import llhelper, oohelper
 from pypy.tool.pairtype import extendabletype
 from pypy.rlib.debug import debug_start, debug_stop, debug_print

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

 from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, REMOVED
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.metainterp.optimizeopt.util import (make_dispatcher_method,
     args_dict)
 

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

 from pypy.jit.metainterp.optimizeopt.intutils import IntBound
 from pypy.jit.metainterp.optimizeopt.optimizer import *
 from pypy.jit.metainterp.optimizeopt.util import _findall, make_dispatcher_method
-from pypy.jit.metainterp.resoperation import (opboolinvers, opboolreflex, rop,
-    ResOperation)
+from pypy.jit.metainterp.resoperation import (opboolinvers, opboolreflex, rop)
 from pypy.rlib.rarithmetic import highest_bit
 
 

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

 from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
 from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
-from pypy.jit.metainterp.resoperation import ResOperation, rop
+from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.metainterp.history import TargetToken, JitCellToken
 
 class OptSimplify(Optimization):

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

 from pypy.jit.metainterp.optimizeopt.optimizer import *
 from pypy.jit.metainterp.optimizeopt.generalize import KillHugeIntBounds
 from pypy.jit.metainterp.inliner import Inliner
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.metainterp.resume import Snapshot
 import sys, os
 

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

 from pypy.jit.metainterp.optimizeopt import optimizer
 from pypy.jit.metainterp.optimizeopt.util import (make_dispatcher_method,
     descrlist_dict, sort_descrs)
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.jit.metainterp.optimizeopt.optimizer import OptValue
 

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

 from pypy.jit.metainterp.history import BoxInt, ConstInt, BoxPtr, Const
 from pypy.jit.metainterp.optimize import InvalidLoop
 from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.debug import debug_start, debug_stop, debug_print
 from pypy.rlib.objectmodel import we_are_translated

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

 from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1
 from pypy.jit.metainterp.optimizeopt.optimizer import llhelper, REMOVED
 from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop
 from pypy.rlib.objectmodel import specialize, we_are_translated
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rpython import annlowlevel

File pypy/jit/metainterp/pyjitpl.py

 from pypy.jit.metainterp import history, compile, resume
 from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstFloat
 from pypy.jit.metainterp.history import Box, TargetToken
-from pypy.jit.metainterp.resoperation import rop
+from pypy.jit.metainterp.resoperation import rop, create_resop
+from pypy.jit.metainterp import resoperation
 from pypy.jit.metainterp import executor
 from pypy.jit.metainterp.logger import Logger
 from pypy.jit.metainterp.jitprof import EmptyProfiler
                 assert not oldbox.same_box(b)
 
 
-    def make_result_of_lastop(self, resultbox):
-        got_type = resultbox.type
+    def make_result_of_lastop(self, resultop):
+        got_type = resultop.type
+        if got_type == resoperation.VOID:
+            return
         # XXX disabled for now, conflicts with str_guard_value
         #if not we_are_translated():
         #    typeof = {'i': history.INT,
         #              'f': history.FLOAT}
         #    assert typeof[self.jitcode._resulttypes[self.pc]] == got_type
         target_index = ord(self.bytecode[self.pc-1])
-        if got_type == history.INT:
-            self.registers_i[target_index] = resultbox
-        elif got_type == history.REF:
+        if got_type == resoperation.INT:
+            self.registers_i[target_index] = resultop
+        elif got_type == resoperation.REF:
             #debug_print(' ->',
             #            llmemory.cast_ptr_to_adr(resultbox.getref_base()))
-            self.registers_r[target_index] = resultbox
-        elif got_type == history.FLOAT:
-            self.registers_f[target_index] = resultbox
+            self.registers_r[target_index] = resultop
+        elif got_type == resoperation.FLOAT:
+            self.registers_f[target_index] = resultop
         else:
             raise AssertionError("bad result box type")
 
 
     @specialize.arg(1)
     def execute_varargs(self, opnum, argboxes, descr, exc, pure):
+        xxx
         self.metainterp.clear_exception()
         resbox = self.metainterp.execute_and_record_varargs(opnum, argboxes,
                                                             descr=descr)
         # store this information for fastpath of call_assembler
         # (only the paths that can actually be taken)
         for jd in self.jitdrivers_sd:
-            name = {history.INT: 'int',
-                    history.REF: 'ref',
-                    history.FLOAT: 'float',
-                    history.VOID: 'void'}[jd.result_type]
+            name = {resoperation.INT: 'int',
+                    resoperation.REF: 'ref',
+                    resoperation.FLOAT: 'float',
+                    resoperation.VOID: 'void'}[jd.result_type]
             tokens = getattr(self, 'loop_tokens_done_with_this_frame_%s' % name)
             jd.portal_finishtoken = tokens[0].finishdescr
             num = self.cpu.get_fail_descr_number(tokens[0].finishdescr)
                 self.aborted_tracing(stb.reason)
             sd = self.staticdata
             result_type = self.jitdriver_sd.result_type
-            if result_type == history.VOID:
+            if result_type == resoperation.VOID:
                 assert resultbox is None
                 raise sd.DoneWithThisFrameVoid()
-            elif result_type == history.INT:
+            elif result_type == resoperation.INT:
                 raise sd.DoneWithThisFrameInt(resultbox.getint())
-            elif result_type == history.REF:
+            elif result_type == resoperation.REF:
                 raise sd.DoneWithThisFrameRef(self.cpu, resultbox.getref_base())
-            elif result_type == history.FLOAT:
+            elif result_type == resoperation.FLOAT:
                 raise sd.DoneWithThisFrameFloat(resultbox.getfloatstorage())
             else:
                 assert False
         # execute the operation
         profiler = self.staticdata.profiler
         profiler.count_ops(opnum)
-        resbox = executor.execute(self.cpu, self, opnum, descr, *argboxes)
-        if rop._ALWAYS_PURE_FIRST <= opnum <= rop._ALWAYS_PURE_LAST:
-            return self._record_helper_pure(opnum, resbox, descr, *argboxes)
-        else:
-            return self._record_helper_nonpure_varargs(opnum, resbox, descr,
-                                                       list(argboxes))
+        resop = executor.execute(self.cpu, self, opnum, descr, *argboxes)
+        if not resop.is_constant():
+            self._record(resop)
+        return resop
 
     @specialize.arg(1)
     def execute_and_record_varargs(self, opnum, argboxes, descr=None):
             resbox = self._record_helper_nonpure_varargs(opnum, resbox, descr, argboxes)
         return resbox
 
-    def _record_helper_pure(self, opnum, resbox, descr, *argboxes):
-        canfold = self._all_constants(*argboxes)
-        if canfold:
-            resbox = resbox.constbox()       # ensure it is a Const
-            return resbox
-        else:
-            resbox = resbox.nonconstbox()    # ensure it is a Box
-            return self._record_helper_nonpure_varargs(opnum, resbox, descr, list(argboxes))
-
     def _record_helper_pure_varargs(self, opnum, resbox, descr, argboxes):
         canfold = self._all_constants_varargs(argboxes)
         if canfold:
         self.attach_debug_info(op)
         return resbox
 
+    def _record(self, resop):
+        opnum = resop.getopnum()
+        if (rop._OVF_FIRST <= opnum <= rop._OVF_LAST and
+            self.last_exc_value_box is None and
+            resop.all_constant_args()):
+            return resop.constbox()
+        profiler = self.staticdata.profiler
+        profiler.count_ops(opnum, Counters.RECORDED_OPS)
+        self.heapcache.invalidate_caches(resop)
+        self.history.record(resop)
+        self.attach_debug_info(resop)
+        return resop
 
     def attach_debug_info(self, op):
         if (not we_are_translated() and op is not None
         # temporarily put a JUMP to a pseudo-loop
         sd = self.staticdata
         result_type = self.jitdriver_sd.result_type
-        if result_type == history.VOID:
+        if result_type == resoperation.VOID:
             assert exitbox is None
             exits = []
             loop_tokens = sd.loop_tokens_done_with_this_frame_void
-        elif result_type == history.INT:
+        elif result_type == resoperation.INT:
             exits = [exitbox]
             loop_tokens = sd.loop_tokens_done_with_this_frame_int
-        elif result_type == history.REF:
+        elif result_type == resoperation.REF:
             exits = [exitbox]
             loop_tokens = sd.loop_tokens_done_with_this_frame_ref
-        elif result_type == history.FLOAT:
+        elif result_type == resoperation.FLOAT:
             exits = [exitbox]
             loop_tokens = sd.loop_tokens_done_with_this_frame_float
         else:
         # FIXME: kill TerminatingLoopToken?
         # FIXME: can we call compile_trace?
         token = loop_tokens[0].finishdescr
-        self.history.record(rop.FINISH, exits, None, descr=token)
+        self.history.record(create_resop(rop.FINISH, exits, None, descr=token))
         target_token = compile.compile_trace(self, self.resumekey)
         if target_token is not token:
             compile.giveup()
             if self.debug:
                 print '\tpyjitpl: %s(%s)' % (name, ', '.join(map(repr, args))),
             try:
-                resultbox = unboundmethod(self, *args)
+                resultop = unboundmethod(self, *args)
             except Exception, e:
                 if self.debug:
                     print '-> %s!' % e.__class__.__name__
                 raise
-            if num_return_args == 0:
-                if self.debug:
-                    print
-                assert resultbox is None
-            else:
-                if self.debug:
-                    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 self.debug:
+                print resultop
+            assert argcodes[next_argcode] == '>'
+            result_argcode = argcodes[next_argcode + 1]
+            assert resultop.type == {'i': resoperation.INT,
+                                     'r': resoperation.REF,
+                                     'f': resoperation.FLOAT,
+                                     'v': resoperation.VOID}[result_argcode]
         else:
-            resultbox = unboundmethod(self, *args)
+            resultop = 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?'
+        self.make_result_of_lastop(resultop)
     #
     unboundmethod = getattr(MIFrame, 'opimpl_' + name).im_func
     argtypes = unrolling_iterable(unboundmethod.argtypes)

File pypy/jit/metainterp/resoperation.py

 from pypy.jit.codewriter import longlong
 from pypy.rlib.objectmodel import compute_identity_hash
 
+INT   = 'i'
+REF   = 'r'
+FLOAT = 'f'
+STRUCT = 's'
+VOID  = 'v'
+
 @specialize.arg(0)
-def ResOperation(opnum, args, result, descr=None):
+def create_resop(opnum, args, result, descr=None):
     cls = opclasses[opnum]
+    assert cls.NUMARGS == -1
+    if cls.is_always_pure():
+        for arg in args:
+            if not arg.is_constant():
+                break
+        else:
+            return cls.wrap_constant(result)
     if result is None:
         op = cls()
     else:
         op.setdescr(descr)
     return op
 
+@specialize.arg(0)
+def create_resop_0(opnum, result, descr=None):
+    cls = opclasses[opnum]
+    assert cls.NUMARGS == 0
+    if result is None:
+        op = cls()
+    else:
+        op = cls(result)
+    if descr is not None:
+        assert isinstance(op, ResOpWithDescr)
+        op.setdescr(descr)
+    return op
+
+@specialize.arg(0)
+def create_resop_1(opnum, arg0, result, descr=None):
+    cls = opclasses[opnum]
+    assert cls.NUMARGS == 1
+    if cls.is_always_pure():
+        if arg0.is_constant():
+            return cls.wrap_constant(result)
+    if result is None:
+        op = cls()
+    else:
+        op = cls(result)
+    op._arg0 = arg0
+    if descr is not None:
+        assert isinstance(op, ResOpWithDescr)
+        op.setdescr(descr)
+    return op
+
+@specialize.arg(0)
+def create_resop_2(opnum, arg0, arg1, result, descr=None):
+    cls = opclasses[opnum]
+    assert cls.NUMARGS == 2
+    if cls.is_always_pure():
+        if arg0.is_constant() and arg1.is_constant():
+            return cls.wrap_constant(result)
+    if result is None:
+        op = cls()
+    else:
+        op = cls(result)
+    op._arg0 = arg0
+    op._arg1 = arg1
+    if descr is not None:
+        assert isinstance(op, ResOpWithDescr)
+        op.setdescr(descr)
+    return op
+
+@specialize.arg(0)
+def create_resop_3(opnum, arg0, arg1, arg2, result, descr=None):
+    cls = opclasses[opnum]
+    assert cls.NUMARGS == 3
+    if cls.is_always_pure():
+        if arg0.is_constant() and arg1.is_constant() and arg2.is_constant():
+            return cls.wrap_constant(result)
+    if result is None:
+        op = cls()
+    else:
+        op = cls(result)
+    op._arg0 = arg0
+    op._arg1 = arg1
+    op._arg2 = arg2
+    if descr is not None:
+        assert isinstance(op, ResOpWithDescr)
+        op.setdescr(descr)
+    return op
+
+def copy_and_change(self, opnum, args=None, result=None, descr=None):
+    "shallow copy: the returned operation is meant to be used in place of self"
+    if args is None:
+        args = self.getarglist()
+    if result is None:
+        result = self.result
+    if descr is None:
+        descr = self.getdescr()
+    newop = ResOperation(opnum, args, result, descr)
+    return newop
+
 class AbstractValue(object):
     __slots__ = ()
 
     def same_box(self, other):
         return self is other
 
+    def is_constant(self):
+        return False
+
 class AbstractResOp(AbstractValue):
     """The central ResOperation class, representing one operation."""
 
     pc = 0
     opnum = 0
 
-    def getopnum(self):
-        return self.opnum
+    @classmethod
+    def getopnum(cls):
+        return cls.opnum
 
     # methods implemented by the arity mixins
     # ---------------------------------------
     def getdescr(self):
         return None
 
+    def getdescrclone(self):
+        return None
+
     def setdescr(self, descr):
         raise NotImplementedError
 
     # common methods
     # --------------
 
-    def copy_and_change(self, opnum, args=None, result=None, descr=None):
-        "shallow copy: the returned operation is meant to be used in place of self"
-        if args is None:
-            args = self.getarglist()
-        if result is None:
-            result = self.result
-        if descr is None:
-            descr = self.getdescr()
-        newop = ResOperation(opnum, args, result, descr)
-        return newop
-
-    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
-            op.pc = self.pc
-        return op
-
     def __repr__(self):
         try:
             return self.repr()
             return '%s%s%s(%s, descr=%r)' % (prefix, sres, self.getopname(),
                                              ', '.join([str(a) for a in args]), descr)
 
-    def getopname(self):
+    @classmethod
+    def getopname(cls):
         try:
-            return opname[self.getopnum()].lower()
+            return opname[cls.getopnum()].lower()
         except KeyError:
-            return '<%d>' % self.getopnum()
+            return '<%d>' % cls.getopnum()
 
-    def is_guard(self):
-        return rop._GUARD_FIRST <= self.getopnum() <= rop._GUARD_LAST
+    @classmethod
+    def is_guard(cls):
+        return rop._GUARD_FIRST <= cls.getopnum() <= rop._GUARD_LAST
 
-    def is_foldable_guard(self):
-        return rop._GUARD_FOLDABLE_FIRST <= self.getopnum() <= rop._GUARD_FOLDABLE_LAST
+    @classmethod
+    def is_foldable_guard(cls):
+        return rop._GUARD_FOLDABLE_FIRST <= cls.getopnum() <= rop._GUARD_FOLDABLE_LAST
 
-    def is_guard_exception(self):
-        return (self.getopnum() == rop.GUARD_EXCEPTION or
-                self.getopnum() == rop.GUARD_NO_EXCEPTION)
+    @classmethod
+    def is_guard_exception(cls):
+        return (cls.getopnum() == rop.GUARD_EXCEPTION or
+                cls.getopnum() == rop.GUARD_NO_EXCEPTION)
 
-    def is_guard_overflow(self):
-        return (self.getopnum() == rop.GUARD_OVERFLOW or
-                self.getopnum() == rop.GUARD_NO_OVERFLOW)
+    @classmethod
+    def is_guard_overflow(cls):
+        return (cls.getopnum() == rop.GUARD_OVERFLOW or
+                cls.getopnum() == rop.GUARD_NO_OVERFLOW)
 
-    def is_always_pure(self):
-        return rop._ALWAYS_PURE_FIRST <= self.getopnum() <= rop._ALWAYS_PURE_LAST
+    @classmethod
+    def is_always_pure(cls):
+        return rop._ALWAYS_PURE_FIRST <= cls.getopnum() <= rop._ALWAYS_PURE_LAST
 
-    def has_no_side_effect(self):
-        return rop._NOSIDEEFFECT_FIRST <= self.getopnum() <= rop._NOSIDEEFFECT_LAST
+    @classmethod
+    def has_no_side_effect(cls):
+        return rop._NOSIDEEFFECT_FIRST <= cls.getopnum() <= rop._NOSIDEEFFECT_LAST
 
-    def can_raise(self):
-        return rop._CANRAISE_FIRST <= self.getopnum() <= rop._CANRAISE_LAST
+    @classmethod
+    def can_raise(cls):
+        return rop._CANRAISE_FIRST <= cls.getopnum() <= rop._CANRAISE_LAST
 
-    def is_malloc(self):
+    @classmethod
+    def is_malloc(cls):
         # a slightly different meaning from can_malloc
-        return rop._MALLOC_FIRST <= self.getopnum() <= rop._MALLOC_LAST
+        return rop._MALLOC_FIRST <= cls.getopnum() <= rop._MALLOC_LAST
 
-    def can_malloc(self):
-        return self.is_call() or self.is_malloc()
+    @classmethod
+    def can_malloc(cls):
+        return cls.is_call() or cls.is_malloc()
 
-    def is_call(self):
-        return rop._CALL_FIRST <= self.getopnum() <= rop._CALL_LAST
+    @classmethod
+    def is_call(cls):
+        return rop._CALL_FIRST <= cls.getopnum() <= rop._CALL_LAST
 
-    def is_ovf(self):
-        return rop._OVF_FIRST <= self.getopnum() <= rop._OVF_LAST
+    @classmethod
+    def is_ovf(cls):
+        return rop._OVF_FIRST <= cls.getopnum() <= rop._OVF_LAST
 
-    def is_comparison(self):
-        return self.is_always_pure() and self.returns_bool_result()
+    @classmethod
+    def is_comparison(cls):
+        return cls.is_always_pure() and cls.returns_bool_result()
 
-    def is_final(self):
-        return rop._FINAL_FIRST <= self.getopnum() <= rop._FINAL_LAST
+    @classmethod
+    def is_final(cls):
+        return rop._FINAL_FIRST <= cls.getopnum() <= rop._FINAL_LAST
 
-    def returns_bool_result(self):
-        opnum = self.getopnum()
+    @classmethod
+    def returns_bool_result(cls):
+        opnum = cls.getopnum()
         if we_are_translated():
             assert opnum >= 0
         elif opnum < 0:
 
 class ResOpNone(object):
     _mixin_ = True
+    type = VOID
     
     def __init__(self):
         pass # no return value
 
+    def getresult(self):
+        return None
+
 class ResOpInt(object):
     _mixin_ = True
+    type = INT
     
     def __init__(self, intval):
         assert isinstance(intval, int)
 
     def getint(self):
         return self.intval
+    getresult = getint
+
+    @staticmethod
+    def wrap_constant(intval):
+        from pypy.jit.metainterp.history import ConstInt
+        return ConstInt(intval)
 
 class ResOpFloat(object):
     _mixin_ = True
+    type = FLOAT
     
     def __init__(self, floatval):
         #assert isinstance(floatval, float)
 
     def getfloatstorage(self):
         return self.floatval
+    getresult = getfloatstorage
+
+    @staticmethod
+    def wrap_constant(floatval):
+        from pypy.jit.metainterp.history import ConstFloat
+        return ConstFloat(floatval)
 
 class ResOpPointer(object):
     _mixin_ = True
+    type = REF
     
     def __init__(self, pval):
         assert typeOf(pval) == GCREF
 
     def getref_base(self):
         return self.pval
+    getresult = getref_base
+
+    @staticmethod
+    def wrap_constant(pval):
+        from pypy.jit.metainterp.history import ConstPtr
+        return ConstPtr(pval)
 
 # ===================
 # Top of the hierachy
     def getdescr(self):
         return self._descr
 
+    def getdescrclone(self):
+        return self._descr.clone_if_mutable()
+
     def setdescr(self, descr):
         # for 'call', 'new', 'getfield_gc'...: the descr is a prebuilt
         # instance provided by the backend holding details about the type
     def setfailargs(self, fail_args):
         self._fail_args = fail_args
 
-    def copy_and_change(self, opnum, args=None, result=None, descr=None):
-        newop = AbstractResOp.copy_and_change(self, opnum, args, result, descr)
-        newop.setfailargs(self.getfailargs())
-        return newop
-
-    def clone(self):
-        newop = AbstractResOp.clone(self)
-        newop.setfailargs(self.getfailargs())
-        return newop
-
 # ============
 # arity mixins
 # ============
 class NullaryOp(object):
     _mixin_ = True
 
+    NUMARGS = 0
+
     def initarglist(self, args):
         assert len(args) == 0
 
     def setarg(self, i, box):
         raise IndexError
 
+    def foreach_arg(self, func):
+        pass
+
+    def clone(self):
+        r = create_resop_0(self.opnum, self.getresult(), self.getdescrclone())
+        if self.is_guard():
+            r.setfailargs(self.getfailargs())
+        return r
 
 class UnaryOp(object):
     _mixin_ = True
     _arg0 = None
 
+    NUMARGS = 1
+
     def initarglist(self, args):
         assert len(args) == 1
         self._arg0, = args
         else:
             raise IndexError
 
+    @specialize.arg(1)
+    def foreach_arg(self, func):
+        func(self.getopnum(), 0, self._arg0)
+
+    def clone(self):
+        r = create_resop_1(self.opnum, self._arg0, self.getresult(),
+                              self.getdescrclone())
+        if self.is_guard():
+            r.setfailargs(self.getfailargs())
+        return r
 
 class BinaryOp(object):
     _mixin_ = True
     _arg0 = None
     _arg1 = None
 
+    NUMARGS = 2
+
     def initarglist(self, args):
         assert len(args) == 2
         self._arg0, self._arg1 = args
     def getarglist(self):
         return [self._arg0, self._arg1]
 
+    @specialize.arg(1)
+    def foreach_arg(self, func):
+        func(self.getopnum(), 0, self._arg0)
+        func(self.getopnum(), 1, self._arg1)
+
+    def clone(self):
+        r = create_resop_2(self.opnum, self._arg0, self._arg1,
+                           self.getresult(),  self.getdescrclone())
+        if self.is_guard():
+            r.setfailargs(self.getfailargs())
+        return r
+
 
 class TernaryOp(object):
     _mixin_ = True
     _arg1 = None
     _arg2 = None
 
+    NUMARGS = 3
+
     def initarglist(self, args):
         assert len(args) == 3
         self._arg0, self._arg1, self._arg2 = args
         else:
             raise IndexError
 
+    @specialize.arg(1)
+    def foreach_arg(self, func):
+        func(self.getopnum(), 0, self._arg0)
+        func(self.getopnum(), 1, self._arg1)
+        func(self.getopnum(), 2, self._arg2)
+
+    def clone(self):
+        assert not self.is_guard()
+        return create_resop_3(self.opnum, self._arg0, self._arg1, self._arg2,
+                              self.getresult(), self.getdescrclone())
+    
+
 class N_aryOp(object):
     _mixin_ = True
     _args = None
 
+    NUMARGS = -1
+
     def initarglist(self, args):
         self._args = args
 
     def setarg(self, i, box):
         self._args[i] = box
 
+    @specialize.arg(1)
+    def foreach_arg(self, func):
+        for i, arg in enumerate(self._args):
+            func(self.getopnum(), i, arg)
+
+    def clone(self):
+        assert not self.is_guard()
+        return create_resop(self.opnum, self._args[:], self.getresult(),
+                              self.getdescrclone())
+
 
 # ____________________________________________________________
 

File pypy/jit/metainterp/resume.py

 import sys, os
 from pypy.jit.metainterp.history import Box, Const, ConstInt, getkind
 from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat
-from pypy.jit.metainterp.history import INT, REF, FLOAT, HOLE
+from pypy.jit.metainterp.resoperation import INT, REF, FLOAT
 from pypy.jit.metainterp.history import AbstractDescr
 from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.metainterp import jitprof

File pypy/jit/metainterp/test/test_resoperation.py

 from pypy.jit.metainterp import resoperation as rop
 from pypy.jit.metainterp.history import AbstractDescr
 
+class FakeBox(object):
+    def __init__(self, v):
+        self.v = v
+
+    def __eq__(self, other):
+        return self.v == other.v
+
+    def __ne__(self, other):
+        return not self == other
+    
+    def is_constant(self):
+        return False
+
 def test_arity_mixins():
     cases = [
         (0, rop.NullaryOp),
 def test_instantiate():
     from pypy.rpython.lltypesystem import lltype, llmemory
     
-    op = rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 15)
-    assert op.getarglist() == ['a', 'b']
+    op = rop.create_resop_2(rop.rop.INT_ADD, FakeBox('a'), FakeBox('b'), 15)
+    assert op.getarglist() == [FakeBox('a'), FakeBox('b')]
     assert op.getint() == 15
 
     mydescr = AbstractDescr()
-    op = rop.ResOperation(rop.rop.CALL_f, ['a', 'b'], 15.5, descr=mydescr)
-    assert op.getarglist() == ['a', 'b']
+    op = rop.create_resop(rop.rop.CALL_f, [FakeBox('a'),
+                                           FakeBox('b')], 15.5, descr=mydescr)
+    assert op.getarglist() == [FakeBox('a'), FakeBox('b')]
     assert op.getfloat() == 15.5
     assert op.getdescr() is mydescr
 
-    op = rop.ResOperation(rop.rop.CALL_p, ['a', 'b'],
+    op = rop.create_resop(rop.rop.CALL_p, [FakeBox('a'), FakeBox('b')],
                           lltype.nullptr(llmemory.GCREF.TO), descr=mydescr)
-    assert op.getarglist() == ['a', 'b']
+    assert op.getarglist() == [FakeBox('a'), FakeBox('b')]
     assert not op.getref_base()
     assert op.getdescr() is mydescr    
 
 
     mydescr = AbstractDescr()
     p = lltype.malloc(llmemory.GCREF.TO)
-    assert rop.ResOperation(rop.rop.NEW, [], p).can_malloc()
-    call = rop.ResOperation(rop.rop.CALL_i, ['a', 'b'], 3, descr=mydescr)
+    assert rop.create_resop_0(rop.rop.NEW, p).can_malloc()
+    call = rop.create_resop(rop.rop.CALL_i, [FakeBox('a'),
+                                             FakeBox('b')], 3, descr=mydescr)
     assert call.can_malloc()
-    assert not rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 3).can_malloc()
+    assert not rop.create_resop_2(rop.rop.INT_ADD, FakeBox('a'),
+                                  FakeBox('b'), 3).can_malloc()
 
 def test_get_deep_immutable_oplist():
-    ops = [rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 3)]
+    ops = [rop.create_resop_2(rop.rop.INT_ADD, FakeBox('a'), FakeBox('b'), 3)]
     newops = rop.get_deep_immutable_oplist(ops)
     py.test.raises(TypeError, "newops.append('foobar')")
     py.test.raises(TypeError, "newops[0] = 'foobar'")
     py.test.raises(AssertionError, "newops[0].setarg(0, 'd')")
     py.test.raises(AssertionError, "newops[0].setdescr('foobar')")
+
+def test_clone():
+    mydescr = AbstractDescr()
+    op = rop.create_resop_0(rop.rop.GUARD_NO_EXCEPTION, None, descr=mydescr)
+    op.setfailargs([3])
+    op2 = op.clone()
+    assert not op2 is op
+    assert op2.getresult() is None
+    assert op2.getfailargs() is op.getfailargs()
+    op = rop.create_resop_1(rop.rop.INT_IS_ZERO, FakeBox('a'), 1)
+    op2 = op.clone()
+    assert op2 is not op
+    assert op2._arg0 == FakeBox('a')
+    assert op2.getint() == 1
+    op = rop.create_resop_2(rop.rop.INT_ADD, FakeBox('a'), FakeBox('b'), 1)
+    op2 = op.clone()
+    assert op2 is not op
+    assert op2._arg0 == FakeBox('a')
+    assert op2._arg1 == FakeBox('b')
+    assert op2.getint() == 1
+    op = rop.create_resop_3(rop.rop.STRSETITEM, FakeBox('a'), FakeBox('b'),
+                            FakeBox('c'), None)
+    op2 = op.clone()
+    assert op2 is not op
+    assert op2._arg0 == FakeBox('a')
+    assert op2._arg1 == FakeBox('b')
+    assert op2._arg2 == FakeBox('c')
+    assert op2.getresult() is None
+    op = rop.create_resop(rop.rop.CALL_i, [FakeBox('a'), FakeBox('b'),
+                            FakeBox('c')], 13, descr=mydescr)
+    op2 = op.clone()
+    assert op2 is not op
+    assert op2._args == [FakeBox('a'), FakeBox('b'), FakeBox('c')]
+    assert op2.getint() == 13