Author: Carl Friedrich Bolz <[email protected]>
Branch: value-profiling
Changeset: r78995:c0aea2847f70
Date: 2015-08-15 18:59 +0200
http://bitbucket.org/pypy/pypy/changeset/c0aea2847f70/

Log:    track when lists store instances of the same (rpython level) class

diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -40,6 +40,19 @@
 
 UNROLL_CUTOFF = 5
 
+class FixedClsStrategyCache(object):
+    def __init__(self, space):
+        self.space = space
+        self.generic_strategy = space.fromcache(ObjectListStrategy)
+        self.cache = {}
+
+    @jit.elidable
+    def get_or_build(self, cls):
+        strategy = self.cache.get(cls, None)
+        if strategy is None:
+            strategy = ObjectListStrategy(self.space, cls)
+            self.cache[cls] = strategy
+        return strategy
 
 def make_range_list(space, start, step, length):
     if length <= 0:
@@ -125,7 +138,15 @@
         else:
             return space.fromcache(IntOrFloatListStrategy)
 
-    return space.fromcache(ObjectListStrategy)
+    cache = space.fromcache(FixedClsStrategyCache)
+
+    # check for all the same class
+    for i in range(1, len(list_w)):
+        if type(list_w[i]) is not type(w_firstobj):
+            break
+    else:
+        return cache.get_or_build(type(w_firstobj))
+    return cache.generic_strategy
 
 
 def _get_printable_location(w_type):
@@ -685,7 +706,7 @@
             if has_key:
                 sorterclass = CustomKeySort
             else:
-                if self.strategy is space.fromcache(ObjectListStrategy):
+                if isinstance(self.strategy, ObjectListStrategy):
                     sorterclass = SimpleSort
                 else:
                     self.sort(reverse)
@@ -936,7 +957,8 @@
         elif type(w_item) is W_FloatObject:
             strategy = self.space.fromcache(FloatListStrategy)
         else:
-            strategy = self.space.fromcache(ObjectListStrategy)
+            cache = self.space.fromcache(FixedClsStrategyCache)
+            strategy = cache.get_or_build(type(w_item))
 
         storage = strategy.get_empty_storage(self.get_sizehint())
         w_list.strategy = strategy
@@ -1418,9 +1440,8 @@
         w_list.append(w_item)
 
     def insert(self, w_list, index, w_item):
-        l = self.unerase(w_list.lstorage)
-
         if self.is_correct_type(w_item):
+            l = self.unerase(w_list.lstorage)
             l.insert(index, self.unwrap(w_item))
             return
 
@@ -1428,8 +1449,8 @@
         w_list.insert(index, w_item)
 
     def _extend_from_list(self, w_list, w_other):
-        l = self.unerase(w_list.lstorage)
         if self.list_is_correct_type(w_other):
+            l = self.unerase(w_list.lstorage)
             l += self.unerase(w_other.lstorage)
             return
         elif w_other.strategy.is_empty_strategy():
@@ -1581,14 +1602,30 @@
 
 
 class ObjectListStrategy(ListStrategy):
+    _immutable_fields_ = ['_known_cls']
+
     import_from_mixin(AbstractUnwrappedStrategy)
 
     _none_value = None
 
+    def __init__(self, space, known_cls=None):
+        self.space = space
+        self._known_cls = known_cls
+
+    def __repr__(self):
+        return "ObjectListStrategy(space, %s)" % (self._known_cls, )
+
+    @jit.elidable_promote('0')
+    def get_known_cls(self):
+        return self._known_cls
+
     def unwrap(self, w_obj):
         return w_obj
 
     def wrap(self, item):
+        cls = self.get_known_cls()
+        if cls is not None:
+            jit.record_exact_class(item, cls)
         return item
 
     erase, unerase = rerased.new_erasing_pair("object")
@@ -1596,10 +1633,13 @@
     unerase = staticmethod(unerase)
 
     def is_correct_type(self, w_obj):
+        cls = self.get_known_cls()
+        if cls is not None:
+            return type(w_obj) is cls
         return True
 
     def list_is_correct_type(self, w_list):
-        return w_list.strategy is self.space.fromcache(ObjectListStrategy)
+        return w_list.strategy is self
 
     def init_from_list_w(self, w_list, list_w):
         w_list.lstorage = self.erase(list_w)
