[pypy-commit] lang-smalltalk rstrategies: Work in progress.

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


Author: Anton Gulenko <anton.gulenko at googlemail.com>
Branch: rstrategies
Changeset: r1035:4fd727366707
Date: 2014-08-03 13:29 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/4fd727366707/

Log:	Work in progress.

diff --git a/rstrategies.py b/rstrategies.py
new file mode 100644
--- /dev/null
+++ b/rstrategies.py
@@ -0,0 +1,313 @@
+
+import weakref
+from rpython.rlib import jit
+
+class StrategyFactory(object):
+    _immutable_fields_ = ["strategies[*]"]
+    
+    def __init__(self, strategy_root_class, transitions):
+        self.strategies = []
+        self.root_class = strategy_root_class
+        
+        for strategy_class, generalized in transitions.items():
+            self.strategies.append(strategy_class)
+            strategy_class._strategy_instance = self.instantiate_empty(strategy_class)
+            
+            # Patch root class: Add default handler for visitor
+            def copy_from_OTHER(self, other):
+                self.copy_from(other)
+            funcname = "copy_from_" + strategy_class.__name__
+            copy_from_OTHER.func_name = funcname
+            setattr(self.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)
+    
+    # Instantiate new_strategy_type with size, replace old_strategy with it,
+    # and return the new instance
+    def instantiate_and_switch(self, old_strategy, size, new_strategy_type):
+        raise NotImplementedError("Abstract method")
+    
+    # Return a functional but empty instance of strategy_type
+    def instantiate_empty(self, strategy_type):
+        raise NotImplementedError("Abstract method")
+    
+    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)
+        return new_instance
+    
+    @jit.unroll_safe
+    def strategy_type_for(self, objects):
+        specialized_strategies = len(self.strategies)
+        can_handle = [True] * specialized_strategies
+        for obj in objects:
+            if specialized_strategies <= 1:
+                break
+            for i, strategy in enumerate(self.strategies):
+                if can_handle[i] and not strategy._strategy_instance.check_can_handle(obj):
+                    can_handle[i] = False
+                    specialized_strategies -= 1
+        for i, strategy_type in enumerate(self.strategies):
+            if can_handle[i]:
+                return strategy_type
+    
+    def cannot_handle_value(self, old_strategy, index0, value):
+        strategy_type = old_strategy.generalized_strategy_for(value)
+        new_instance = self.switch_strategy(old_strategy, strategy_type)
+        new_instance.store(index0, value)
+    
+    def _freeze_(self):
+        # Instance will be frozen at compile time, making accesses constant.
+        return True
+    
+    def create_transition(self, strategy_class, generalized):
+        # Patch strategy class: Add generalized_strategy_for
+        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
+    
+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")
+    
+    def fetch(self, index0):
+        raise NotImplementedError("Abstract method")
+    
+    def size(self):
+        raise NotImplementedError("Abstract method")
+        
+    def check_can_handle(self, value):
+        raise NotImplementedError("Abstract method")
+    
+    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):
+    # == Required:
+    # See AbstractStrategy
+    
+    def fetch(self, index0):
+        raise IndexError
+    def store(self, index0, value):
+        self.cannot_handle_value(index0, value)
+    def size(self):
+        return 0
+    def check_can_handle(self, value):
+        return False
+    
+class SingleValueStrategy(AbstractStrategy):
+    _immutable_fields_ = ["_size", "val"]
+    # == Required:
+    # See AbstractStrategy
+    # check_index_*(...) - use mixin SafeIndexingMixin or UnsafeIndexingMixin
+    # value(self) - the single value contained in this strategy
+    
+    def init_strategy(self, initial_size):
+        self._size = initial_size
+        self.val = self.value()
+    def fetch(self, index0):
+        self.check_index_fetch(index0)
+        return self.val
+    def store(self, index0, value):
+        self.check_index_store(index0)
+        if self.val is value:
+            return
+        self.cannot_handle_value(index0, value)
+    def size(self):
+        return self._size
+    def check_can_handle(self, value):
+        return value is self.val
+    
+# ============== Basic strategies with storage ==============
+
+class StrategyWithStorage(AbstractStrategy):
+    _immutable_fields_ = ["storage"]
+    # == Required:
+    # See AbstractStrategy
+    # check_index_*(...) - use mixin SafeIndexingMixin, UnsafeIndexingMixin or VariableSizeMixin
+    # default_value(self) - The value to be initially contained in this strategy
+    
+    def init_strategy(self, initial_size):
+        self.init_StrategyWithStorage(initial_size)
+    
+    def init_StrategyWithStorage(self, initial_size):
+        default = self._unwrap(self.default_value())
+        self.storage = [default] * initial_size
+    
+    def store(self, index0, wrapped_value):
+        self.check_index_store(index0)
+        if self.check_can_handle(wrapped_value):
+            unwrapped = self._unwrap(wrapped_value)
+            self.storage[index0] = unwrapped
+        else:
+            self.cannot_handle_value(index0, wrapped_value)
+    
+    def fetch(self, index0):
+        self.check_index_fetch(index0)
+        unwrapped = self.storage[index0]
+        return self._wrap(unwrapped)
+    
+    def _wrap(self, value):
+        raise NotImplementedError("Abstract method")
+    
+    def _unwrap(self, value):
+        raise NotImplementedError("Abstract method")
+    
+    def size(self):
+        return len(self.storage)
+    
+class GenericStrategy(StrategyWithStorage):
+    # == Required:
+    # See StrategyWithStorage
+    
+    def _wrap(self, value):
+        return value
+    def _unwrap(self, value):
+        return value
+    def check_can_handle(self, wrapped_value):
+        return True
+    
+class WeakGenericStrategy(StrategyWithStorage):
+    # == Required:
+    # See StrategyWithStorage
+    
+    def _wrap(self, value):
+        return value() or self.default_value()
+    def _unwrap(self, value):
+        assert value is not None
+        return weakref.ref(value)
+    def check_can_handle(self, wrapped_value):
+        return True
+    
+# ============== Mixins for StrategyWithStorage ==============
+
+class SafeIndexingMixin(object):
+    def check_index_store(self, index0):
+        self.check_index(index0)
+    def check_index_fetch(self, index0):
+        self.check_index(index0)
+    def check_index(self, index0):
+        if index0 < 0 or index0 >= self.size():
+            raise IndexError
+
+class UnsafeIndexingMixin(object):
+    def check_index_store(self, index0):
+        pass
+    def check_index_fetch(self, index0):
+        pass
+
+class VariableSizeMixin(object):
+    # This can be used with StrategyWithStorage
+    # to add functionality for resizing the storage.
+    # Can be combined with either *IndexingMixin or *AutoresizeMixin
+    
+    @jit.unroll_safe
+    def grow(self, by):
+        if by <= 0:
+            raise ValueError
+        for _ in range(by):
+            self.storage.append(self.default_value())
+    
+    @jit.unroll_safe
+    def shrink(self, by):
+        if by <= 0:
+            raise ValueError
+        if by > self.size():
+            raise ValueError
+        for _ in range(by):
+            self.storage.pop()
+    
+class SafeAutoresizeMixin(object):
+    def check_index_fetch(self, index0):
+        if index0 < 0 or index0 > self.size():
+            raise IndexError
+    def check_index_store(self, index0):
+        size = self.size()
+        if index0 < 0:
+            raise IndexError
+        if index0 >= size:
+            self.grow(index0 - size + 1)
+    
+class UnsafeAutoresizeMixin(object):
+    def check_index_fetch(self, index0):
+        pass
+    def check_index_store(self, index0):
+        size = self.size()
+        if index0 >= size:
+            self.grow(index0 - size)
+    
+# ============== Specialized Storage Strategies ==============
+
+class SpecializedStrategy(StrategyWithStorage):
+    # == Required:
+    # See StrategyWithStorage
+    # wrap(self, value) - Return a boxed object for the primitive value
+    # unwrap(self, value) - Return the unboxed primitive value of value
+    
+    def _unwrap(self, value):
+        return self.unwrap(value)
+    def _wrap(self, value):
+        return self.wrap(value)
+    
+class SingleTypeStrategy(SpecializedStrategy):
+    # == Required Functions:
+    # See SpecializedStrategy
+    # contained_type - The wrapped type that can be stored in this strategy
+    
+    def check_can_handle(self, value):
+        return isinstance(value, self.contained_type)
+    
+class TaggingStrategy(SingleTypeStrategy):
+    """This strategy uses a special tag value to represent a single additional object."""
+    # == Required:
+    # See SingleTypeStrategy
+    # wrapped_tagged_value(self) - The tagged object
+    # unwrapped_tagged_value(self) - The unwrapped tag value representing the tagged object
+    
+    def init_strategy(self, initial_size):
+        self.tag = self.unwrapped_tagged_value()
+        self.w_tag = self.wrapped_tagged_value()
+        self.init_StrategyWithStorage(initial_size)
+    
+    def check_can_handle(self, value):
+        return value is self.w_tag or \
+                (isinstance(value, self.contained_type) and \
+                self.unwrap(value) != self.tag)
+    
+    def _unwrap(self, value):
+        if value is self.w_tag:
+            return self.tag
+        return self.unwrap(value)
+    
+    def _wrap(self, value):
+        if value == self.tag:
+            return self.w_tag
+        return self.wrap(value)
diff --git a/spyvm/model.py b/spyvm/model.py
--- a/spyvm/model.py
+++ b/spyvm/model.py
@@ -578,10 +578,8 @@
         self.initialize_storage(space, size, weak)
     
     def initialize_storage(self, space, size, weak=False):
