[pypy-commit] pypy default: merge typed-cells

cfbolz noreply at buildbot.pypy.org
Thu Jan 22 16:50:47 CET 2015


Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: 
Changeset: r75484:fd3d597fb6ea
Date: 2015-01-22 16:49 +0100
http://bitbucket.org/pypy/pypy/changeset/fd3d597fb6ea/

Log:	merge typed-cells

diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py
--- a/pypy/module/pypyjit/test_pypy_c/test_instance.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py
@@ -83,7 +83,7 @@
         loops = log.loops_by_filename(self.filepath)
         assert len(loops) == 1
 
-    def test_mutate_class(self):
+    def test_mutate_class_int(self):
         def fn(n):
             class A(object):
                 count = 1
@@ -106,7 +106,7 @@
         entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True)
         ops = entry_bridge.ops_by_id('mutate', opcode='LOAD_ATTR')
         assert log.opnames(ops) == ['guard_value', 'guard_not_invalidated',
-                                    'getfield_gc', 'guard_nonnull_class']
+                                    'getfield_gc']
         # the STORE_ATTR is folded away
         assert list(entry_bridge.ops_by_id('meth1', opcode='STORE_ATTR')) == []
         #
@@ -114,19 +114,77 @@
         # ----------------------
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match("""
-            i8 = getfield_gc_pure(p5, descr=...)
-            i9 = int_lt(i8, i7)
-            guard_true(i9, descr=.*)
-            guard_not_invalidated(descr=.*)
-            i82 = getfield_gc_pure(p8, descr=...)
-            i11 = int_add_ovf(i82, 1)
+            i58 = int_lt(i38, i31)
+            guard_true(i58, descr=...)
+            guard_not_invalidated(descr=...)
+            i59 = int_add_ovf(i57, 1)
             guard_no_overflow(descr=...)
-            i12 = force_token()
-            --TICK--
-            p20 = new_with_vtable(ConstClass(W_IntObject))
-            setfield_gc(p20, i11, descr=<FieldS.*W_IntObject.inst_intval .*>)
-            setfield_gc(ConstPtr(ptr21), p20, descr=<FieldP .*TypeCell.inst_w_value .*>)
-            jump(..., descr=...)
+            p60 = force_token()
+            i61 = getfield_raw(..., descr=...)
+            setfield_gc(ConstPtr(ptr39), i59, descr=...)
+            i62 = int_lt(i61, 0)
+            guard_false(i62, descr=...)
+            jump(p0, p1, p3, p6, p7, p12, i59, p18, i31, i59, descr=...)
+        """)
+
+    def test_mutate_class(self):
+        def fn(n):
+            class LL(object):
+                def __init__(self, n):
+                    self.n = n
+            class A(object):
+                count = None
+                def __init__(self, a):
+                    self.a = a
+                def f(self):
+                    return self.count
+            i = 0
+            a = A(1)
+            while i < n:
+                A.count = LL(A.count) # ID: mutate
+                a.f()    # ID: meth1
+                i += 1
+            return i
+        #
+        log = self.run(fn, [1000], threshold=10)
+        assert log.result == 1000
+        #
+        # first, we test the entry bridge
+        # -------------------------------
+        entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True)
+        ops = entry_bridge.ops_by_id('mutate', opcode='LOAD_ATTR')
+        assert log.opnames(ops) == ['guard_value', 'guard_not_invalidated',
+                                    'getfield_gc', 'guard_nonnull_class',
+                                    'getfield_gc', 'guard_value', # type check on the attribute
+                                    ]
+        # the STORE_ATTR is folded away
+        assert list(entry_bridge.ops_by_id('meth1', opcode='STORE_ATTR')) == []
+        #
+        # then, the actual loop
+        # ----------------------
+        loop, = log.loops_by_filename(self.filepath)
+        assert loop.match("""
+            i70 = int_lt(i58, i33)
+            guard_true(i70, descr=...)
+            guard_not_invalidated(descr=...)
+            p71 = getfield_gc(p64, descr=...)
+            guard_value(p71, ConstPtr(ptr42), descr=...)
+            p72 = force_token()
+            p73 = force_token()
+            i74 = int_add(i58, 1)
+            i75 = getfield_raw(..., descr=...)
+            i76 = int_lt(i75, 0)
+            guard_false(i76, descr=...)
+            p77 = new_with_vtable(...)
+            setfield_gc(p77, p64, descr=...)
+            setfield_gc(p77, ConstPtr(null), descr=...)
+            setfield_gc(p77, ConstPtr(null), descr=...)
+            setfield_gc(p77, ConstPtr(null), descr=...)
+            setfield_gc(p77, ConstPtr(null), descr=...)
+            setfield_gc(p77, ConstPtr(ptr42), descr=...)
+            setfield_gc(ConstPtr(ptr69), p77, descr=...)
+            jump(p0, p1, p3, p6, p7, p12, i74, p20, p26, i33, p77, descr=...)
+
         """)
 
     def test_oldstyle_newstyle_mix(self):
diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py
--- a/pypy/objspace/std/celldict.py
+++ b/pypy/objspace/std/celldict.py
@@ -9,23 +9,16 @@
 from pypy.objspace.std.dictmultiobject import (
     DictStrategy, ObjectDictStrategy, _never_equal_to_string,
     create_iterator_classes)
+from pypy.objspace.std.typeobject import (
+    MutableCell, IntMutableCell, ObjectMutableCell, write_cell)
 
 
 class VersionTag(object):
     pass
 
-
-class ModuleCell(W_Root):
-    def __init__(self, w_value=None):
-        self.w_value = w_value
-
-    def __repr__(self):
-        return "<ModuleCell: %s>" % (self.w_value, )
-
-
-def unwrap_cell(w_value):
-    if isinstance(w_value, ModuleCell):
-        return w_value.w_value
+def unwrap_cell(space, w_value):
+    if isinstance(w_value, MutableCell):
+        return w_value.unwrap_cell(space)
     return w_value
 
 
@@ -71,15 +64,9 @@
 
     def setitem_str(self, w_dict, key, w_value):
         cell = self.getdictvalue_no_unwrapping(w_dict, key)
-        if isinstance(cell, ModuleCell):
-            cell.w_value = w_value
+        w_value = write_cell(self.space, cell, w_value)
+        if w_value is None:
             return
-        if cell is not None:
-            # If the new value and the current value are the same, don't
-            # create a level of indirection, or mutate the version.
-            if self.space.is_w(w_value, cell):
-                return
-            w_value = ModuleCell(w_value)
         self.mutated()
         self.unerase(w_dict.dstorage)[key] = w_value
 
@@ -131,7 +118,7 @@
 
     def getitem_str(self, w_dict, key):
         cell = self.getdictvalue_no_unwrapping(w_dict, key)
-        return unwrap_cell(cell)
+        return unwrap_cell(self.space, cell)
 
     def w_keys(self, w_dict):
         space = self.space
@@ -140,12 +127,12 @@
 
     def values(self, w_dict):
         iterator = self.unerase(w_dict.dstorage).itervalues
-        return [unwrap_cell(cell) for cell in iterator()]
+        return [unwrap_cell(self.space, cell) for cell in iterator()]
 
     def items(self, w_dict):
         space = self.space
         iterator = self.unerase(w_dict.dstorage).iteritems
-        return [space.newtuple([_wrapkey(space, key), unwrap_cell(cell)])
+        return [space.newtuple([_wrapkey(space, key), unwrap_cell(self.space, cell)])
                 for key, cell in iterator()]
 
     def clear(self, w_dict):
@@ -157,7 +144,7 @@
         d = self.unerase(w_dict.dstorage)
         key, cell = d.popitem()
         self.mutated()
-        return _wrapkey(space, key), unwrap_cell(cell)
+        return _wrapkey(space, key), unwrap_cell(self.space, cell)
 
     def switch_to_object_strategy(self, w_dict):
         space = self.space
@@ -165,7 +152,7 @@
         strategy = space.fromcache(ObjectDictStrategy)
         d_new = strategy.unerase(strategy.get_empty_storage())
         for key, cell in d.iteritems():
-            d_new[_wrapkey(space, key)] = unwrap_cell(cell)
+            d_new[_wrapkey(space, key)] = unwrap_cell(self.space, cell)
         w_dict.strategy = strategy
         w_dict.dstorage = strategy.erase(d_new)
 
@@ -181,7 +168,7 @@
     wrapkey = _wrapkey
 
     def wrapvalue(space, value):
-        return unwrap_cell(value)
+        return unwrap_cell(space, value)
 
 
 create_iterator_classes(ModuleDictStrategy)
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
@@ -8,7 +8,7 @@
     W_DictMultiObject, DictStrategy, ObjectDictStrategy, BaseKeyIterator,
     BaseValueIterator, BaseItemIterator, _never_equal_to_string
 )
-from pypy.objspace.std.typeobject import TypeCell
+from pypy.objspace.std.typeobject import MutableCell
 
 
 # ____________________________________________________________
@@ -872,15 +872,15 @@
         if version_tag is not None:
             name = space.str_w(w_name)
             # We need to care for obscure cases in which the w_descr is
-            # a TypeCell, which may change without changing the version_tag
+            # a MutableCell, which may change without changing the version_tag
             _, w_descr = w_type._pure_lookup_where_possibly_with_method_cache(
                 name, version_tag)
             #
             selector = ("", INVALID)
             if w_descr is None:
                 selector = (name, DICT) # common case: no such attr in the class
-            elif isinstance(w_descr, TypeCell):
-                pass              # we have a TypeCell in the class: give up
+            elif isinstance(w_descr, MutableCell):
+                pass              # we have a MutableCell in the class: give up
             elif space.is_data_descr(w_descr):
                 # we have a data descriptor, which means the dictionary value
                 # (if any) has no relevance.
@@ -929,11 +929,11 @@
     # We know here that w_obj.getdictvalue(space, name) just returned None,
     # so the 'name' is not in the instance.  We repeat the lookup to find it
     # in the class, this time taking care of the result: it can be either a
-    # quasi-constant class attribute, or actually a TypeCell --- which we
+    # quasi-constant class attribute, or actually a MutableCell --- which we
     # must not cache.  (It should not be None here, but you never know...)
     _, w_method = w_type._pure_lookup_where_possibly_with_method_cache(
         name, version_tag)
-    if w_method is None or isinstance(w_method, TypeCell):
+    if w_method is None or isinstance(w_method, MutableCell):
         return
     _fill_cache(pycode, nameindex, map, version_tag, -1, w_method)
 
diff --git a/pypy/objspace/std/test/test_versionedtype.py b/pypy/objspace/std/test/test_versionedtype.py
--- a/pypy/objspace/std/test/test_versionedtype.py
+++ b/pypy/objspace/std/test/test_versionedtype.py
@@ -210,6 +210,56 @@
         assert w_A.version_tag() is atag
         assert space.int_w(space.getattr(w_A, w_x)) == 4
 
+    def test_no_cell_when_writing_same_value(self):
+        space = self.space
+        w_x = space.wrap("x")
+        w_A, w_B, w_C = self.get_three_classes()
+        atag = w_A.version_tag()
+        w_val = space.newint(1)
+        space.setattr(w_A, w_x, w_val)
+        space.setattr(w_A, w_x, w_val)
+        w_val1 = w_A._getdictvalue_no_unwrapping(space, "x")
+        assert w_val1 is w_val
+
+    def test_int_cells(self):
+        space = self.space
+        w_x = space.wrap("x")
+        w_A, w_B, w_C = self.get_three_classes()
+        atag = w_A.version_tag()
+        space.setattr(w_A, w_x, space.newint(1))
+        assert w_A.version_tag() is not atag
+        assert space.int_w(space.getattr(w_A, w_x)) == 1
+
+        atag = w_A.version_tag()
+        space.setattr(w_A, w_x, space.newint(2))
+        assert w_A.version_tag() is not atag
+        assert space.int_w(space.getattr(w_A, w_x)) == 2
+        cell = w_A._getdictvalue_no_unwrapping(space, "x")
+        assert cell.intvalue == 2
+
+        atag = w_A.version_tag()
+        space.setattr(w_A, w_x, space.newint(3))
+        assert w_A.version_tag() is atag
+        assert space.int_w(space.getattr(w_A, w_x)) == 3
+        assert cell.intvalue == 3
+
+        space.setattr(w_A, w_x, space.newint(4))
+        assert w_A.version_tag() is atag
+        assert space.int_w(space.getattr(w_A, w_x)) == 4
+        assert cell.intvalue == 4
+
+    def test_int_cell_turns_into_cell(self):
+        space = self.space
+        w_x = space.wrap("x")
+        w_A, w_B, w_C = self.get_three_classes()
+        atag = w_A.version_tag()
+        space.setattr(w_A, w_x, space.newint(1))
+        space.setattr(w_A, w_x, space.newint(2))
+        space.setattr(w_A, w_x, space.newfloat(2.2))
+        cell = w_A._getdictvalue_no_unwrapping(space, "x")
+        assert space.float_w(cell.w_value) == 2.2
+
+
 
 class AppTestVersionedType(test_typeobject.AppTestTypeObject):
     spaceconfig = {"objspace.std.withtypeversion": True}
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -11,18 +11,57 @@
 from rpython.rlib.objectmodel import current_object_addr_as_int, compute_hash
 from rpython.rlib.rarithmetic import intmask, r_uint
 
