[pypy-svn] r64783 - in pypy/branch/pyjitpl5/pypy: jit/metainterp jit/metainterp/test rpython rpython/lltypesystem rpython/ootypesystem

arigo at codespeak.net arigo at codespeak.net
Tue Apr 28 16:52:45 CEST 2009


Author: arigo
Date: Tue Apr 28 16:52:44 2009
New Revision: 64783

Modified:
   pypy/branch/pyjitpl5/pypy/jit/metainterp/support.py
   pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_dict.py
   pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/rdict.py
   pypy/branch/pyjitpl5/pypy/rpython/ootypesystem/rdict.py
   pypy/branch/pyjitpl5/pypy/rpython/rdict.py
Log:
Refactor oopspec's of dictionaries to support keys(),
values(), items(), iterkeys(), itervalues(), iteritems().
Really add a test, which shows that the previous solution
was just translating but not working correctly.


Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/support.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/support.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/support.py	Tue Apr 28 16:52:44 2009
@@ -132,6 +132,8 @@
 _ll_2_list_getitem_foldable = _ll_2_list_getitem
 _ll_1_list_len_foldable     = _ll_1_list_len
 
+# ---------- dict ----------
+
 def _ll_0_newdict(DICT):
     return rdict.ll_newdict(DICT)
 _ll_0_newdict.need_result_type = True
@@ -142,19 +144,37 @@
 _ll_3_dict_setdefault = rdict.ll_setdefault
 _ll_2_dict_contains = rdict.ll_contains
 _ll_3_dict_get = rdict.ll_get
-def _ll_1_newdictiter(ITERPTR, d):
-    return rdict.ll_dictiter(lltype.Ptr(ITERPTR), d)
-_ll_1_newdictiter.need_result_type = True
-def _ll_2_dictiter_dictnext(RESULTTYPE, dic, func):
-    return rdict.ll_dictnext(dic, func, RESULTTYPE)
-_ll_2_dictiter_dictnext.need_result_type = True
-def _ll_2_newdictkvi(LIST, dic, func):
-    return rdict.ll_kvi(dic, LIST, func)
-_ll_2_newdictkvi.need_result_type = True
 _ll_1_dict_copy = rdict.ll_copy
 _ll_1_dict_clear = rdict.ll_clear
 _ll_2_dict_update = rdict.ll_update
 
+# ---------- dict keys(), values(), items(), iter ----------
+
+_ll_1_dict_keys   = rdict.ll_dict_keys
+_ll_1_dict_values = rdict.ll_dict_values
+_ll_1_dict_items  = rdict.ll_dict_items
+_ll_1_dict_keys  .need_result_type = True
+_ll_1_dict_values.need_result_type = True
+_ll_1_dict_items .need_result_type = True
+
+def _ll_1_newdictiter(ITER, d):
+    return rdict.ll_dictiter(lltype.Ptr(ITER), d)
+_ll_1_newdictiter.need_result_type = True
+
+_dictnext_keys   = rdict.ll_dictnext_group['keys']
+_dictnext_values = rdict.ll_dictnext_group['values']
+_dictnext_items  = rdict.ll_dictnext_group['items']
+
+def _ll_1_dictiter_nextkeys(iter):
+    return _dictnext_keys(None, iter)
+def _ll_1_dictiter_nextvalues(iter):
+    return _dictnext_values(None, iter)
+def _ll_1_dictiter_nextitems(RES, iter):
+    return _dictnext_items(lltype.Ptr(RES), iter)
+_ll_1_dictiter_nextitems.need_result_type = True
+
+# ---------- strings and unicode ----------
+
 _ll_5_string_copy_contents = rstr.copy_string_contents
 
 _ll_1_str_str2unicode = rstr.LLHelpers.ll_str2unicode

Modified: pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_dict.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_dict.py	(original)
+++ pypy/branch/pyjitpl5/pypy/jit/metainterp/test/test_dict.py	Tue Apr 28 16:52:44 2009
@@ -4,27 +4,60 @@
 
 class DictTests:
 