-        from spyvm.storage import empty_storage
-        storage = empty_storage(space, self, size, weak)
-        self.store_shadow(storage)
-        self.log_storage("Initialized")
+        storage = space.strategy_factory.empty_storage(self, size, weak)
+        self.store_shadow(storage, operation="Initialized")
     
     def fillin(self, space, g_self):
         W_AbstractObjectWithClassReference.fillin(self, space, g_self)
@@ -589,12 +587,10 @@
         for g_obj in g_self.pointers:
             g_obj.fillin(space)
         pointers = g_self.get_pointers()
-        # TODO -- Also handle weak objects loaded from images.
-        from spyvm.storage import find_storage_for_objects
-        storage = find_storage_for_objects(space, pointers, g_self.isweak())(space, self, len(pointers))
-        self.store_shadow(storage)
+        storage_type = space.strategy_factory.strategy_type_for(pointers, g_self.isweak())
+        storage = storage_type(space, self, len(pointers))
+        self.store_shadow(storage, operation="Filledin", log_classname=False)
         self.store_all(space, pointers)
-        self.log_storage("Filledin", log_classname=False)
     
     def is_weak(self):
         from storage import WeakListStorageShadow
@@ -620,12 +616,6 @@
         self.store_shadow(new_shadow)
         old_shadow.copy_into(new_shadow)
         new_shadow.attach_shadow()
