Author: Anton Gulenko <anton.gule...@googlemail.com>
Branch: storage
Changeset: r708:969853688ab7
Date: 2014-03-27 14:47 +0100
http://bitbucket.org/pypy/lang-smalltalk/changeset/969853688ab7/

Log:    Added code for specialized storage strategies. Fillin-sequence has
        to be done recursively, in order for the specialized storage
        strategies to work.

diff --git a/spyvm/model.py b/spyvm/model.py
--- a/spyvm/model.py
+++ b/spyvm/model.py
@@ -471,6 +471,8 @@
     
     def fillin(self, space, g_self):
         W_AbstractObjectWithIdentityHash.fillin(self, space, g_self)
+        # The class data will be initialized lazily, after the initial 
fillin-sequence is over.
+        # Don't construct the ClassShadow here, yet!
         self.w_class = g_self.get_class()
         
     def getclass(self, space):
@@ -547,7 +549,7 @@
 class W_AbstractPointersObject(W_AbstractObjectWithClassReference):
     """Common object."""
     _attrs_ = ['shadow']
-    shadow = None # Default value
+    shadow = None
     repr_classname = "W_AbstractPointersObject"
     
     @jit.unroll_safe
@@ -555,16 +557,34 @@
         """Create new object with size = fixed + variable size."""
         W_AbstractObjectWithClassReference.__init__(self, space, w_class)
         self.initialize_storage(space, size)
-
+        
     def initialize_storage(self, space, size):
-        self.store_shadow(self.default_storage(space, size))
+        self.store_shadow(self.empty_storage(space, size))
         
     def fillin(self, space, g_self):
         W_AbstractObjectWithClassReference.fillin(self, space, g_self)
+        # Recursive fillin required to enable specialized storage strategies.
+        for g_obj in g_self.pointers:
+            g_obj.fillin(space)
         pointers = g_self.get_pointers()
-        self.initialize_storage(space, len(pointers))
+        self.store_shadow(self.storage_for_list(space, pointers))
         self.store_all(space, pointers)
         
+    def empty_storage(self, space, size):
+        raise NotImplementedError()
+    def storage_for_list(self, space, vars):
+        raise NotImplementedError()
+    
+    def switch_shadow(self, new_shadow):
+        if self.shadow is not None:
+            new_shadow.copy_from(self.shadow)
+        self.store_shadow(new_shadow)
+        new_shadow.attach_shadow()
+    
+    def store_with_new_storage(self, new_storage, n0, w_val):
+        self.switch_shadow(new_storage(self.space(), self, self.size()))
+        self.store(self.space(), n0, w_val)
+    
     def space(self):
         assert self.shadow, "Cannot access space without a shadow!"
         return self.shadow.space
@@ -637,10 +657,7 @@
         shadow = old_shadow
         if not isinstance(old_shadow, TheClass):
             shadow = TheClass(space, self)
-            if old_shadow is not None:
-                shadow.copy_from(old_shadow)
-            self.store_shadow(shadow)
-            shadow.attach_shadow()
+            self.switch_shadow(shadow)
         return shadow
 
     def get_shadow(self, space):
@@ -702,15 +719,27 @@
         
 class W_PointersObject(W_AbstractPointersObject):
     repr_classname = 'W_PointersObject'
-    def default_storage(self, space, size):
-        from spyvm.shadow import ListStorageShadow
-        return ListStorageShadow(space, self, size)
+    
+    def empty_storage(self, space, size):
+        # A newly allocated object contains only nils.
+        from spyvm.shadow import AllNilStorageShadow
+        return AllNilStorageShadow(space, self, size)
+    
+    def storage_for_list(self, space, vars):
+        #if not self.class_shadow(space).isvariable():
+        #   return ListStorageShadow(space, self, len(vars))
+        from spyvm.shadow import find_storage_for_objects
+        return find_storage_for_objects(space, vars)(space, self, len(vars))
 
 class W_WeakPointersObject(W_AbstractPointersObject):
     repr_classname = 'W_WeakPointersObject'
-    def default_storage(self, space, size):
+    
+    def empty_storage(self, space, size):
         from spyvm.shadow import WeakListStorageShadow
         return WeakListStorageShadow(space, self, size)
+    def storage_for_list(self, space, vars):
+        from spyvm.shadow import WeakListStorageShadow
+        return WeakListStorageShadow(space, self, len(vars))
 
 class W_BytesObject(W_AbstractObjectWithClassReference):
     _attrs_ = ['bytes', 'c_bytes', '_size']