-    def test_basic_dict(self):
-        py.test.skip("in-progress")
-        myjitdriver = JitDriver(greens = [], reds = ['n', 'dct'])
+    def test_dict_keys_values_items(self):
+        for name, extract, expected in [('keys', None, 'k'),
+                                        ('values', None, 'v'),
+                                        ('items', 0, 'k'),
+                                        ('items', 1, 'v'),
+                                        ]:
+            myjitdriver = JitDriver(greens = [], reds = ['n', 'dct'])
+            def f(n):
+                dct = {}
+                while n > 0:
+                    myjitdriver.can_enter_jit(n=n, dct=dct)
+                    myjitdriver.jit_merge_point(n=n, dct=dct)
+                    dct[n] = n*n
+                    n -= 1
+                sum = 0
+                for x in getattr(dct, name)():
+                    if extract is not None:
+                        x = x[extract]
+                    sum += x
+                return sum
+
+            if expected == 'k':
+                expected = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10
+            else:
+                expected = 1 + 4 + 9 + 16 + 25 + 36 + 49 + 64 + 81 + 100
+
+            assert f(10) == expected
+            res = self.meta_interp(f, [10], listops=True)
+            assert res == expected
+
+    def test_dict_iter(self):
+        myjitdriver = JitDriver(greens = [], reds = ['total', 'it'])
         def f(n):
-            dct = {}
-            while n > 0:
-                myjitdriver.can_enter_jit(n=n, dct=dct)
-                myjitdriver.jit_merge_point(n=n, dct=dct)
-                dct[n] = n*n
-                n -= 1
-            sum = 0
-            for i in dct.values():
-                sum += i
-            return sum
-        assert f(10) == 1 + 4 + 9 + 16 + 25 + 36 + 49 + 64 + 81 + 100
+            dct = {n: 100, 50: n+1}
+            it = dct.iterkeys()
+            total = 0
+            while True:
+                myjitdriver.can_enter_jit(total=total, it=it)
+                myjitdriver.jit_merge_point(total=total, it=it)
+                try:
+                    total += it.next()
+                except StopIteration:
+                    break
+            return total
+
+        assert f(10) == 60
         res = self.meta_interp(f, [10], listops=True)
-        assert res == 1 + 4 + 9 + 16 + 25 + 36 + 49 + 64 + 81 + 100
+        assert res == 60
 
 
 class TestOOtype(DictTests, OOJitMixin):
-    def test_basic_dict(self):
+    def test_dict_keys_values_items(self):
+        py.test.skip("implement me")
+    def test_dict_iter(self):
         py.test.skip("implement me")
 
 class TestLLtype(DictTests, LLJitMixin):

Modified: pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/rdict.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/rdict.py	(original)
+++ pypy/branch/pyjitpl5/pypy/rpython/lltypesystem/rdict.py	Tue Apr 28 16:52:44 2009
@@ -2,7 +2,7 @@
 from pypy.annotation import model as annmodel
 from pypy.objspace.flow.model import Constant
 from pypy.rpython.rdict import AbstractDictRepr, AbstractDictIteratorRepr,\
-     rtype_newdict, dum_variant, dum_keys, dum_values, dum_items
+     rtype_newdict
 from pypy.rpython.lltypesystem import lltype
 from pypy.rlib.rarithmetic import r_uint, intmask
 from pypy.rlib.objectmodel import hlinvoke
@@ -273,22 +273,21 @@
         hop.exception_cannot_occur()
         return hop.gendirectcall(ll_update, v_dic1, v_dic2)
 
-    def _rtype_method_kvi(self, hop, spec):
+    def _rtype_method_kvi(self, hop, ll_func):
         v_dic, = hop.inputargs(self)
         r_list = hop.r_result
-        v_func = hop.inputconst(lltype.Void, spec)
         cLIST = hop.inputconst(lltype.Void, r_list.lowleveltype.TO)
         hop.exception_cannot_occur()
-        return hop.gendirectcall(ll_kvi, v_dic, cLIST, v_func)
+        return hop.gendirectcall(ll_func, cLIST, v_dic)
 
     def rtype_method_keys(self, hop):
-        return self._rtype_method_kvi(hop, dum_keys)
+        return self._rtype_method_kvi(hop, ll_dict_keys)
 
     def rtype_method_values(self, hop):
-        return self._rtype_method_kvi(hop, dum_values)
+        return self._rtype_method_kvi(hop, ll_dict_values)
 
     def rtype_method_items(self, hop):
-        return self._rtype_method_kvi(hop, dum_items)
+        return self._rtype_method_kvi(hop, ll_dict_items)
 
     def rtype_method_iterkeys(self, hop):
         hop.exception_cannot_occur()
@@ -422,7 +421,6 @@
     else: 
         raise KeyError 
 ll_dict_getitem.oopspec = 'dict.getitem(d, key)'
