Author: Anton Gulenko <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit