[pypy-commit] pypy type-specialized-instances: introduced IntAttribute

l.diekmann noreply at buildbot.pypy.org
Fri Nov 18 14:42:27 CET 2011


Author: Lukas Diekmann <lukas.diekmann at uni-duesseldorf.de>
Branch: type-specialized-instances
Changeset: r49522:b16fead0c3f3
Date: 2011-11-16 18:24 +0100
http://bitbucket.org/pypy/pypy/changeset/b16fead0c3f3/

Log:	introduced IntAttribute

diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -125,15 +125,15 @@
         return None
 
     @jit.elidable
-    def _get_new_attr(self, name, index):
-        selector = name, index
+    def _get_new_attr(self, name, index, attrclass):
+        key = name, index, attrclass
         cache = self.cache_attrs
         if cache is None:
             cache = self.cache_attrs = {}
-        attr = cache.get(selector, None)
+        attr = cache.get(key, None)
         if attr is None:
-            attr = PlainAttribute(selector, self)
-            cache[selector] = attr
+            attr = attrclass(key, self)
+            cache[key] = attr
         return attr
 
     @jit.look_inside_iff(lambda self, obj, selector, w_value:
@@ -141,8 +141,9 @@
             jit.isconstant(selector[0]) and
             jit.isconstant(selector[1]))
     def add_attr(self, obj, selector, w_value):
+        attrclass = get_attrclass_from_value(self.space, w_value)
         # grumble, jit needs this
