[pypy-svn] r34817 - in pypy/dist/pypy: jit/hintannotator jit/timeshifter jit/timeshifter/test rpython/lltypesystem

arigo at codespeak.net arigo at codespeak.net
Tue Nov 21 00:11:11 CET 2006


Author: arigo
Date: Tue Nov 21 00:11:03 2006
New Revision: 34817

Added:
   pypy/dist/pypy/jit/timeshifter/test/test_vdict.py   (contents, props changed)
   pypy/dist/pypy/jit/timeshifter/vdict.py   (contents, props changed)
Modified:
   pypy/dist/pypy/jit/hintannotator/model.py
   pypy/dist/pypy/jit/timeshifter/oop.py
   pypy/dist/pypy/jit/timeshifter/vlist.py
   pypy/dist/pypy/rpython/lltypesystem/rdict.py
Log:
(pedronis, arigo)

Starting oopspec'ed dict support.  As usual, kind of easy but a lot of
mess to get correctly typed while still avoiding total specialization
explosion.


Modified: pypy/dist/pypy/jit/hintannotator/model.py
==============================================================================
--- pypy/dist/pypy/jit/hintannotator/model.py	(original)
+++ pypy/dist/pypy/jit/hintannotator/model.py	Tue Nov 21 00:11:03 2006
@@ -576,6 +576,8 @@
     operation_name, args = ll_func.oopspec.split('(', 1)
     assert args.endswith(')')
     args = args[:-1] + ','     # trailing comma to force tuple syntax
+    if args.strip() == ',':
+        args = '()'
     argnames = ll_func.func_code.co_varnames[:len(args_hs)]
     d = dict(zip(argnames, args_hs))
     argtuple = eval(args, d)

Modified: pypy/dist/pypy/jit/timeshifter/oop.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/oop.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/oop.py	Tue Nov 21 00:11:03 2006
@@ -22,6 +22,8 @@
         operation_name, args = ll_func.oopspec.split('(', 1)
         assert args.endswith(')')
         args = args[:-1] + ','     # trailing comma to force tuple syntax
+        if args.strip() == ',':
+            args = '()'
         argnames = ll_func.func_code.co_varnames[:nb_args]
         d = dict(zip(argnames, [Index(n) for n in range(nb_args)]))
         self.argtuple = eval(args, d)
@@ -55,6 +57,10 @@
             typename, method = 'list', 'oop_newlist'
             SELFTYPE = FUNCTYPE.RESULT.TO
             self.is_method = False
+        elif operation_name == 'newdict':
+            typename, method = 'dict', 'oop_newdict'
+            SELFTYPE = FUNCTYPE.RESULT.TO
+            self.is_method = False
         else:
             typename, method = operation_name.split('.')
             method = 'oop_%s_%s' % (typename, method)

Added: pypy/dist/pypy/jit/timeshifter/test/test_vdict.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/jit/timeshifter/test/test_vdict.py	Tue Nov 21 00:11:03 2006
@@ -0,0 +1,19 @@
+from pypy.annotation.policy import AnnotatorPolicy
+from pypy.jit.timeshifter.test.test_timeshift import TimeshiftingTests
+
+P_OOPSPEC = AnnotatorPolicy()
+P_OOPSPEC.novirtualcontainer = True
+P_OOPSPEC.oopspec = True
+
+
+class TestVDict(TimeshiftingTests):
+
+    def test_vdict(self):
+        def ll_function():
+            dic = {}
+            dic[12] = 34
+            dic[13] = 35
+            return dic[12]
+        res = self.timeshift(ll_function, [], [], policy=P_OOPSPEC)
+        assert res == 34
+        self.check_insns({})