-ll_dict_getitem.oopargcheck = lambda d, key: bool(d)
 
 def ll_dict_setitem(d, key, value):
     hash = d.keyhash(key)
@@ -651,7 +649,7 @@
                                          ('dict', r_dict.lowleveltype),
                                          ('index', lltype.Signed)))
         self.ll_dictiter = ll_dictiter
-        self.ll_dictnext = ll_dictnext
+        self.ll_dictnext = ll_dictnext_group[variant]
 
 
 def ll_dictiter(ITERPTR, d):
@@ -661,33 +659,41 @@
     return iter
 ll_dictiter.oopspec = 'newdictiter(d)'
 
-def ll_dictnext(iter, func, RETURNTYPE):
-    dict = iter.dict
-    if dict:
-        entries = dict.entries
-        index = iter.index
-        entries_len = len(entries)
-        while index < entries_len:
-            entry = entries[index]
-            is_valid = entries.valid(index)
-            index = index + 1
-            if is_valid:
-                iter.index = index
-                if RETURNTYPE is lltype.Void:
-                    return None
-                elif func is dum_items:
-                    r = lltype.malloc(RETURNTYPE.TO)
-                    r.item0 = recast(RETURNTYPE.TO.item0, entry.key)
-                    r.item1 = recast(RETURNTYPE.TO.item1, entry.value)
-                    return r
-                elif func is dum_keys:
-                    return entry.key
-                elif func is dum_values:
-                    return entry.value
-        # clear the reference to the dict and prevent restarts
-        iter.dict = lltype.nullptr(lltype.typeOf(iter).TO.dict.TO)
-    raise StopIteration
-ll_dictnext.oopspec = 'dictiter.dictnext(iter, func)'
+def _make_ll_dictnext(kind):
+    # make three versions of the following function: keys, values, items
+    def ll_dictnext(RETURNTYPE, iter):
+        # note that RETURNTYPE is None for keys and values
+        dict = iter.dict
+        if dict:
+            entries = dict.entries
+            index = iter.index
+            entries_len = len(entries)
+            while index < entries_len:
+                entry = entries[index]
+                is_valid = entries.valid(index)
+                index = index + 1
+                if is_valid:
+                    iter.index = index
+                    if RETURNTYPE is lltype.Void:
+                        return None
+                    elif kind == 'items':
+                        r = lltype.malloc(RETURNTYPE.TO)
+                        r.item0 = recast(RETURNTYPE.TO.item0, entry.key)
+                        r.item1 = recast(RETURNTYPE.TO.item1, entry.value)
+                        return r
+                    elif kind == 'keys':
+                        return entry.key
+                    elif kind == 'values':
+                        return entry.value
+            # clear the reference to the dict and prevent restarts
+            iter.dict = lltype.nullptr(lltype.typeOf(iter).TO.dict.TO)
+        raise StopIteration
+    ll_dictnext.oopspec = 'dictiter.next%s(iter)' % kind
+    return ll_dictnext
+
+ll_dictnext_group = {'keys'  : _make_ll_dictnext('keys'),
+                     'values': _make_ll_dictnext('values'),
+                     'items' : _make_ll_dictnext('items')}
 
 # _____________________________________________________________
 # methods
@@ -766,35 +772,40 @@
     else:
         return v
 
-def ll_kvi(dic, LIST, func):
-    res = LIST.ll_newlist(dic.num_items)
-    entries = dic.entries
-    dlen = len(entries)
-    items = res.ll_items()
-    i = 0
-    p = 0
-    while i < dlen:
-        if entries.valid(i):
-            ELEM = lltype.typeOf(items).TO.OF
-            if ELEM is not lltype.Void:
-                entry = entries[i]
-                if func is dum_items:
-                    r = lltype.malloc(ELEM.TO)
-                    r.item0 = recast(ELEM.TO.item0, entry.key)
-                    r.item1 = recast(ELEM.TO.item1, entry.value)
-                    items[p] = r
-                elif func is dum_keys:
-                    items[p] = recast(ELEM, entry.key)
-                elif func is dum_values:
-                    items[p] = recast(ELEM, entry.value)
-            p += 1
-        i += 1
-    assert p == res.ll_length()
-    return res
-ll_kvi.oopspec = 'newdictkvi(dic, func)'
+def _make_ll_keys_values_items(kind):
+    def ll_kvi(LIST, dic):
+        res = LIST.ll_newlist(dic.num_items)
+        entries = dic.entries
+        dlen = len(entries)
+        items = res.ll_items()
+        i = 0
+        p = 0
+        while i < dlen:
+            if entries.valid(i):
+                ELEM = lltype.typeOf(items).TO.OF
+                if ELEM is not lltype.Void:
+                    entry = entries[i]
+                    if kind == 'items':
+                        r = lltype.malloc(ELEM.TO)
+                        r.item0 = recast(ELEM.TO.item0, entry.key)
+                        r.item1 = recast(ELEM.TO.item1, entry.value)
+                        items[p] = r
+                    elif kind == 'keys':
+                        items[p] = recast(ELEM, entry.key)
+                    elif kind == 'values':
+                        items[p] = recast(ELEM, entry.value)
+                p += 1
+            i += 1
+        assert p == res.ll_length()
+        return res
+    ll_kvi.oopspec = 'dict.%s(dic)' % kind
+    return ll_kvi
+
+ll_dict_keys   = _make_ll_keys_values_items('keys')
+ll_dict_values = _make_ll_keys_values_items('values')
+ll_dict_items  = _make_ll_keys_values_items('items')
 
 def ll_contains(d, key):
     i = ll_dict_lookup(d, key, d.keyhash(key))
     return d.entries.valid(i)
 ll_contains.oopspec = 'dict.contains(d, key)'
-ll_contains.oopargcheck = lambda d, key: bool(d)

Modified: pypy/branch/pyjitpl5/pypy/rpython/ootypesystem/rdict.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/rpython/ootypesystem/rdict.py	(original)
+++ pypy/branch/pyjitpl5/pypy/rpython/ootypesystem/rdict.py	Tue Apr 28 16:52:44 2009
@@ -3,7 +3,7 @@
 from pypy.annotation import model as annmodel
 from pypy.objspace.flow.model import Constant
 from pypy.rpython.rdict import AbstractDictRepr, AbstractDictIteratorRepr,\
-     rtype_newdict, dum_variant, dum_keys, dum_values, dum_items
+     rtype_newdict
 from pypy.rpython.rpbc import MethodOfFrozenPBCRepr,\
      AbstractFunctionsPBCRepr, AbstractMethodsPBCRepr
 from pypy.rpython.ootypesystem import ootype
@@ -121,21 +121,20 @@
         return hop.gendirectcall(ll_dict_update, v_dict1, v_dict2)
 
     def rtype_method_keys(self, hop):
-        return self._rtype_method_kvi(hop, dum_keys)
+        return self._rtype_method_kvi(hop, ll_dict_keys)
 
     def rtype_method_values(self, hop):
-        return self._rtype_method_kvi(hop, dum_values)
+        return self._rtype_method_kvi(hop, ll_dict_values)
 
     def rtype_method_items(self, hop):
-        return self._rtype_method_kvi(hop, dum_items)
+        return self._rtype_method_kvi(hop, ll_dict_items)
 
-    def _rtype_method_kvi(self, hop, spec):
+    def _rtype_method_kvi(self, hop, ll_func):
         v_dict, = hop.inputargs(self)
         r_list = hop.r_result
         cLIST = hop.inputconst(ootype.Void, r_list.lowleveltype)
-        c_func = hop.inputconst(ootype.Void, spec)
         hop.exception_cannot_occur()
-        return hop.gendirectcall(ll_dict_kvi, v_dict, cLIST, c_func)
+        return hop.gendirectcall(ll_func, cLIST, v_dict)
 
     def rtype_method_iterkeys(self, hop):
         hop.exception_cannot_occur()
@@ -321,25 +320,31 @@
         d.ll_set(key, default)
         return default
 