diff --git a/spyvm/shadow.py b/spyvm/shadow.py
--- a/spyvm/shadow.py
+++ b/spyvm/shadow.py
@@ -2,9 +2,11 @@
 from spyvm import model, constants, error, wrapper, version
 from spyvm.version import elidable_for_version, constant_for_version
 from rpython.tool.pairtype import extendabletype
-from rpython.rlib import rarithmetic, jit
+from rpython.rlib import rarithmetic, jit, longlong2float
 from rpython.rlib.objectmodel import import_from_mixin
 from rpython.rlib.debug import make_sure_not_resized
+from rpython.rlib.rstruct.runpack import runpack
+from rpython.rtyper.lltypesystem import rffi, lltype
 
 class AbstractShadow(object):
     """A shadow is an optional extra bit of information that
@@ -46,20 +48,145 @@
         for i in range(self.size()):
             self.copy_field_from(i, other_shadow)
 
-class AllNilStorageShadow(AbstractShadow):
+class AbstractStorageShadow(AbstractShadow):
+    repr_classname = "AbstractStorageShadow"
+    def store(self, n0, w_val):
+        if self.can_contain(w_val):
+            return self.do_store(n0, w_val)
+        new_storage = self.generelized_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)
+    def do_store(self, n0, w_val):
+        raise NotImplemtedError()
+    def generelized_strategy_for(self, w_val):
+        raise NotImplemtedError()
+
+class AllNilStorageShadow(AbstractStorageShadow):
+    repr_classname = "AllNilStorageShadow"
+    _attrs_ = ['_size']
+    _immutable_fields_ = ['_size']
+    def __init__(self, space, w_self, size):
+        AbstractShadow.__init__(self, space, w_self)
+        self._size = size
     def fetch(self, n0):
-        raise NotImplementedError("Abstract class")
-    def store(self, n0, w_value):
-        raise NotImplementedError("Abstract class")
+        if n0 >= self._size:
+            raise IndexError
+        return self.space.w_nil
+    def do_store(self, n0, w_value):
+        pass
     def size(self):
-        raise NotImplementedError("Abstract class")
+        return self._size
+    def generelized_strategy_for(self, w_val):
+        return find_storage_for_objects(self.space, [w_val])
+    @staticmethod
+    def static_can_contain(space, w_val):
+        return w_val == space.w_nil
 
-class SmallIntegerOrNilStorageShadow:
-    pass
+class AbstractValueOrNilStorageMixin(object):
+    # Class must provide: wrap, unwrap, nil_value, is_nil_value, wrapper_class
+    storage = []
+    _attrs_ = ['storage']
+    
+    def __init__(self, space, w_self, size):
+        AbstractStorageShadow.__init__(self, space, w_self)
+        self.storage = [self.nil_value] * size
+    
+    def size(self):
+        return len(self.storage)
+    
+    def generelized_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):
+        store = self.storage
+        if w_val == self.space.w_nil:
+            store[n0] = self.nil_value
+        else:
+            store[n0] = self.unwrap(self.space, w_val)
 
-class FloatOrNilStorageShadow:
-    pass
+# This is to avoid code duplication
+def _value_or_nil_can_handle(cls, space, w_val):
+    return w_val == space.w_nil or \
+            (isinstance(w_val, cls.wrapper_class) \
+            and not cls.is_nil_value(cls.unwrap(space, w_val)))
 
+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)
+
+class FloatOrNilStorageShadow(AbstractStorageShadow):
+    repr_classname = "FloatOrNilStorageShadow"
+    # TODO -- use another value... something like max_float?
+    nil_value = runpack("d", "\x10\x00\x00\x00\x00\x00\xf8\x7f")
+    nil_value_longlong = longlong2float.float2longlong(nil_value)
+    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 longlong2float.float2longlong(val) == 
FloatOrNilStorageShadow.nil_value_longlong
+    @staticmethod
+    def wrap(space, val):
+        return space.wrap_float(val)
+    @staticmethod
+    def unwrap(space, w_val):
+        return space.unwrap_float(w_val)
+
+def find_storage_for_objects(space, vars):
+    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 ListStorageShadow(AbstractShadow):
     _attrs_ = ['storage']
     repr_classname = "ListStorageShadow"
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
@@ -22,7 +22,6 @@
 
 class MockFrame(model.W_PointersObject):
     def __init__(self, space, stack):
-        self.space = space
         size = 6 + len(stack) + 6
         self.initialize_storage(space, size)
         self.store_all(space, [None] * 6 + stack + [space.w_nil] * 6)
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to