Added: pypy/dist/pypy/jit/timeshifter/vdict.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/jit/timeshifter/vdict.py	Tue Nov 21 00:11:03 2006
@@ -0,0 +1,253 @@
+import operator
+from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.lltypesystem import rdict
+from pypy.jit.timeshifter.rcontainer import AbstractContainer, cachedtype
+from pypy.jit.timeshifter import rvalue
+from pypy.rlib.objectmodel import r_dict
+
+HASH = lltype.Signed
+
+
+class LLEqDesc(object):
+    __metaclass__ = cachedtype
+
+    def __init__(self, KEY, keyeq, keyhash):
+        # this makes one version of the following function per KEY,
+        # which is supposed to be the ll type of x and y
+
+        def lleq(x, y):
+            return keyeq(x, y)
+        def llhash(x):
+            return keyhash(x)
+
+        class VirtualDict(AbstractVirtualDict):
+
+            def make_item_boxes(self):
+                self.item_boxes = r_dict(lleq, llhash)
+
+            def getboxes(self):
+                return self.item_boxes.values()
+
+            def getitems_and_makeempty(self, rgenop):
+                result = [(rgenop.genconst(key), box, llhash(key))
+                          for key, box in self.item_boxes.iteritems()]
+                self.item_boxes = None
+                return result
+
+            def getitem(self, keybox):
+                key = rvalue.ll_getvalue(keybox, KEY)
+                return self.item_boxes[key]
+
+            def setitem(self, keybox, valuebox):
+                key = rvalue.ll_getvalue(keybox, KEY)
+                self.item_boxes[key] = valuebox
+
+            def copy_from(self, other, memo):
+                assert isinstance(other, VirtualDict)
+                self.make_item_boxes()
+                for key, valuebox in other.item_boxes.iteritems():
+                    self.item_boxes[key] = valuebox.copy(memo)
+
+            def replace(self, memo):
+                changes = []
+                for key, valuebox in self.item_boxes.iteritems():
+                    newbox = valuebox.replace(memo)
+                    if newbox is not valuebox:
+                        changes.append((key, newbox))
+                for key, newbox in changes:
+                    self.item_boxes[key] = newbox
+
+
+        class FrozenVirtualDict(AbstractFrozenVirtualDict):
+
+            def freeze_from(self, vdict, memo):
+                assert isinstance(vdict, VirtualDict)
+                frozens = []
+                for key, valuebox in vdict.item_boxes.iteritems():
+                    frozens.append((key, valuebox.freeze(memo)))
+                self.fz_item_boxes = frozens
+
+            def same_keys_as(self, vdict, boxes):
+                assert isinstance(vdict, VirtualDict)
+                self_boxes = self.fz_item_boxes
+                vdict_boxes = vdict.item_boxes
+                if len(self_boxes) != len(vdict_boxes):
+                    return False
+                for key, selfbox in self_boxes:
+                    try:
+                        vdictbox = vdict_boxes[key]
+                    except KeyError:
+                        return False
+                    boxes.append((selfbox, vdictbox))
+                return True
+
+
+        self.VirtualDict = VirtualDict
+        self.FrozenVirtualDict = FrozenVirtualDict
+
+        VirtualDict.FrozenVirtualDict = FrozenVirtualDict
+
+
+class DictTypeDesc(object):
+    __metaclass__ = cachedtype
+
+    def __init__(self, hrtyper, DICT):
+        RGenOp = hrtyper.RGenOp
+        rtyper = hrtyper.rtyper
+        bk = rtyper.annotator.bookkeeper
+        self.DICT = DICT
+        self.DICTPTR = lltype.Ptr(DICT)
+        self.ptrkind = RGenOp.kindToken(self.DICTPTR)
+
+        argtypes = [bk.immutablevalue(DICT)]
+        ll_newdict_ptr = rtyper.annotate_helper_fn(rdict.ll_newdict,
+                                                   argtypes)
+        self.gv_ll_newdict = RGenOp.constPrebuiltGlobal(ll_newdict_ptr)
+        self.tok_ll_newdict = RGenOp.sigToken(lltype.typeOf(ll_newdict_ptr).TO)
+
+        argtypes = [self.DICTPTR, DICT.KEY, DICT.VALUE, HASH]
+        ll_insertclean = rtyper.annotate_helper_fn(rdict.ll_dict_insertclean,
+                                                    argtypes)
+        self.gv_ll_insertclean = RGenOp.constPrebuiltGlobal(ll_insertclean)
+        self.tok_ll_insertclean = RGenOp.sigToken(
+            lltype.typeOf(ll_insertclean).TO)
+
+        # XXX some fishing that only works if the DICT does not come from
+        # an r_dict
+        if DICT.keyeq is None:
+            keyeq = operator.eq
+        else:
+            assert isinstance(DICT.keyeq, lltype.staticAdtMethod)
+            keyeq = DICT.keyeq.__get__(42)
+        assert isinstance(DICT.keyhash, lltype.staticAdtMethod)
+        keyhash = DICT.keyhash.__get__(42)
+        keydesc = LLEqDesc(DICT.KEY, keyeq, keyhash)
+        self.VirtualDict = keydesc.VirtualDict
+
+    def _freeze_(self):
+        return True
+
+    def factory(self):
+        vdict = self.VirtualDict(self)
+        box = rvalue.PtrRedBox(self.ptrkind)
+        box.content = vdict
+        vdict.ownbox = box
+        return box
+
+TypeDesc = DictTypeDesc
+
+
+class AbstractFrozenVirtualDict(AbstractContainer):
+    __slots__ = ('typedesc',)
+
+    def __init__(self, typedesc):
+        self.typedesc = typedesc
+        #self.fz_item_boxes initialized later
+
+    def exactmatch(self, vdict, outgoingvarboxes, memo):
+        assert isinstance(vdict, AbstractVirtualDict)
+        contmemo = memo.containers
+        if self in contmemo:
+            ok = vdict is contmemo[self]
+            if not ok:
+                outgoingvarboxes.append(vdict.ownbox)
+            return ok
+        if vdict in contmemo:
+            assert contmemo[vdict] is not self
+            outgoingvarboxes.append(vdict.ownbox)
+            return False
+        assert self.typedesc is vdict.typedesc
+        boxes = []
+        if not self.same_keys_as(vdict, boxes):
+            outgoingvarboxes.append(vdict.ownbox)
+            return False
+        contmemo[self] = vdict
+        contmemo[vdict] = self
+        fullmatch = True
+        for selfbox, vdictbox in boxes:
+            if not selfbox.exactmatch(vdictbox,
+                                      outgoingvarboxes,
+                                      memo):
+                fullmatch = False
+        return fullmatch
+
+
+class AbstractVirtualDict(AbstractContainer):
+    __slots__ = ('typedesc', 'ownbox')     # and no item_boxes
+
+    def __init__(self, typedesc):
+        self.typedesc = typedesc
+        self.make_item_boxes()
+        # self.ownbox = ...    set in factory()
+
+    def enter_block(self, incoming, memo):
+        contmemo = memo.containers
+        if self not in contmemo:
+            contmemo[self] = None
+            for box in self.getboxes():
+                box.enter_block(incoming, memo)
+
+    def force_runtime_container(self, builder):
+        typedesc = self.typedesc
+        items = self.getitems_and_makeempty(builder.rgenop)
+
+        args_gv = [None]
+        gv_dict = builder.genop_call(typedesc.tok_ll_newdict,
+                                     typedesc.gv_ll_newdict,
+                                     args_gv)
+        self.ownbox.genvar = gv_dict
+        self.ownbox.content = None
+        for gv_key, valuebox, hash in items:
+            gv_hash = builder.rgenop.genconst(hash)
+            gv_value = valuebox.getgenvar(builder)
+            args_gv = [gv_dict, gv_key, gv_value, gv_hash]
+            builder.genop_call(typedesc.tok_ll_insertclean,
+                               typedesc.gv_ll_insertclean,
+                               args_gv)
+
+    def freeze(self, memo):
+        contmemo = memo.containers
+        try:
+            return contmemo[self]
+        except KeyError:
+            result = contmemo[self] = self.FrozenVirtualDict(self.typedesc)
+            result.freeze_from(self, memo)
+            return result
+
+    def copy(self, memo):
+        contmemo = memo.containers
+        try:
+            return contmemo[self]
+        except KeyError:
+            result = contmemo[self] = self.__class__(self.typedesc)
+            result.copy_from(self, memo)
+            result.ownbox = self.ownbox.copy(memo)
+            return result
+
+    def replace(self, memo):
+        contmemo = memo.containers
+        if self not in contmemo:
+            contmemo[self] = None
+            self.replace(memo)
+            self.ownbox = self.ownbox.replace(memo)
+
+
+def oop_newdict(jitstate, oopspecdesc):
+    return oopspecdesc.typedesc.factory()
+
+def oop_dict_setitem(jitstate, oopspecdesc, selfbox, keybox, valuebox):
+    content = selfbox.content
+    if isinstance(content, AbstractVirtualDict) and keybox.is_constant():
+        content.setitem(keybox, valuebox)
+    else:
+        oopspecdesc.residual_call(jitstate, [selfbox, keybox, valuebox])
+
+def oop_dict_getitem(jitstate, oopspecdesc, selfbox, keybox):
+    content = selfbox.content
+    if isinstance(content, AbstractVirtualDict) and keybox.is_constant():
+        try:
+            return content.getitem(keybox)
+        except KeyError:
+            return oopspecdesc.residual_exception(jitstate, KeyError)
+    else:
+        return oopspecdesc.residual_call(jitstate, [selfbox, keybox])

