[pypy-commit] lang-smalltalk rstrategies: Implementing rstrategies

anton_gulenko noreply at buildbot.pypy.org
Thu Aug 21 12:54:52 CEST 2014


Author: Anton Gulenko <anton.gulenko at googlemail.com>
Branch: rstrategies
Changeset: r1036:d7e93bfe0dd6
Date: 2014-08-20 16:12 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/d7e93bfe0dd6/

Log:	Implementing rstrategies

diff --git a/rstrategies.py b/rstrategies.py
--- a/rstrategies.py
+++ b/rstrategies.py
@@ -2,15 +2,23 @@
 import weakref
 from rpython.rlib import jit
 
+def collect_subclasses(cls):
+    "NOT_RPYTHON"
+    subclasses = []
+    for subcls in cls.__subclasses__():
+        subclasses.append(subcls)
+        subclasses.extend(collect_subclasses(subcls))
+    return subclasses
+
 class StrategyFactory(object):
-    _immutable_fields_ = ["strategies[*]"]
+    _immutable_fields_ = ["xx[*]"]
     
-    def __init__(self, strategy_root_class, transitions):
-        self.strategies = []
-        self.root_class = strategy_root_class
+    def __init__(self, root_class, all_strategy_classes=None):
+        if all_strategy_classes is None:
+            all_strategy_classes = collect_subclasses(root_class)
+        self.strategies = all_strategy_classes
         
-        for strategy_class, generalized in transitions.items():
-            self.strategies.append(strategy_class)
+        for strategy_class in self.strategies:
             strategy_class._strategy_instance = self.instantiate_empty(strategy_class)
             
             # Patch root class: Add default handler for visitor
@@ -18,14 +26,17 @@
                 self.copy_from(other)
             funcname = "copy_from_" + strategy_class.__name__
             copy_from_OTHER.func_name = funcname
-            setattr(self.root_class, funcname, copy_from_OTHER)
+            setattr(root_class, funcname, copy_from_OTHER)
             
             # Patch strategy class: Add polymorphic visitor function
             def initiate_copy_into(self, other):
                 getattr(other, funcname)(self)
             strategy_class.initiate_copy_into = initiate_copy_into
-            
-            self.create_transition(strategy_class, generalized)
+    
+    def setup_strategy_transitions(self, transitions):
+        "NOT_RPYTHON"
+        for strategy_class, generalized in transitions.items():
+            generalize(generalized)(strategy_class)
     
     # Instantiate new_strategy_type with size, replace old_strategy with it,
     # and return the new instance
@@ -39,6 +50,7 @@
     def switch_strategy(self, old_strategy, new_strategy_type):
         new_instance = self.instantiate_and_switch(old_strategy, old_strategy.size(), new_strategy_type)
         old_strategy.initiate_copy_into(new_instance)
+        new_instance.strategy_switched()
         return new_instance
     
     @jit.unroll_safe
@@ -55,6 +67,7 @@
         for i, strategy_type in enumerate(self.strategies):
             if can_handle[i]:
                 return strategy_type
+        raise Exception("Could not find strategy to handle: %s" % objects)
     
     def cannot_handle_value(self, old_strategy, index0, value):
         strategy_type = old_strategy.generalized_strategy_for(value)
@@ -64,24 +77,44 @@
     def _freeze_(self):
         # Instance will be frozen at compile time, making accesses constant.
         return True
-    
-    def create_transition(self, strategy_class, generalized):
+
+def generalize(generalized):
+    def decorator(strategy_class):
         # Patch strategy class: Add generalized_strategy_for
+        # TODO - optimize this method
+        @jit.unroll_safe
         def generalized_strategy_for(self, value):
             for strategy in generalized:
                 if strategy._strategy_instance.check_can_handle(value):
                     return strategy
             raise Exception("Could not find generalized strategy for %s coming from %s" % (value, self))
         strategy_class.generalized_strategy_for = generalized_strategy_for
+        return strategy_class
+    return decorator
+
+class AbstractCollection(object):
+    # == Required:
+    # store(self, n0, e)
+    
+    def strategy_switched(self): pass
+    def init_strategy(self, initial_size): pass
+    
+    def initiate_copy_into(self, other):
+        other.copy_from(self)
+    
+    def copy_from(self, other):
+        assert self.size() == other.size()
+        for i in range(self.size()):
+            self.copy_field_from(i, other)
+    
+    def copy_field_from(self, n0, other):
+        self.store(n0, other.fetch(n0))
     
 class AbstractStrategy(object):
     # == Required:
     # strategy_factory(self) - Access to StorageFactory
     # __init__(...) - Constructor should invoke the provided init_strategy(self, size) method
     