+class MutableCell(W_Root):
+    def unwrap_cell(self, space):
+        raise NotImplementedError("abstract base")
 
-class TypeCell(W_Root):
+class ObjectMutableCell(MutableCell):
     def __init__(self, w_value=None):
         self.w_value = w_value
 
+    def unwrap_cell(self, space):
+        return self.w_value
+
+    def __repr__(self):
+        return "<ObjectMutableCell: %s>" % (self.w_value, )
+
+
+class IntMutableCell(MutableCell):
+    def __init__(self, intvalue):
+        self.intvalue = intvalue
+
+    def unwrap_cell(self, space):
+        return space.wrap(self.intvalue)
+
+    def __repr__(self):
+        return "<IntMutableCell: %s>" % (self.intvalue, )
+
 
 def unwrap_cell(space, w_value):
-    if (space.config.objspace.std.withtypeversion and
-            isinstance(w_value, TypeCell)):
-        return w_value.w_value
+    if space.config.objspace.std.withtypeversion:
+        if isinstance(w_value, MutableCell):
+            return w_value.unwrap_cell(space)
     return w_value
 
+def write_cell(space, w_cell, w_value):
+    from pypy.objspace.std.intobject import W_IntObject
+    if w_cell is None:
+        # attribute does not exist at all, write it without a cell first
+        return w_value
+    if isinstance(w_cell, ObjectMutableCell):
+        w_cell.w_value = w_value
+        return None
+    elif isinstance(w_cell, IntMutableCell) and type(w_value) is W_IntObject:
+        w_cell.intvalue = w_value.intval
+        return None
+    elif space.is_w(w_cell, w_value):
+        # If the new value and the current value are the same, don't
+        # create a level of indirection, or mutate the version.
+        return None
+    if type(w_value) is W_IntObject:
+        return IntMutableCell(w_value.intval)
+    else:
+        return ObjectMutableCell(w_value)
 
 class VersionTag(object):
     pass
@@ -274,11 +313,9 @@
             if version_tag is not None:
                 w_curr = w_self._pure_getdictvalue_no_unwrapping(
                         space, version_tag, name)
-                if w_curr is not None:
-                    if isinstance(w_curr, TypeCell):
-                        w_curr.w_value = w_value
-                        return True
-                    w_value = TypeCell(w_value)
+                w_value = write_cell(space, w_curr, w_value)
+                if w_value is None:
+                    return True
         w_self.mutated(name)
         w_self.dict_w[name] = w_value
         return True
@@ -369,8 +406,8 @@
         tup_w = w_self._pure_lookup_where_with_method_cache(name, version_tag)
         w_class, w_value = tup_w
         if (space.config.objspace.std.withtypeversion and
-                isinstance(w_value, TypeCell)):
-            return w_class, w_value.w_value
+                isinstance(w_value, MutableCell)):
+            return w_class, w_value.unwrap_cell(space)
         return tup_w   # don't make a new tuple, reuse the old one
 
     def _pure_lookup_where_possibly_with_method_cache(w_self, name, version_tag):


More information about the pypy-commit mailing list