-        attr = self._get_new_attr(selector[0], selector[1])
+        attr = self._get_new_attr(selector[0], selector[1], attrclass)
         oldattr = obj._get_mapdict_map()
         if not jit.we_are_jitted():
             size_est = (oldattr._size_estimate + attr.size_estimate()
@@ -264,8 +265,10 @@
             terminator = terminator.devolved_dict_terminator
         return Terminator.set_terminator(self, obj, terminator)
 
-class PlainAttribute(AbstractAttribute):
+class AbstractStoredAttribute(AbstractAttribute):
+
     _immutable_fields_ = ['selector', 'position', 'back']
+
     def __init__(self, selector, back):
         AbstractAttribute.__init__(self, back.space, back.terminator)
         self.selector = selector
@@ -277,17 +280,6 @@
         w_value = self.read(obj, self.selector)
         new_obj._get_mapdict_map().add_attr(new_obj, self.selector, w_value)
 
-    def read_attr(self, obj):
-        # XXX do the unerasing (and wrapping) here
-        erased = obj._mapdict_read_storage(self.position)
-        w_value = unerase_item(erased)
-        return w_value
-
-    def write_attr(self, obj, w_value):
-        # XXX do the unerasing (and unwrapping) here
-        erased = erase_item(w_value)
-        obj._mapdict_write_storage(self.position, erased)
-
     def delete(self, obj, selector):
         if selector == self.selector:
             # ok, attribute is deleted
@@ -333,6 +325,41 @@
     def __repr__(self):
         return "<PlainAttribute %s %s %r>" % (self.selector, self.position, self.back)
 
+class PlainAttribute(AbstractStoredAttribute):
+
+    erase_item, unerase_item = rerased.new_erasing_pair("mapdict storage object item")
+    erase_item = staticmethod(erase_item)
+    unerase_item = staticmethod(unerase_item)
+
+    def read_attr(self, obj):
+        erased = obj._mapdict_read_storage(self.position)
+        w_value = self.unerase_item(erased)
+        return w_value
+
+    def write_attr(self, obj, w_value):
+        erased = self.erase_item(w_value)
+        obj._mapdict_write_storage(self.position, erased)
+
+class IntAttribute(AbstractStoredAttribute):
+
+    erase_item, unerase_item = rerased.erase_int, rerased.unerase_int
+    erase_item = staticmethod(erase_item)
+    unerase_item = staticmethod(unerase_item)
+
+    def read_attr(self, obj):
+        erased = obj._mapdict_read_storage(self.position)
+        value = self.unerase_item(erased)
+        return self.space.wrap(value)
+
+    def write_attr(self, obj, w_value):
+        erased = self.erase_item(self.space.int_w(w_value))
+        obj._mapdict_write_storage(self.position, erased)
+
+def get_attrclass_from_value(space, w_value):
+    if space.is_w(space.type(w_value), space.w_int):
+        return IntAttribute
+    return PlainAttribute
+
 def _become(w_obj, new_obj):
     # this is like the _become method, really, but we cannot use that due to
     # RPython reasons
@@ -524,7 +551,6 @@
 memo_get_subclass_of_correct_size._annspecialcase_ = "specialize:memo"
 _subclass_cache = {}
 
-erase_item, unerase_item = rerased.new_erasing_pair("mapdict storage item")
 erase_list, unerase_list = rerased.new_erasing_pair("mapdict storage list")
 
 def _make_subclass_size_n(supercls, n):
diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py
--- a/pypy/objspace/std/test/test_mapdict.py
+++ b/pypy/objspace/std/test/test_mapdict.py
@@ -5,12 +5,14 @@
 space = FakeSpace()
 
 class Class(object):
-    def __init__(self, hasdict=True):
+    def __init__(self, hasdict=True, sp=None):
         self.hasdict = True
+        if sp is None:
+            sp = space
         if hasdict:
-            self.terminator = DictTerminator(space, self)
+            self.terminator = DictTerminator(sp, self)
         else:
-            self.terminator = NoDictTerminator(space, self)
+            self.terminator = NoDictTerminator(sp, self)
 
     def instantiate(self, sp=None):
         if sp is None:
@@ -24,10 +26,10 @@
         hasdict = False
 
 def erase_storage_items(items):
-    return [erase_item(item) for item in items]
+    return [IntAttribute.erase_item(item) for item in items]
 
 def unerase_storage_items(storage):
-    return [unerase_item(item) for item in storage]
+    return [IntAttribute.unerase_item(item) for item in storage]
 
 def test_plain_attribute():
 
@@ -247,7 +249,6 @@
     assert obj.getdict(space) is obj.getdict(space)
     assert obj.getdict(space).length() == 3
 
-
 def test_materialize_r_dict():
     cls = Class()
     obj = cls.instantiate()
@@ -301,6 +302,50 @@
                 obj.setdictvalue(space, a, 50)
         assert c.terminator.size_estimate() in [(i + 10) // 2, (i + 11) // 2]
 
+class TestTypeSpecializedAttributes(object):
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{"objspace.std.withmapdict": True})
+
+    def test_attributes(self):
+        space = self.space
+        cls = Class(sp=space)
+        obj1 = cls.instantiate()
+        obj1.setdictvalue(space, "x", space.wrap(1))
+        #assert space.eq_w(obj1.getdictvalue(space, "x"), space.wrap(1))
+
+        obj2 = cls.instantiate()
+        w_str = space.wrap("string")
+        obj2.setdictvalue(space, "x", w_str)
+        #assert space.eq_w(obj1.getdictvalue(space, "x"), w_str)
+
+        assert obj1.map is not obj2.map
+        assert isinstance(obj1.map, IntAttribute)
+
+        obj3 = cls.instantiate()
+        obj3.setdictvalue(space, "x", space.wrap(5))
+
+        assert obj1.map is obj3.map
+
+        assert IntAttribute.unerase_item(obj1.storage[0]) == 1
+        assert PlainAttribute.unerase_item(obj2.storage[0]) == w_str
+
+    def test_add_more_attributes(self):
+        space = self.space
+        cls = Class(sp=space)
+
+        obj1 = cls.instantiate()
+        obj1.setdictvalue(space, "x", space.wrap(1))
+        obj1.setdictvalue(space, "y", space.wrap(2))
+
+    def test_switch_attribute_types(self):
+        space = self.space
+        cls = Class(sp=space)
+        obj1 = cls.instantiate()
+        obj1.setdictvalue(space, "x", space.wrap(1))
+        assert isinstance(obj1.map, IntAttribute)
+        obj1.setdictvalue(space, "y", space.wrap("str"))
+        assert isinstance(obj1.map, PlainAttribute)
+
 # ___________________________________________________________
 # dict tests
 


More information about the pypy-commit mailing list