-        self.log_storage("Switched", old_shadow, w_element=w_element)
-    
-    def store_with_new_storage(self, new_storage, n0, w_val):
-        space = self.space()
-        self.switch_shadow(new_storage(space, self, self.size()), w_element=w_val)
-        self.store(space, n0, w_val)
     
     def space(self):
         return self.assert_shadow().space
@@ -685,8 +675,10 @@
     def instsize(self):
         return self.class_shadow(self.space()).instsize()
 
-    def store_shadow(self, shadow):
+    def store_shadow(self, shadow, operation="", w_element=None, log_classname=True):
+        old_shadow = self.shadow
         self.shadow = shadow
+        self.log_storage(operation, old_shadow, log_classname, w_element)
 
     def _get_shadow(self):
         return self.shadow
@@ -696,8 +688,7 @@
         old_shadow = self._get_shadow()
         shadow = old_shadow
         if not isinstance(old_shadow, TheClass):
-            shadow = TheClass(space, self, old_shadow.size())
-            self.switch_shadow(shadow)
+            shadow = space.strategy_factory.switch_strategy(old_shadow, TheClass)
         return shadow
 
     def get_shadow(self, space):
diff --git a/spyvm/objspace.py b/spyvm/objspace.py
--- a/spyvm/objspace.py
+++ b/spyvm/objspace.py
@@ -1,6 +1,6 @@
 import os
 