diff --git a/pypy/objspace/std/test/test_liststrategies.py 
b/pypy/objspace/std/test/test_liststrategies.py
--- a/pypy/objspace/std/test/test_liststrategies.py
+++ b/pypy/objspace/std/test/test_liststrategies.py
@@ -8,6 +8,8 @@
 from pypy.objspace.std import listobject
 from pypy.objspace.std.test.test_listobject import TestW_ListObject
 
+from rpython.rlib import jit
+
 
 class TestW_ListStrategies(TestW_ListObject):
     def test_check_strategy(self):
@@ -1035,6 +1037,93 @@
             (int, 5), (float, 1.2), (int, 1), (float, 1.0)]
 
 
+class TestKnownClasListStrategy:
+    def test_create_from_list(self):
+        space = self.space
+        w_tup = space.wrap((1, 2))
+        w_l = W_ListObject(space, [w_tup, w_tup])
+        assert isinstance(w_l.strategy, ObjectListStrategy)
+        assert w_l.strategy._known_cls is type(w_tup)
+
+        w_l1 = W_ListObject(space, [w_tup, w_tup])
+        assert w_l1.strategy is w_l.strategy
+
+    def test_create_empty(self):
+        space = self.space
+        w_l = W_ListObject(space, [])
+        w_tup = space.wrap((1, 2))
+        w_l.append(w_tup)
+        assert isinstance(w_l.strategy, ObjectListStrategy)
+        assert w_l.strategy._known_cls is type(w_tup)
+        w_l.append(w_tup)
+        assert w_l.strategy._known_cls is type(w_tup)
+
+    def test_append(self):
+        space = self.space
+        w_tup = space.wrap((1, 2))
+        w_l = W_ListObject(space, [w_tup, w_tup])
+        strategy = w_l.strategy
+        w_l.append(w_tup)
+        assert strategy is w_l.strategy
+        w_l.append(w_l)
+        assert w_l.strategy.get_known_cls() is None
+
+    def test_setitem(self):
+        space = self.space
+        w_tup = space.wrap((1, 2))
+        w_l = W_ListObject(space, [w_tup, w_tup])
+        w_l.setitem(0, w_tup)
+        assert w_l.strategy.get_known_cls() is type(w_tup)
+        w_l.setitem(0, w_l)
+        assert w_l.strategy.get_known_cls() is None
+
+    def test_extend(self):
+        space = self.space
+        w_tup = space.wrap((1, 2))
+        w_l = W_ListObject(space, [w_tup, w_tup])
+        w_l1 = W_ListObject(space, [w_tup, w_tup])
+        w_l.extend(w_l1)
+        assert w_l.strategy.get_known_cls() is type(w_tup)
+
+        w_l2 = W_ListObject(space, [w_l, w_l])
+        w_l.extend(w_l2)
+        assert w_l.strategy.get_known_cls() is None
+
+    def test_getslice(self):
+        space = self.space
+        w_tup = space.wrap((1, 2))
+        w_l = W_ListObject(space, [w_tup, w_tup, w_tup])
+        w_l1 = w_l.getslice(0, 1, 1, 1)
+        assert w_l.strategy is w_l1.strategy
+
+    def test_setslice(self):
+        space = self.space
+        w_tup = space.wrap((1, 2))
+        w_l = W_ListObject(space, [w_tup, w_tup, w_tup])
+        w_l.setslice(0, 1, 2, W_ListObject(space, [w_tup, w_tup, w_tup]))
+        assert w_l.strategy.get_known_cls() is type(w_tup)
+        w_l.setslice(0, 1, 2, W_ListObject(space, [w_l, w_tup, w_tup]))
+        assert w_l.strategy.get_known_cls() is None
+
+    def test_propagate_cls_knowledge(self, monkeypatch):
+        l = []
+        def record_exact_class(obj, cls):
+            assert type(obj) is cls
+            l.append((obj, cls))
+        monkeypatch.setattr(jit, 'record_exact_class', record_exact_class)
+
+        space = self.space
+        w_tup = space.wrap((1, 2))
+        w_l = W_ListObject(space, [w_tup, w_tup, w_tup])
+        w_tup1 = w_l.getitem(0)
+        assert w_tup1 is w_tup
+        assert l == [(w_tup, type(w_tup))] * 1
+
+        w_tup1 = w_l.pop_end()
+        assert w_tup1 is w_tup
+        assert l == [(w_tup, type(w_tup))] * 2
+
+
 class TestW_ListStrategiesDisabled:
     spaceconfig = {"objspace.std.withliststrategies": False}
 
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to