-    def init_strategy(self, initial_size):
-        pass
-    
     def store(self, index0, value):
         raise NotImplementedError("Abstract method")
     
@@ -97,17 +130,6 @@
     def cannot_handle_value(self, index0, value):
         self.strategy_factory().cannot_handle_value(self, index0, value)
     
-    def initiate_copy_into(self, other):
-        other.copy_from(self)
-    
-    def copy_from(self, other):
-        assert self.size() == other.size()
-        for i in range(self.size()):
-            self.copy_field_from(i, other)
-    
-    def copy_field_from(self, n0, other):
-        self.store(n0, other.fetch(n0))
-    
 # ============== Special Strategies with no storage array ==============
 
 class EmptyStrategy(AbstractStrategy):
diff --git a/spyvm/model.py b/spyvm/model.py
--- a/spyvm/model.py
+++ b/spyvm/model.py
@@ -611,12 +611,6 @@
         assert shadow, "The shadow has not been initialized yet!"
         return shadow
     
-    def switch_shadow(self, new_shadow, w_element=None):
-        old_shadow = self.assert_shadow()
-        self.store_shadow(new_shadow)
-        old_shadow.copy_into(new_shadow)
-        new_shadow.attach_shadow()
-    
     def space(self):
         return self.assert_shadow().space
         
@@ -675,7 +669,7 @@
     def instsize(self):
         return self.class_shadow(self.space()).instsize()
 
-    def store_shadow(self, shadow, operation="", w_element=None, log_classname=True):
+    def store_shadow(self, shadow, operation="Switched", w_element=None, log_classname=True):
         old_shadow = self.shadow
         self.shadow = shadow
         self.log_storage(operation, old_shadow, log_classname, w_element)
diff --git a/spyvm/plugins/bitblt.py b/spyvm/plugins/bitblt.py
--- a/spyvm/plugins/bitblt.py
+++ b/spyvm/plugins/bitblt.py
@@ -47,15 +47,13 @@
 
 
 class BitBltShadow(AbstractCachingShadow):
+    repr_classname = "BitBltShadow"
     WordSize = 32
     MaskTable = [r_uint(0)]
     for i in xrange(WordSize):
         MaskTable.append(r_uint((2 ** (i + 1)) - 1))
     AllOnes = r_uint(0xFFFFFFFF)
 
-    def attach_shadow(self):
-        pass
-
     def intOrIfNil(self, w_int, i):
         return intOrIfNil(self.space, w_int, i)
 
@@ -724,6 +722,7 @@
 
 
 class FormShadow(AbstractCachingShadow):
+    repr_classname = "FormShadow"
     _attrs_ = ["w_bits", "width", "height", "depth", "offsetX",
                "offsetY", "msb", "pixPerWord", "pitch", "invalid"]
 
@@ -734,7 +733,7 @@
     def intOrIfNil(self, w_int, i):
         return intOrIfNil(self.space, w_int, i)
 
-    def attach_shadow(self):
+    def strategy_switched(self):
         self.invalid = True
         if self.size() < 5:
             return
diff --git a/spyvm/storage.py b/spyvm/storage.py
--- a/spyvm/storage.py
+++ b/spyvm/storage.py
@@ -1,5 +1,4 @@
 
-import weakref
 from spyvm import model, version, constants
 from spyvm.version import elidable_for_version
 from rpython.rlib import objectmodel, jit
@@ -14,7 +13,8 @@
     _immutable_fields_ = ['space']
     provides_getname = False
     repr_classname = "AbstractShadow"
-
+    import_from_mixin(rstrat.AbstractCollection)
+    
     def __init__(self, space, w_self, size):
         self.space = space
         assert w_self is None or isinstance(w_self, model.W_PointersObject)
@@ -29,35 +29,6 @@
         else:
             return "<%s>" % self.repr_classname
 
-    def fetch(self, n0):
-        raise NotImplementedError("Abstract class")
-    def store(self, n0, w_value):
-        raise NotImplementedError("Abstract class")
-    def size(self):
-        raise NotImplementedError("Abstract class")
-
-    # This will invoke an appropriate copy_from_* method.
-    # Overwriting this allows optimized transitions between certain storage types.
-    def copy_into(self, other_shadow):
-        other_shadow.copy_from(self)
-    
-    def attach_shadow(self): pass
-
-    def copy_field_from(self, n0, other_shadow):
-        self.store(n0, other_shadow.fetch(n0))
-
-    def copy_from(self, other_shadow):
-        assert self.size() == other_shadow.size()
-        for i in range(self.size()):
-            self.copy_field_from(i, other_shadow)
-    
-    def copy_from_AllNil(self, all_nil_storage):
-        self.copy_from(all_nil_storage)
-    def copy_from_SmallIntegerOrNil(self, small_int_storage):
-        self.copy_from(small_int_storage)
-    def copy_from_FloatOrNil(self, float_storage):
-        self.copy_from(float_storage)
-
 # ========== Storage classes implementing storage strategies ==========
 
 class AbstractStorageShadow(AbstractShadow):