-def ll_dict_kvi(d, LIST, func):
-    length = d.ll_length()
-    result = LIST.ll_newlist(length)
-    it = d.ll_get_items_iterator()
-    i = 0
-    while it.ll_go_next():
-        if func is dum_keys:
-            result.ll_setitem_fast(i, it.ll_current_key())
-        elif func is dum_values:
-            result.ll_setitem_fast(i, it.ll_current_value())
-        if func is dum_items:
-            r = ootype.new(LIST.ITEM)
-            r.item0 = it.ll_current_key()   # TODO: do we need casting?
-            r.item1 = it.ll_current_value()
-            result.ll_setitem_fast(i, r)
-        i += 1
-    assert i == length
-    return result
-
+def _make_ll_keys_values_items(kind):
+    def ll_dict_kvi(LIST, d):
+        length = d.ll_length()
+        result = LIST.ll_newlist(length)
+        it = d.ll_get_items_iterator()
+        i = 0
+        while it.ll_go_next():
+            if kind == 'keys':
+                result.ll_setitem_fast(i, it.ll_current_key())
+            elif kind == 'values':
+                result.ll_setitem_fast(i, it.ll_current_value())
+            elif kind == 'items':
+                r = ootype.new(LIST.ITEM)
+                r.item0 = it.ll_current_key()   # TODO: do we need casting?
+                r.item1 = it.ll_current_value()
+                result.ll_setitem_fast(i, r)
+            i += 1
+        assert i == length
+        return result
+    ll_dict_kvi.oopspec = 'dict.%s(d)' % kind
+    return ll_dict_kvi
+
+ll_dict_keys   = _make_ll_keys_values_items('keys')
+ll_dict_values = _make_ll_keys_values_items('values')
+ll_dict_items  = _make_ll_keys_values_items('items')
 
 # ____________________________________________________________
 #
@@ -352,7 +357,7 @@
         self.variant = variant
         self.lowleveltype = self._get_type()
         self.ll_dictiter = ll_dictiter
-        self.ll_dictnext = ll_dictnext
+        self.ll_dictnext = ll_dictnext_group[variant]
 
     def _get_type(self):
         KEYTYPE = self.r_dict.key_repr.lowleveltype
@@ -365,18 +370,26 @@
     iter.iterator = d.ll_get_items_iterator()
     return iter
 
-def ll_dictnext(iter, func, RETURNTYPE):
-    it = iter.iterator
-    if not it.ll_go_next():
-        raise StopIteration
-
-    if func is dum_keys:
-        return it.ll_current_key()
-    elif func is dum_values:
-        return it.ll_current_value()
-    elif func is dum_items:
-        res = ootype.new(RETURNTYPE)
-        res.item0 = it.ll_current_key()
-        res.item1 = it.ll_current_value()
-        return res
-
+def _make_ll_dictnext(kind):
+    # make three versions of the following function: keys, values, items
+    def ll_dictnext(RETURNTYPE, iter):
+        # note that RETURNTYPE is None for keys and values
+        it = iter.iterator
+        if not it.ll_go_next():
+            raise StopIteration
+
+        if kind == 'keys':
+            return it.ll_current_key()
+        elif kind == 'values':
+            return it.ll_current_value()
+        elif kind == 'items':
+            res = ootype.new(RETURNTYPE)
+            res.item0 = it.ll_current_key()
+            res.item1 = it.ll_current_value()
+            return res
+    ll_dictnext.oopspec = 'dictiter.next%s(iter)' % kind
+    return ll_dictnext
+
+ll_dictnext_group = {'keys'  : _make_ll_dictnext('keys'),
+                     'values': _make_ll_dictnext('values'),
+                     'items' : _make_ll_dictnext('items')}

Modified: pypy/branch/pyjitpl5/pypy/rpython/rdict.py
==============================================================================
--- pypy/branch/pyjitpl5/pypy/rpython/rdict.py	(original)
+++ pypy/branch/pyjitpl5/pypy/rpython/rdict.py	Tue Apr 28 16:52:44 2009
@@ -8,13 +8,6 @@
 from pypy.rlib import objectmodel
 from pypy.rpython import rmodel
 
-def dum_keys(): pass
-def dum_values(): pass
-def dum_items():pass
-dum_variant = {"keys":   dum_keys,
-               "values": dum_values,
-               "items":  dum_items}
-
 
 class __extend__(annmodel.SomeDict):
     def rtyper_makerepr(self, rtyper):
@@ -92,7 +85,6 @@
     def rtype_next(self, hop):
         variant = self.variant
         v_iter, = hop.inputargs(self)
-        v_func = hop.inputconst(lltype.Void, dum_variant[self.variant])
         if variant in ('keys', 'values'):
             c1 = hop.inputconst(lltype.Void, None)
         else:
@@ -101,7 +93,7 @@
         hop.has_implicit_exception(StopIteration)
         hop.has_implicit_exception(RuntimeError)
         hop.exception_is_here()
-        v = hop.gendirectcall(self.ll_dictnext, v_iter, v_func, c1)
+        v = hop.gendirectcall(self.ll_dictnext, c1, v_iter)
         if variant == 'keys':
             return self.r_dict.recast_key(hop.llops, v)
         elif variant == 'values':



More information about the Pypy-commit mailing list