-from spyvm import constants, model, model_display, wrapper, version, display
+from spyvm import constants, model, model_display, wrapper, version, display, storage
 from spyvm.error import UnwrappingError, WrappingError, PrimitiveFailedError
 from rpython.rlib import jit, rpath
 from rpython.rlib.objectmodel import instantiate, specialize, import_from_mixin
@@ -66,6 +66,7 @@
         w_nil.w_class = None
         self.add_bootstrap_object("w_nil", w_nil)
         
+        self.strategy_factory = storage.StrategyFactory(self)
         self.make_bootstrap_classes()
         self.make_bootstrap_objects()
 
diff --git a/spyvm/storage.py b/spyvm/storage.py
--- a/spyvm/storage.py
+++ b/spyvm/storage.py
@@ -1,9 +1,10 @@
 
-import sys, weakref
+import weakref
 from spyvm import model, version, constants
 from spyvm.version import elidable_for_version
 from rpython.rlib import objectmodel, jit
 from rpython.rlib.objectmodel import import_from_mixin
+import rstrategies as rstrat
 
 class AbstractShadow(object):
     """A shadow is an optional extra bit of information that
@@ -60,211 +61,94 @@
 # ========== Storage classes implementing storage strategies ==========
 
 class AbstractStorageShadow(AbstractShadow):
-    _attrs_ = []
     repr_classname = "AbstractStorageShadow"
+    import_from_mixin(rstrat.SafeIndexingMixin)
     
-    def store(self, n0, w_val):
-        if self.can_contain(w_val):
-            return self.do_store(n0, w_val)
-        new_storage = self.generalized_strategy_for(w_val)
-        return self._w_self.store_with_new_storage(new_storage, n0, w_val)
-    def can_contain(self, w_val):
-        return self.static_can_contain(self.space, w_val)
-    @staticmethod
-    def static_can_contain(space, w_val):
-        raise NotImplementedError()
-    def do_store(self, n0, w_val):
-        raise NotImplementedError()
-    def generalized_strategy_for(self, w_val):
-        raise NotImplementedError()
+    def __init__(self, space, w_self, size):
+        AbstractShadow.__init__(self, space, w_self, size)
+        self.init_strategy(size)
     
-    def copy_from_AllNil(self, all_nil_storage):
-        pass # Already initialized
-    def copy_from(self, other_shadow):
-        assert self.size() == other_shadow.size()
-        for i in range(self.size()):
-            w_val = other_shadow.fetch(i)
-            if not w_val.is_nil(self.space): # nil fields already initialized
-                self.store(i, w_val)
+    def strategy_factory(self):
+        return self.space.strategy_factory
+    
+    def copy_from_AllNilStrategy(self, all_nil_storage):
+        pass # Fields already initialized to nil
 
 class AllNilStorageShadow(AbstractStorageShadow):
     repr_classname = "AllNilStorageShadow"
-    _attrs_ = ['_size']
-    _immutable_fields_ = ['_size']
-    def __init__(self, space, w_self, size):
-        AbstractStorageShadow.__init__(self, space, w_self, size)
-        self._size = size
-    def fetch(self, n0):
-        if n0 >= self._size:
-            raise IndexError
-        return self.space.w_nil
-    def copy_into(self, other_shadow):
-        other_shadow.copy_from_AllNil(self)
-    def do_store(self, n0, w_value):
-        pass
-    def size(self):
-        return self._size
-    def generalized_strategy_for(self, w_val):
-        return find_storage_for_objects(self.space, [w_val])
-    @staticmethod
-    def static_can_contain(space, w_val):
-        return isinstance(w_val, model.W_Object) and w_val.is_nil(space)
-
-class AbstractValueOrNilStorageMixin(object):
-    # Class must provide: wrap, unwrap, nil_value, is_nil_value, wrapper_class
-    _attrs_ = ['storage']
-    _immutable_fields_ = ['storage']
-
-    def __init__(self, space, w_self, size):
-        AbstractStorageShadow.__init__(self, space, w_self, size)
-        self.storage = [self.nil_value] * size
-
-    def size(self):
-        return len(self.storage)
-
-    def generalized_strategy_for(self, w_val):
-        return ListStorageShadow
-
-    def fetch(self, n0):
-        val = self.storage[n0]
-        if self.is_nil_value(val):
-            return self.space.w_nil
-        else:
-            return self.wrap(self.space, val)
-
-    def do_store(self, n0, w_val):
-        if w_val.is_nil(self.space):
-            self.storage[n0] = self.nil_value
-        else:
-            self.storage[n0] = self.unwrap(self.space, w_val)
-
-# This is to avoid code duplication
- at objectmodel.specialize.arg(0)
-def _value_or_nil_can_handle(cls, space, w_val):
-    return isinstance(w_val, model.W_Object) and w_val.is_nil(space) or \
-            (isinstance(w_val, cls.wrapper_class) \
-            and not cls.is_nil_value(cls.unwrap(space, w_val)))
+    import_from_mixin(rstrat.SingleValueStrategy)
+    def value(self): return self.space.w_nil
 
 class SmallIntegerOrNilStorageShadow(AbstractStorageShadow):
     repr_classname = "SmallIntegerOrNilStorageShadow"
-    nil_value = constants.MAXINT
-    wrapper_class = model.W_SmallInteger
-    import_from_mixin(AbstractValueOrNilStorageMixin)
-
-    @staticmethod
-    def static_can_contain(space, w_val):
-        return _value_or_nil_can_handle(SmallIntegerOrNilStorageShadow, space, w_val)
-    @staticmethod
-    def is_nil_value(val):
-        return val == SmallIntegerOrNilStorageShadow.nil_value
-    @staticmethod
-    def wrap(space, val):
-        return space.wrap_int(val)
-    @staticmethod
-    def unwrap(space, w_val):
-        return space.unwrap_int(w_val)
-    def copy_into(self, other_shadow):
-        other_shadow.copy_from_SmallIntegerOrNil(self)
+    import_from_mixin(rstrat.TaggingStrategy)
+    contained_type = model.W_SmallInteger
+    def wrap(self, val): return self.space.wrap_int(val)
+    def unwrap(self, w_val): return self.space.unwrap_int(w_val)
+    def default_value(self): return self.space.w_nil
+    def wrapped_tagged_value(self): return self.space.w_nil
+    def unwrapped_tagged_value(self): return constants.MAXINT
 
 class FloatOrNilStorageShadow(AbstractStorageShadow):
     repr_classname = "FloatOrNilStorageShadow"
-    nil_value = sys.float_info.max
-    wrapper_class = model.W_Float
-    import_from_mixin(AbstractValueOrNilStorageMixin)
-
-    @staticmethod
-    def static_can_contain(space, w_val):
-        return _value_or_nil_can_handle(FloatOrNilStorageShadow, space, w_val)
-    @staticmethod
-    def is_nil_value(val):
-        return val == FloatOrNilStorageShadow.nil_value
-    @staticmethod
-    def wrap(space, val):
-        return space.wrap_float(val)
-    @staticmethod
-    def unwrap(space, w_val):
-        return space.unwrap_float(w_val)
-    def copy_into(self, other_shadow):
-        other_shadow.copy_from_FloatOrNil(self)
-
-def empty_storage(space, w_self, size, weak=False):
-    if weak:
-        return WeakListStorageShadow(space, w_self, size)
-    if space.no_specialized_storage.is_set():
-        return ListStorageShadow(space, w_self, size)
-    return AllNilStorageShadow(space, w_self, size)
-
- at jit.unroll_safe
-def find_storage_for_objects(space, vars, weak=False):
-    if weak:
-        return WeakListStorageShadow
-    if space.no_specialized_storage.is_set():
-        return ListStorageShadow
-    specialized_strategies = 3
-    all_nil_can_handle = True
-    small_int_can_handle = True
-    float_can_handle = True
-    for w_obj in vars:
-        if all_nil_can_handle and not AllNilStorageShadow.static_can_contain(space, w_obj):
-            all_nil_can_handle = False
-            specialized_strategies = specialized_strategies - 1
-        if small_int_can_handle and not SmallIntegerOrNilStorageShadow.static_can_contain(space, w_obj):
-            small_int_can_handle = False
-            specialized_strategies = specialized_strategies - 1
-        if float_can_handle and not FloatOrNilStorageShadow.static_can_contain(space, w_obj):
-            float_can_handle = False
-            specialized_strategies = specialized_strategies - 1
-
-        if specialized_strategies <= 0:
-            return ListStorageShadow
-
-    if all_nil_can_handle:
-        return AllNilStorageShadow
-    if small_int_can_handle:
-        return SmallIntegerOrNilStorageShadow
-    if float_can_handle:
-        return FloatOrNilStorageShadow
-
-    # If this happens, please look for a bug in the code above.
-    assert False, "No strategy could be found for list..."
-
-class ListStorageMixin(object):
-    def __init__(self, space, w_self, size):
-        AbstractStorageShadow.__init__(self, space, w_self, size)
-        self.initialize_storage(size)
-    def size(self):
-        return len(self.storage)
+    import_from_mixin(rstrat.TaggingStrategy)
+    contained_type = model.W_Float
+    def wrap(self, val): return self.space.wrap_float(val)
+    def unwrap(self, w_val): return self.space.unwrap_float(w_val)
+    def default_value(self): return self.space.w_nil
+    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):
-    _attrs_ = ['storage']
-    _immutable_fields_ = ['storage']
     repr_classname = "ListStorageShadow"
-    import_from_mixin(ListStorageMixin)
-
-    def initialize_storage(self, size):
-        self.storage = [self.space.w_nil] * size
-    def fetch(self, n0):
-        return self.storage[n0]
-    def store(self, n0, w_value):
-        self.storage[n0] = w_value
+    import_from_mixin(rstrat.GenericStrategy)
+    def default_value(self): return self.space.w_nil
 
 class WeakListStorageShadow(AbstractStorageShadow):
-    _attrs_ = ['storage']
-    _immutable_fields_ = ['storage']
     repr_classname = "WeakListStorageShadow"
-    import_from_mixin(ListStorageMixin)
+    import_from_mixin(rstrat.WeakGenericStrategy)
+    def default_value(self): return self.space.w_nil
 
-    def initialize_storage(self, size):
-        self.storage = [weakref.ref(self.space.w_nil)] * size
-    def fetch(self, n0):
-        weakobj = self.storage[n0]
-        return weakobj() or self.space.w_nil
-    def store(self, n0, w_value):
-        assert w_value is not None
-        self.storage[n0] = weakref.ref(w_value)
-        
+class StrategyFactory(rstrat.StrategyFactory):
+    _immutable_fields_ = ["space", "no_specialized_storage?"]
+    def __init__(self, space):
+        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],
+        })
+    
+    def strategy_type_for(self, objects, weak=False):
+        if weak:
+            WeakListStorageShadow
+        if self.no_specialized_storage.is_set():
+            return ListStorageShadow
+        return rstrat.StrategyFactory.strategy_type_for(self, objects)
+    
+    def empty_storage(self, w_self, size, weak=False):
+        if weak:
+            return WeakListStorageShadow(self.space, w_self, size)
+        if self.no_specialized_storage.is_set():
+            return ListStorageShadow(self.space, w_self, size)
+        return AllNilStorageShadow(self.space, w_self, size)
+    
+    def instantiate_and_switch(self, old_strategy, size, strategy_class):
+        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):
+        return strategy_type(self.space, None, 0)
+
 # ========== Other storage classes, non-strategies ==========
-        
+
 class AbstractRedirectingShadow(AbstractShadow):
     _attrs_ = ['_w_self_size']
     repr_classname = "AbstractRedirectingShadow"
diff --git a/targetimageloadingsmalltalk.py b/targetimageloadingsmalltalk.py
--- a/targetimageloadingsmalltalk.py
+++ b/targetimageloadingsmalltalk.py
@@ -129,7 +129,7 @@
             elif arg in ["--hacks"]:
                 space.run_spy_hacks.activate()
             elif arg in ["-S"]:
-                space.no_specialized_storage.activate()
+                space.strategy_factory.no_specialized_storage.activate()
             elif arg in ["-u"]:
                 from spyvm.plugins.vmdebugging import stop_ui_process
                 stop_ui_process()


More information about the pypy-commit mailing list