@@ -74,11 +45,17 @@
     def copy_from_AllNilStrategy(self, all_nil_storage):
         pass # Fields already initialized to nil
 
-class AllNilStorageShadow(AbstractStorageShadow):
-    repr_classname = "AllNilStorageShadow"
-    import_from_mixin(rstrat.SingleValueStrategy)
-    def value(self): return self.space.w_nil
+class ListStorageShadow(AbstractStorageShadow):
+    repr_classname = "ListStorageShadow"
+    import_from_mixin(rstrat.GenericStrategy)
+    def default_value(self): return self.space.w_nil
 
+class WeakListStorageShadow(AbstractStorageShadow):
+    repr_classname = "WeakListStorageShadow"
+    import_from_mixin(rstrat.WeakGenericStrategy)
+    def default_value(self): return self.space.w_nil
+
+ at rstrat.generalize([ListStorageShadow])
 class SmallIntegerOrNilStorageShadow(AbstractStorageShadow):
     repr_classname = "SmallIntegerOrNilStorageShadow"
     import_from_mixin(rstrat.TaggingStrategy)
@@ -89,6 +66,7 @@
     def wrapped_tagged_value(self): return self.space.w_nil
     def unwrapped_tagged_value(self): return constants.MAXINT
 
+ at rstrat.generalize([ListStorageShadow])
 class FloatOrNilStorageShadow(AbstractStorageShadow):
     repr_classname = "FloatOrNilStorageShadow"
     import_from_mixin(rstrat.TaggingStrategy)
@@ -99,15 +77,14 @@
     def wrapped_tagged_value(self): return self.space.w_nil
     def unwrapped_tagged_value(self): import sys; return sys.float_info.max
 
-class ListStorageShadow(AbstractStorageShadow):
-    repr_classname = "ListStorageShadow"
-    import_from_mixin(rstrat.GenericStrategy)
-    def default_value(self): return self.space.w_nil
-
-class WeakListStorageShadow(AbstractStorageShadow):
-    repr_classname = "WeakListStorageShadow"
-    import_from_mixin(rstrat.WeakGenericStrategy)
-    def default_value(self): return self.space.w_nil
+ at rstrat.generalize([
+    SmallIntegerOrNilStorageShadow,
+    FloatOrNilStorageShadow,
+    ListStorageShadow])
+class AllNilStorageShadow(AbstractStorageShadow):
+    repr_classname = "AllNilStorageShadow"
+    import_from_mixin(rstrat.SingleValueStrategy)
+    def value(self): return self.space.w_nil
 
 class StrategyFactory(rstrat.StrategyFactory):
     _immutable_fields_ = ["space", "no_specialized_storage?"]
@@ -115,13 +92,7 @@
         from spyvm import objspace
         self.space = space
         self.no_specialized_storage = objspace.ConstantFlag()
-        rstrat.StrategyFactory.__init__(self, AbstractStorageShadow, {
-            AllNilStorageShadow: [SmallIntegerOrNilStorageShadow,
-                                    FloatOrNilStorageShadow,
-                                    ListStorageShadow],
-            SmallIntegerOrNilStorageShadow: [ListStorageShadow],
-            FloatOrNilStorageShadow: [ListStorageShadow],
-        })
+        rstrat.StrategyFactory.__init__(self, AbstractStorageShadow)
     
     def strategy_type_for(self, objects, weak=False):
         if weak:
@@ -141,7 +112,6 @@
         w_self = old_strategy.w_self()
         instance = strategy_class(self.space, w_self, size)
         w_self.store_shadow(instance)
-        instance.attach_shadow()
         return instance
     
     def instantiate_empty(self, strategy_type):
diff --git a/spyvm/test/test_primitives.py b/spyvm/test/test_primitives.py
--- a/spyvm/test/test_primitives.py
+++ b/spyvm/test/test_primitives.py
@@ -792,7 +792,7 @@
 
     try:
         monkeypatch.setattr(w_frame.shadow, "_sendSelfSelector", perform_mock)
-        monkeypatch.setattr(bitblt.BitBltShadow, "attach_shadow", sync_cache_mock)
+        monkeypatch.setattr(bitblt.BitBltShadow, "strategy_switched", sync_cache_mock)
         with py.test.raises(CallCopyBitsSimulation):
             prim_table[primitives.BITBLT_COPY_BITS](interp, w_frame.as_context_get_shadow(space), argument_count-1)
     finally:


More information about the pypy-commit mailing list