[pypy-svn] r77196 - in pypy/branch/resoperation-refactoring/pypy/jit/metainterp: . optimizeopt test
antocuni at codespeak.net
antocuni at codespeak.net
Mon Sep 20 12:21:18 CEST 2010
Author: antocuni
Date: Mon Sep 20 12:21:16 2010
New Revision: 77196
Added:
pypy/branch/resoperation-refactoring/pypy/jit/metainterp/test/test_resoperation.py (contents, props changed)
Modified:
pypy/branch/resoperation-refactoring/pypy/jit/metainterp/optimizeopt/virtualize.py
pypy/branch/resoperation-refactoring/pypy/jit/metainterp/resoperation.py
pypy/branch/resoperation-refactoring/pypy/jit/metainterp/test/oparser.py
pypy/branch/resoperation-refactoring/pypy/jit/metainterp/test/test_optimizeopt.py
Log:
complete the refactoring, and create a class for each operation
Modified: pypy/branch/resoperation-refactoring/pypy/jit/metainterp/optimizeopt/virtualize.py
==============================================================================
--- pypy/branch/resoperation-refactoring/pypy/jit/metainterp/optimizeopt/virtualize.py (original)
+++ pypy/branch/resoperation-refactoring/pypy/jit/metainterp/optimizeopt/virtualize.py Mon Sep 20 12:21:16 2010
@@ -292,7 +292,7 @@
for i in range(len(specnodes)):
value = self.getvalue(op.getarg(i))
specnodes[i].teardown_virtual_node(self, value, exitargs)
- op.setarglist(exitargs[:])
+ op = op.copy_and_change(op.getopnum(), args=exitargs[:])
self.emit_operation(op)
def optimize_VIRTUAL_REF(self, op):
Modified: pypy/branch/resoperation-refactoring/pypy/jit/metainterp/resoperation.py
==============================================================================
--- pypy/branch/resoperation-refactoring/pypy/jit/metainterp/resoperation.py (original)
+++ pypy/branch/resoperation-refactoring/pypy/jit/metainterp/resoperation.py Mon Sep 20 12:21:16 2010
@@ -2,101 +2,91 @@
from pypy.rlib.debug import make_sure_not_resized
def ResOperation(opnum, args, result, descr=None):
- return BaseResOperation(opnum, args, result, descr)
+ cls = opclasses[opnum]
+ op = cls(result)
+ op.initarglist(args)
+ if descr is not None:
+ assert isinstance(op, ResOpWithDescr)
+ op.setdescr(descr)
+ return op
-class BaseResOperation(object):
- """The central ResOperation class, representing one operation."""
- __slots__ = ['_fail_args', '_opnum', '_args', 'result', '_descr',
- 'name', 'pc', '_exc_box', '__weakref__']
+class AbstractResOp(object):
+ """The central ResOperation class, representing one operation."""
# debug
- ## name = ""
- ## pc = 0
+ name = ""
+ pc = 0
- def __init__(self, opnum, args, result, descr=None):
- make_sure_not_resized(args)
- assert isinstance(opnum, int)
- self._opnum = opnum
- self._args = list(args)
- make_sure_not_resized(self._args)
- assert not isinstance(result, list)
+ def __init__(self, result):
self.result = result
- self.setdescr(descr)
-
- self._fail_args = None
- self.pc = 0
- self.name = ''
- ## def __init__(self, result):
- ## self.result = result
+ # methods implemented by each concrete class
+ # ------------------------------------------
+
+ def getopnum(self):
+ raise NotImplementedError
- 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)
- #if isinstance(self, GuardOperation)
- newop.setfailargs(self.getfailargs())
- return newop
+ # methods implemented by the arity mixins
+ # ---------------------------------------
- def getopnum(self):
- return self._opnum
- #raise NotImplementedError
+ def initarglist(self, args):
+ "This is supposed to be called only just after the ResOp has been created"
+ raise NotImplementedError
+
+ def getarglist(self):
+ raise NotImplementedError
def getarg(self, i):
- return self._args[i]
- #raise NotImplementedError
+ raise NotImplementedError
def setarg(self, i, box):
- self._args[i] = box
- #raise NotImplementedError
+ raise NotImplementedError
def numargs(self):
- return len(self._args)
- #raise NotImplementedError
+ raise NotImplementedError
- def setarglist(self, args):
- # XXX: is it really needed?
- self._args = args
- #raise NotImplementedError
- def getarglist(self):
- return self._args
- #raise NotImplementedError
+ # methods implemented by GuardResOp
+ # ---------------------------------
def getfailargs(self):
- return self._fail_args
- #raise NotImplementedError
+ return None
def setfailargs(self, fail_args):
- self._fail_args = fail_args
+ raise NotImplementedError
+
+ # methods implemented by ResOpWithDescr
+ # -------------------------------------
def getdescr(self):
- return self._descr
+ return None
- def setdescr(self, descr):
- # for 'call', 'new', 'getfield_gc'...: the descr is a prebuilt
- # instance provided by the backend holding details about the type
- # of the operation. It must inherit from AbstractDescr. The
- # backend provides it with cpu.fielddescrof(), cpu.arraydescrof(),
- # cpu.calldescrof(), and cpu.typedescrof().
- from pypy.jit.metainterp.history import check_descr
- check_descr(descr)
- self._descr = descr
+ def setdescr(self):
+ 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):
- descr = self._descr
+ args = self.getarglist()
+ descr = self.getdescr()
if descr is not None:
descr = descr.clone_if_mutable()
- op = ResOperation(self.getopnum(), self._args, self.result, descr)
- op._fail_args = self._fail_args
- op.name = self.name
+ op = ResOperation(self.getopnum(), args, self.result, descr)
if not we_are_translated():
+ op.name = self.name
op.pc = self.pc
return op
@@ -113,12 +103,14 @@
prefix = "%s:%s " % (self.name, self.pc)
else:
prefix = ""
- if self.getdescr() is None or we_are_translated():
+ args = self.getarglist()
+ descr = self.getdescr()
+ if descr is None or we_are_translated():
return '%s%s%s(%s)' % (prefix, sres, self.getopname(),
- ', '.join([str(a) for a in self._args]))
+ ', '.join([str(a) for a in args]))
else:
return '%s%s%s(%s, descr=%r)' % (prefix, sres, self.getopname(),
- ', '.join([str(a) for a in self._args]), self._descr)
+ ', '.join([str(a) for a in args]), descr)
def getopname(self):
try:
@@ -167,30 +159,215 @@
return opboolresult[opnum]
+# ===================
+# Top of the hierachy
+# ===================
+
+class PlainResOp(AbstractResOp):
+ pass
+
+class ResOpWithDescr(AbstractResOp):
+
+ _descr = None
+
+ def getdescr(self):
+ return self._descr
+
+ def setdescr(self, descr):
+ # for 'call', 'new', 'getfield_gc'...: the descr is a prebuilt
+ # instance provided by the backend holding details about the type
+ # of the operation. It must inherit from AbstractDescr. The
+ # backend provides it with cpu.fielddescrof(), cpu.arraydescrof(),
+ # cpu.calldescrof(), and cpu.typedescrof().
+ from pypy.jit.metainterp.history import check_descr
+ check_descr(descr)
+ self._descr = descr
+
+class GuardResOp(ResOpWithDescr):
+
+ _fail_args = None
+
+ def getfailargs(self):
+ return self._fail_args
+
+ 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
+
+ def initarglist(self, args):
+ assert len(args) == 0
+
+ def getarglist(self):
+ return []
+
+ def numargs(self):
+ return 0
+
+ def getarg(self, i):
+ raise IndexError
+
+ def setarg(self, i, box):
+ raise IndexError
+
+
+class UnaryOp(object):
+ _mixin_ = True
+ _arg0 = None
+
+ def initarglist(self, args):
+ assert len(args) == 1
+ self._arg0, = args
+
+ def getarglist(self):
+ return [self._arg0]
+
+ def numargs(self):
+ return 1
+
+ def getarg(self, i):
+ if i == 0:
+ return self._arg0
+ else:
+ raise IndexError
+
+ def setarg(self, i, box):
+ if i == 0:
+ self._arg0 = box
+ else:
+ raise IndexError
+
+
+class BinaryOp(object):
+ _mixin_ = True
+ _arg0 = None
+ _arg1 = None
+
+ def initarglist(self, args):
+ assert len(args) == 2
+ self._arg0, self._arg1 = args
+
+ def getarglist(self):
+ return [self._arg0, self._arg1, self._arg2]
+
+ def numargs(self):
+ return 2
+
+ def getarg(self, i):
+ if i == 0:
+ return self._arg0
+ elif i == 1:
+ return self._arg1
+ else:
+ raise IndexError
+
+ def setarg(self, i, box):
+ if i == 0:
+ self._arg0 = box
+ elif i == 1:
+ self._arg1 = box
+ else:
+ raise IndexError
+
+ def getarglist(self):
+ return [self._arg0, self._arg1]
+
+
+class TernaryOp(object):
+ _mixin_ = True
+ _arg0 = None
+ _arg1 = None
+ _arg2 = None
+
+ def initarglist(self, args):
+ assert len(args) == 3
+ self._arg0, self._arg1, self._arg2 = args
+
+ def getarglist(self):
+ return [self._arg0, self._arg1, self._arg2]
+
+ def numargs(self):
+ return 3
+
+ def getarg(self, i):
+ if i == 0:
+ return self._arg0
+ elif i == 1:
+ return self._arg1
+ elif i == 2:
+ return self._arg2
+ else:
+ raise IndexError
+
+ def setarg(self, i, box):
+ if i == 0:
+ self._arg0 = box
+ elif i == 1:
+ self._arg1 = box
+ elif i == 2:
+ self._arg2 = box
+ else:
+ raise IndexError
+
+class N_aryOp(object):
+ _mixin_ = True
+ _args = None
+
+ def initarglist(self, args):
+ self._args = args
+
+ def getarglist(self):
+ return self._args
+
+ def numargs(self):
+ return len(self._args)
+
+ def getarg(self, i):
+ return self._args[i]
+
+ def setarg(self, i, box):
+ self._args[i] = box
+
# ____________________________________________________________
_oplist = [
'_FINAL_FIRST',
- 'JUMP',
- 'FINISH',
+ 'JUMP/*d',
+ 'FINISH/*d',
'_FINAL_LAST',
'_GUARD_FIRST',
'_GUARD_FOLDABLE_FIRST',
- 'GUARD_TRUE',
- 'GUARD_FALSE',
- 'GUARD_VALUE',
- 'GUARD_CLASS',
- 'GUARD_NONNULL',
- 'GUARD_ISNULL',
- 'GUARD_NONNULL_CLASS',
+ 'GUARD_TRUE/1d',
+ 'GUARD_FALSE/1d',
+ 'GUARD_VALUE/2d',
+ 'GUARD_CLASS/2d',
+ 'GUARD_NONNULL/1d',
+ 'GUARD_ISNULL/1d',
+ 'GUARD_NONNULL_CLASS/2d',
'_GUARD_FOLDABLE_LAST',
- 'GUARD_NO_EXCEPTION',
- 'GUARD_EXCEPTION',
- 'GUARD_NO_OVERFLOW',
- 'GUARD_OVERFLOW',
- 'GUARD_NOT_FORCED',
+ 'GUARD_NO_EXCEPTION/0d',
+ 'GUARD_EXCEPTION/1d',
+ 'GUARD_NO_OVERFLOW/0d',
+ 'GUARD_OVERFLOW/0d',
+ 'GUARD_NOT_FORCED/0d',
'_GUARD_LAST', # ----- end of guard operations -----
'_NOSIDEEFFECT_FIRST', # ----- start of no_side_effect operations -----
@@ -279,18 +456,18 @@
'UNICODESETITEM/3',
'NEWUNICODE/1',
#'RUNTIMENEW/1', # ootype operation
- 'COND_CALL_GC_WB', # [objptr, newvalue] (for the write barrier)
+ 'COND_CALL_GC_WB/2d', # [objptr, newvalue] (for the write barrier)
'DEBUG_MERGE_POINT/1', # debugging only
'VIRTUAL_REF_FINISH/2', # removed before it's passed to the backend
'_CANRAISE_FIRST', # ----- start of can_raise operations -----
- 'CALL',
- 'CALL_ASSEMBLER',
- 'CALL_MAY_FORCE',
- 'CALL_LOOPINVARIANT',
+ 'CALL/*d',
+ 'CALL_ASSEMBLER/*d',
+ 'CALL_MAY_FORCE/*d',
+ 'CALL_LOOPINVARIANT/*d',
#'OOSEND', # ootype operation
#'OOSEND_PURE', # ootype operation
- 'CALL_PURE', # removed before it's passed to the backend
+ 'CALL_PURE/*d', # removed before it's passed to the backend
# CALL_PURE(result, func, arg_1,..,arg_n)
'_CANRAISE_LAST', # ----- end of can_raise operations -----
@@ -307,6 +484,7 @@
class rop(object):
pass
+opclasses = [] # mapping numbers to the concrete ResOp class
opname = {} # mapping numbers to the original names, for debugging
oparity = [] # mapping numbers to the arity of the operation or -1
opwithdescr = [] # mapping numbers to a flag "takes a descr"
@@ -321,16 +499,50 @@
name, arity = name.split('/')
withdescr = 'd' in arity
boolresult = 'b' in arity
- arity = int(arity.rstrip('db'))
+ arity = arity.rstrip('db')
+ if arity == '*':
+ arity = -1
+ else:
+ arity = int(arity)
else:
arity, withdescr, boolresult = -1, True, False # default
setattr(rop, name, i)
if not name.startswith('_'):
opname[i] = name
+ cls = create_class_for_op(name, i, arity, withdescr)
+ else:
+ cls = None
+ opclasses.append(cls)
oparity.append(arity)
opwithdescr.append(withdescr)
opboolresult.append(boolresult)
- assert len(oparity)==len(opwithdescr)==len(opboolresult)==len(_oplist)
+ assert len(opclasses)==len(oparity)==len(opwithdescr)==len(opboolresult)==len(_oplist)
+
+def create_class_for_op(name, opnum, arity, withdescr):
+ arity2mixin = {
+ 0: NullaryOp,
+ 1: UnaryOp,
+ 2: BinaryOp,
+ 3: TernaryOp
+ }
+
+ is_guard = name.startswith('GUARD')
+ if is_guard:
+ assert withdescr
+ baseclass = GuardResOp
+ elif withdescr:
+ baseclass = ResOpWithDescr
+ else:
+ baseclass = PlainResOp
+ mixin = arity2mixin.get(arity, N_aryOp)
+
+ def getopnum(self):
+ return opnum
+
+ cls_name = '%s_OP' % name
+ bases = (mixin, baseclass)
+ dic = {'getopnum': getopnum}
+ return type(cls_name, bases, dic)
setup(__name__ == '__main__') # print out the table when run directly
del _oplist
Modified: pypy/branch/resoperation-refactoring/pypy/jit/metainterp/test/oparser.py
==============================================================================
--- pypy/branch/resoperation-refactoring/pypy/jit/metainterp/test/oparser.py (original)
+++ pypy/branch/resoperation-refactoring/pypy/jit/metainterp/test/oparser.py Mon Sep 20 12:21:16 2010
@@ -6,7 +6,7 @@
from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt,\
ConstObj, ConstPtr, Box, BasicFailDescr, BoxFloat, ConstFloat,\
LoopToken
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop, ResOperation, ResOpWithDescr, N_aryOp
from pypy.jit.metainterp.typesystem import llhelper
from pypy.jit.codewriter.heaptracker import adr2int
from pypy.rpython.lltypesystem import lltype, llmemory
@@ -16,10 +16,22 @@
class ParseError(Exception):
pass
-
class Boxes(object):
pass
+class ESCAPE_OP(N_aryOp, ResOpWithDescr):
+
+ OPNUM = -123
+
+ def __init__(self, opnum, args, result, descr=None):
+ assert opnum == self.OPNUM
+ self.result = result
+ self.initarglist(args)
+ self.setdescr(descr)
+
+ def getopnum(self):
+ return self.OPNUM
+
class ExtendedTreeLoop(TreeLoop):
def getboxes(self):
@@ -171,7 +183,7 @@
opnum = getattr(rop, opname.upper())
except AttributeError:
if opname == 'escape':
- opnum = -123
+ opnum = ESCAPE_OP.OPNUM
else:
raise ParseError("unknown op: %s" % opname)
endnum = line.rfind(')')
@@ -228,6 +240,12 @@
descr = self.looptoken
return opnum, args, descr, fail_args
+ def create_op(self, opnum, args, result, descr):
+ if opnum == ESCAPE_OP.OPNUM:
+ return ESCAPE_OP(opnum, args, result, descr)
+ else:
+ return ResOperation(opnum, args, result, descr)
+
def parse_result_op(self, line):
res, op = line.split("=", 1)
res = res.strip()
@@ -237,14 +255,16 @@
raise ParseError("Double assign to var %s in line: %s" % (res, line))
rvar = self.box_for_var(res)
self.vars[res] = rvar
- res = ResOperation(opnum, args, rvar, descr)
- res.setfailargs(fail_args)
+ res = self.create_op(opnum, args, rvar, descr)
+ if fail_args is not None:
+ res.setfailargs(fail_args)
return res
def parse_op_no_result(self, line):
opnum, args, descr, fail_args = self.parse_op(line)
- res = ResOperation(opnum, args, None, descr)
- res.setfailargs(fail_args)
+ res = self.create_op(opnum, args, None, descr)
+ if fail_args is not None:
+ res.setfailargs(fail_args)
return res
def parse_next_op(self, line):
Modified: pypy/branch/resoperation-refactoring/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/resoperation-refactoring/pypy/jit/metainterp/test/test_optimizeopt.py (original)
+++ pypy/branch/resoperation-refactoring/pypy/jit/metainterp/test/test_optimizeopt.py Mon Sep 20 12:21:16 2010
@@ -42,7 +42,7 @@
opt = optimizeopt.Optimizer(FakeMetaInterpStaticData(LLtypeMixin.cpu),
None)
fdescr = ResumeGuardDescr(None, None)
- op = ResOperation(rop.GUARD_TRUE, [], None, descr=fdescr)
+ op = ResOperation(rop.GUARD_TRUE, ['dummy'], None, descr=fdescr)
# setup rd data
fi0 = resume.FrameInfo(None, "code0", 11)
fdescr.rd_frame_info_list = resume.FrameInfo(fi0, "code1", 33)
Added: pypy/branch/resoperation-refactoring/pypy/jit/metainterp/test/test_resoperation.py
==============================================================================
--- (empty file)
+++ pypy/branch/resoperation-refactoring/pypy/jit/metainterp/test/test_resoperation.py Mon Sep 20 12:21:16 2010
@@ -0,0 +1,54 @@
+import py
+from pypy.jit.metainterp import resoperation as rop
+from pypy.jit.metainterp.history import AbstractDescr
+
+def test_arity_mixins():
+ cases = [
+ (0, rop.NullaryOp),
+ (1, rop.UnaryOp),
+ (2, rop.BinaryOp),
+ (3, rop.TernaryOp),
+ (9, rop.N_aryOp)
+ ]
+
+ def test_case(n, cls):
+ obj = cls()
+ obj.initarglist(range(n))
+ assert obj.getarglist() == range(n)
+ for i in range(n):
+ obj.setarg(i, i*2)
+ assert obj.numargs() == n
+ for i in range(n):
+ assert obj.getarg(i) == i*2
+ py.test.raises(IndexError, obj.getarg, n+1)
+ py.test.raises(IndexError, obj.setarg, n+1, 0)
+
+ for n, cls in cases:
+ test_case(n, cls)
+
+def test_concrete_classes():
+ cls = rop.opclasses[rop.rop.INT_ADD]
+ assert issubclass(cls, rop.PlainResOp)
+ assert issubclass(cls, rop.BinaryOp)
+ assert cls.getopnum.im_func(None) == rop.rop.INT_ADD
+
+ cls = rop.opclasses[rop.rop.CALL]
+ assert issubclass(cls, rop.ResOpWithDescr)
+ assert issubclass(cls, rop.N_aryOp)
+ assert cls.getopnum.im_func(None) == rop.rop.CALL
+
+ cls = rop.opclasses[rop.rop.GUARD_TRUE]
+ assert issubclass(cls, rop.GuardResOp)
+ assert issubclass(cls, rop.UnaryOp)
+ assert cls.getopnum.im_func(None) == rop.rop.GUARD_TRUE
+
+def test_instantiate():
+ op = rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 'c')
+ assert op.getarglist() == ['a', 'b']
+ assert op.result == 'c'
+
+ mydescr = AbstractDescr()
+ op = rop.ResOperation(rop.rop.CALL, ['a', 'b'], 'c', descr=mydescr)
+ assert op.getarglist() == ['a', 'b']
+ assert op.result == 'c'
+ assert op.getdescr() is mydescr
More information about the Pypy-commit
mailing list