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