Modified: pypy/dist/pypy/jit/timeshifter/vlist.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/vlist.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/vlist.py	Tue Nov 21 00:11:03 2006
@@ -26,6 +26,9 @@
         self.tok_ll_setitem_fast = RGenOp.sigToken(
             lltype.typeOf(ll_setitem_fast).TO)
 
+    def _freeze_(self):
+        return True
+
     def factory(self, length, itembox):
         vlist = VirtualList(self, length, itembox)
         box = rvalue.PtrRedBox(self.ptrkind)

Modified: pypy/dist/pypy/rpython/lltypesystem/rdict.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rdict.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/rdict.py	Tue Nov 21 00:11:03 2006
@@ -170,6 +170,8 @@
                     'keyeq':    ll_keyeq,
                     'paranoia': False,
                     }
+            adtmeths['KEY']   = self.DICTKEY
+            adtmeths['VALUE'] = self.DICTVALUE
             self.DICT.become(lltype.GcStruct("dicttable", adtmeths=adtmeths,
                                              *fields))
 
@@ -394,6 +396,7 @@
         return entry.value 
     else: 
         raise KeyError 
+ll_dict_getitem.oopspec = 'dict.getitem(d, key)'
 
 def ll_dict_setitem(d, key, value):
     hash = d.keyhash(key)
@@ -414,6 +417,7 @@
         d.num_pristine_entries -= 1
         if d.num_pristine_entries <= len(d.entries) / 3:
             ll_dict_resize(d)
+ll_dict_setitem.oopspec = 'dict.setitem(d, key, value)'
 
 def ll_dict_insertclean(d, key, value, hash):
     # Internal routine used by ll_dict_resize() to insert an item which is
@@ -554,6 +558,7 @@
     d.num_items = 0
     d.num_pristine_entries = DICT_INITSIZE
     return d
+ll_newdict.oopspec = 'newdict()'
 
 def ll_newdict_size(DICT, length_estimate):
     length_estimate = (length_estimate // 2) * 3
@@ -565,6 +570,7 @@
     d.num_items = 0
     d.num_pristine_entries = DICT_INITSIZE
     return d
+ll_newdict_size.oopspec = 'newdict()'
 
 
 def rtype_r_dict(hop):



More information about the Pypy-commit mailing list