Author: Anton Gulenko <[email protected]>
Branch: strategies-tagging
Changeset: r669:f63aa764c7bf
Date: 2014-03-20 11:39 +0100
http://bitbucket.org/pypy/lang-smalltalk/changeset/f63aa764c7bf/
Log: Refactoring to remove rerased and use two separate variables for
wrapped and unwrapped storage.
diff --git a/spyvm/model.py b/spyvm/model.py
--- a/spyvm/model.py
+++ b/spyvm/model.py
@@ -653,16 +653,15 @@
strategy_stats = StrategyStatistics()
class W_PointersObject(W_AbstractPointersObject):
- _attrs_ = ['_storage', 'strategy']
+ _attrs_ = ['_size', '_storage', 'int_storage', 'strategy']
@jit.unroll_safe
def __init__(self, space, w_class, size):
from spyvm.strategies import strategy_of_size
"""Create new object with size = fixed + variable size."""
W_AbstractPointersObject.__init__(self, space, w_class, size)
- # TODO - setting strategy/storage is useless if fillin() will be
called afterwards.
self.strategy = strategy_of_size(self.s_class, size)
- self.set_storage(self.strategy.initial_storage(space, size))
+ self.set_storage(space, size)
self.log_strategy_operation("Initialized")
def log_strategy_operation(self, op, old_strategy=None):
@@ -680,11 +679,12 @@
if strategy_stats.do_log:
strategy_stats.log_operation(op, new_strategy_tag,
old_strategy_tag, classname, size)
- def set_storage(self, storage):
- self._storage = storage
-
- def get_storage(self):
- return self._storage
+ def set_storage(self, space, size):
+ self._size = size
+ if self.strategy.uses_int_storage:
+ self.int_storage = self.strategy.initial_int_storage(space, size)
+ else:
+ self._storage = self.strategy.initial_storage(space, size)
def get_strategy(self):
return self.strategy
@@ -692,7 +692,11 @@
def fillin_pointers(self, space, collection):
from spyvm.strategies import strategy_for_list
self.strategy = strategy_for_list(self.s_class, collection)
- self.set_storage(self.strategy.storage_for_list(space, collection))
+ self._size = len(collection)
+ if self.strategy.uses_int_storage:
+ self.int_storage = self.strategy.int_storage_for_list(space,
collection)
+ else:
+ self._storage = self.strategy.storage_for_list(space, collection)
def fillin(self, space, g_self):
W_AbstractPointersObject.fillin(self, space, g_self)
@@ -701,10 +705,12 @@
def switch_strategy(self, space, new_strategy):
assert self.strategy != new_strategy
- new_storage = new_strategy.copy_storage_from(space, self,
reuse_storage=True)
+ if new_strategy.uses_int_storage:
+ self.int_storage = new_strategy.copy_int_storage_from(space, self,
reuse_storage=True)
+ else:
+ self._storage = new_strategy.copy_storage_from(space, self,
reuse_storage=True)
old_strategy = self.strategy
self.strategy = new_strategy
- self.set_storage(new_storage)
self.log_strategy_operation("Switched", old_strategy)
def store_with_new_strategy(self, space, new_strategy, n0, w_val):
@@ -735,15 +741,15 @@
return self.get_strategy().store(space, self, n0, w_value)
def basic_size(self):
- return self.get_strategy().size_of(self)
+ return self._size
def become(self, w_other):
if not isinstance(w_other, W_PointersObject):
return False
self.strategy, w_other.strategy = w_other.strategy, self.strategy
- self_storage = self._storage
- self.set_storage(w_other._storage)
- w_other.set_storage(self_storage)
+ self._size, w_other._size = w_other._size, self._size
+ self._storage, w_other._storage = w_other._storage, self._storage
+ self.int_storage, w_other.int_storage = w_other.int_storage,
self.int_storage
return W_AbstractPointersObject.become(self, w_other)
@jit.unroll_safe
diff --git a/spyvm/objspace.py b/spyvm/objspace.py
--- a/spyvm/objspace.py
+++ b/spyvm/objspace.py
@@ -165,7 +165,7 @@
from spyvm.strategies import ListStorageStrategy
w_nil.space = self
w_nil.strategy = ListStorageStrategy.singleton
- w_nil.set_storage(w_nil.strategy.initial_storage(self, 0))
+ w_nil.set_storage(self, 0)
w_nil.s_class =
self.classtable['w_UndefinedObject'].as_class_get_penumbra(self)
return w_nil
w_nil = self.w_nil = patch_nil(model.w_nil)
diff --git a/spyvm/shadow.py b/spyvm/shadow.py
--- a/spyvm/shadow.py
+++ b/spyvm/shadow.py
@@ -432,7 +432,7 @@
self.copy_from_w_self(i)
except error.SenderChainManipulation, e:
assert e.s_context == self
- w_self.set_storage(w_self.strategy.initial_storage(self.space, 0))
+ w_self.set_storage(self.space, 0)
# def detach_shadow(self):
# w_self = self.w_self()
diff --git a/spyvm/strategies.py b/spyvm/strategies.py
--- a/spyvm/strategies.py
+++ b/spyvm/strategies.py
@@ -14,6 +14,7 @@
_attrs_ = []
_settled_ = True
strategy_tag = 'abstract'
+ uses_int_storage = False
def __init__(self):
pass
@@ -31,14 +32,23 @@
def initial_storage(self, space, size):
raise NotImplementedError("Abstract base class")
+ def initial_int_storage(self, space, size):
+ raise NotImplementedError("Abstract base class")
def storage_for_list(self, space, collection):
raise NotImplementedError("Abstract base class")
+ def int_storage_for_list(self, space, collection):
+ raise NotImplementedError("Abstract base class")
+ def copy_int_storage_from(self, space, w_obj, reuse_storage=False):
+ old_strategy = w_obj.strategy
+ if old_strategy == self and reuse_storage:
+ return w_obj.int_storage
+ else:
+ # This can be overridden and optimized (reuse_storage flag, less
temporary storage)
+ return self.int_storage_for_list(space, w_obj.fetch_all(space))
def copy_storage_from(self, space, w_obj, reuse_storage=False):
old_strategy = w_obj.strategy
if old_strategy == self and reuse_storage:
- return w_obj.get_storage()
- if isinstance(old_strategy, AllNilStorageStrategy):
- return self.initial_storage(space, old_strategy.size_of(w_obj))
+ return w_obj._storage
else:
# This can be overridden and optimized (reuse_storage flag, less
temporary storage)
return self.storage_for_list(space, w_obj.fetch_all(space))
@@ -51,22 +61,24 @@
class BasicStorageStrategyMixin(object):
# Concrete class must implement: unerase
+ def size_of(self, w_obj):
+ if self.uses_int_storage:
+ return len(self.int_storage(w_obj))
+ else:
+ return len(self.storage(w_obj))
+ def int_storage(self, w_obj):
+ return w_obj.int_storage
def storage(self, w_obj):
- return self.unerase(w_obj.get_storage())
-
-# This is a container for an int-value to be used with a rerased-pair
-class SizeStorage(object):
- _attrs_ = ['size']
- _settled_ = True
- def __init__(self, size):
- self.size = size
+ return w_obj._storage
+ def erase(self, a): return a
+ def unerase(self, a): return a
# this is the typical "initial" storage strategy, for when every slot
# in a var-sized object is still nil. No storage is allocated except for
# holding the size of the object.
class AllNilStorageStrategy(AbstractStorageStrategy):
__metaclass__ = SingletonMeta
- erase, unerase = rerased.new_static_erasing_pair("all-nil-strategy")
+ # erase, unerase = rerased.new_static_erasing_pair("all-nil-strategy")
import_from_mixin(BasicStorageStrategyMixin)
strategy_tag = 'allnil'
@@ -82,21 +94,19 @@
return w_obj.store_with_new_strategy(space,
TaggingSmallIntegerStorageStrategy.singleton, n0, w_val)
return w_obj.store_with_new_strategy(space,
ListStorageStrategy.singleton, n0, w_val)
- def size_of(self, w_obj):
- return self.storage(w_obj).size
def initial_storage(self, space, size):
- return self.erase(SizeStorage(size))
+ return []
def storage_for_list(self, space, collection):
- return self.erase(SizeStorage(len(collection)))
+ return []
def copy_storage_from(self, space, w_obj, reuse_storage=False):
- return self.erase(SizeStorage(w_obj.basic_size()))
+ return []
# This is the regular storage strategy that does not result in any
# optimizations but can handle every case. Applicable for both
# fixed-sized and var-sized objects.
class ListStorageStrategy(AbstractStorageStrategy):
__metaclass__ = SingletonMeta
- erase, unerase = rerased.new_static_erasing_pair("list-storage-strategy")
+ # erase, unerase = rerased.new_static_erasing_pair("list-storage-strategy")
import_from_mixin(BasicStorageStrategyMixin)
strategy_tag = 'list'
@@ -105,8 +115,6 @@
def store(self, space, w_obj, n0, w_val):
# TODO enable generalization by maintaining a counter of elements that
are nil.
self.storage(w_obj)[n0] = w_val
- def size_of(self, w_obj):
- return len(self.storage(w_obj))
def erased_list(self, list):
make_sure_not_resized(list)
return self.erase(list)
@@ -117,147 +125,13 @@
def copy_storage_from(self, space, w_obj, reuse_storage=False):
length = w_obj.basic_size()
return self.erased_list([w_obj.strategy.fetch(space, w_obj, i) for i
in range(length)])
-
-class DenseStorage(object):
- # Subclass must provide attribute: default_element
- _immutable_fields_ = ['arr']
- _attrs_ = ['arr', '_from', '_to']
- _settled_ = True
-
- def __init__(self, _from, _to, size):
- self._from = _from # first used index ("inclusive")
- self._to = _to # first unused index ("exclusive")
- self.arr = [self.default_element] * size
- make_sure_not_resized(self.arr)
-
-class DenseStorageStrategyMixin(object):
- # Concrete class must implement: storage, erase, do_fetch, do_store,
sparse_strategy
- # Concrete class must provide attributes: storage_type (subclass of
DenseStorage)
-
- def fetch(self, space, w_obj, n0):
- store = self.storage(w_obj)
- if n0 < store._from or n0 >= store._to:
- return model.w_nil
- return self.do_fetch(space, store.arr, n0)
- def store(self, space, w_obj, n0, w_val):
- store = self.storage(w_obj)
- if not self.can_contain_object(w_val):
- if w_val == model.w_nil:
- if store._to - 1 == n0: # Optimize Collection >> remove:
- store._to = store._to - 1
- elif n0 < store._from or store._to <= n0:
- pass # Storing nil to an already-nil position
- elif store._from == n0:
- store._from = store._from + 1
- else:
- # Deletion from the middle of the storage. Deoptimize to
sparse storage.
- return w_obj.store_with_new_strategy(space,
self.sparse_strategy().singleton, n0, w_val)
- if store._from == store._to:
- # Deleted last element. Generelize to AllNilStorage.
- w_obj.switch_strategy(space,
AllNilStorageStrategy.singleton)
- return
- else:
- # Storing a non-int - dehomogenize to ListStorage
- return w_obj.store_with_new_strategy(space,
ListStorageStrategy.singleton, n0, w_val)
- if n0 == store._to: # Optimize Collection >> add:
- store._to = store._to+1
- elif store._from <= n0 and n0 < store._to:
- pass
- elif n0 == store._from - 1: # It's ok if this wraps around.
- store._from = store._from-1
- else:
- if store._from == store._to:
- # Initial store to non-zero position.
- store._from = n0
- store._to = n0+1
- else:
- # Store to a non-dense position. Deoptimize to sparse storage.
- return w_obj.store_with_new_strategy(space,
self.sparse_strategy().singleton, n0, w_val)
- # It is a dense store, so finally store the unwrapped value.
- self.do_store(space, store.arr, n0, w_val)
- def initial_storage(self, space, size):
- return self.erase(self.storage_type(0, 0, size))
- def storage_for_list(self, space, collection):
- _from = 0
- while _from < len(collection) and collection[_from] == model.w_nil:
- _from = _from+1
- _to = _from
- while _to < len(collection) and collection[_to] != model.w_nil:
- _to = _to+1
- store = self.storage_type(_from, _to, len(collection))
- for i in range(_from, _to):
- self.do_store(space, store.arr, i, collection[i])
- return self.erase(store)
-
-class SparseStorage(object):
- _immutable_fields_ = ['arr', 'nil_flags']
- _attrs_ = ['arr', 'nil_flags']
- _settled_ = True
-
- def __init__(self, arr, nil_flags):
- self.arr = arr
- self.nil_flags = nil_flags
- make_sure_not_resized(self.arr)
- make_sure_not_resized(self.nil_flags)
-
-class SparseStorageStrategyMixin(object):
- # Concrete class must implement: storage, erase, do_fetch, do_store,
dense_strategy
- # Concrete class must provide attributes: storage_type (Subclass of
SparseStorage)
-
- def fetch(self, space, w_obj, n0):
- store = self.storage(w_obj)
- if store.nil_flags[n0]:
- return model.w_nil
- return self.do_fetch(space, store.arr, n0)
- def store(self, space, w_obj, n0, w_val):
- store = self.storage(w_obj)
- if not self.can_contain_object(w_val):
- if w_val == model.w_nil:
- # TODO - generelize to AllNilStorage by maintaining a counter
of nil-elements
- store.nil_flags[n0] = True
- return
- else:
- # Storing a wrong type - dehomogenize to ListStorage
- return w_obj.store_with_new_strategy(space,
ListStorageStrategy.singleton, n0, w_val)
- store.nil_flags[n0] = False
- self.do_store(space, store.arr, n0, w_val)
- def storage_for_size(self, size):
- # TODO -- for inlining strategy, the size must be extended!!
- # size = size * self.slots_per_object()
- return self.storage_type([self.storage_type.default_element] * size,
[True] * size)
- def initial_storage(self, space, size):
- return self.erase(self.storage_for_size(size))
- def storage_for_list(self, space, collection):
- length = len(collection)
- store = self.storage_for_size(length)
- for i in range(length):
- if collection[i] != model.w_nil:
- store.nil_flags[i] = False
- self.do_store(space, store.arr, i, collection[i])
- return self.erase(store)
- def copy_storage_from(self, space, w_obj, reuse_storage=False):
- old_strategy = w_obj.strategy
- if isinstance(old_strategy, self.dense_strategy()):
- # Optimized transition from dense to sparse strategy
- store = old_strategy.storage(w_obj)
- return self.erase(self.copy_from_dense_storage(store,
reuse_storage))
- else:
- return AbstractStorageStrategy.copy_storage_from(self, space,
w_obj, reuse_storage)
- def copy_from_dense_storage(self, store, reuse_storage):
- # TODO possible optimization: compare len(arr) with _to-_from, use
smaller iteration size
- nil_flags = [True] * len(store.arr)
- for i in range(store._from, store._to):
- nil_flags[i] = False
- arr = store.arr
- if not reuse_storage:
- arr = [x for x in arr]
- return self.storage_type(arr, nil_flags)
class TaggingSmallIntegerStorageStrategy(AbstractStorageStrategy):
__metaclass__ = SingletonMeta
strategy_tag = 'tagging-small-int'
- erase, unerase =
rerased.new_static_erasing_pair("tagging-small-integer-strategry")
+ # erase, unerase =
rerased.new_static_erasing_pair("tagging-small-integer-strategry")
import_from_mixin(BasicStorageStrategyMixin)
+ uses_int_storage = True
@staticmethod
def wrap(val):
@@ -266,9 +140,6 @@
def unwrap(val):
return val >> 1
@staticmethod
- def is_nil(val):
- return (val & 1) == 1
- @staticmethod
def can_contain(w_val):
return isinstance(w_val, model.W_SmallInteger)
# TODO - use just a single value to represent nil (max_int-1)
@@ -280,35 +151,32 @@
return True
def fetch(self, space, w_obj, n0):
- val = self.storage(w_obj)[n0]
- if (self.is_nil(val)):
+ val = self.int_storage(w_obj)[n0]
+ if val == self.nil_value:
return space.w_nil
else:
return space.wrap_int(self.unwrap(val))
def store(self, space, w_obj, n0, w_val):
- store = self.storage(w_obj)
+ store = self.int_storage(w_obj)
if self.can_contain(w_val):
store[n0] = self.wrap(space.unwrap_int(w_val))
else:
- if w_val == model.w_nil:
+ if w_val == space.w_nil:
# TODO - generelize to AllNilStorage by maintaining a counter
of nil-elements
store[n0] = self.nil_value
else:
# Storing a wrong type - dehomogenize to ListStorage
return w_obj.store_with_new_strategy(space,
ListStorageStrategy.singleton, n0, w_val)
- def size_of(self, w_obj):
- return len(self.storage(w_obj))
-
- def initial_storage(self, space, size):
+ def initial_int_storage(self, space, size):
return self.erase([self.nil_value] * size)
- def storage_for_list(self, space, collection):
+ def int_storage_for_list(self, space, collection):
length = len(collection)
store = [self.nil_value] * length
for i in range(length):
- if collection[i] != model.w_nil:
+ if collection[i] != space.w_nil:
store[i] = self.wrap(space.unwrap_int(collection[i]))
return self.erase(store)
@@ -324,8 +192,8 @@
def strategy_for_list(s_containing_class, vars):
if s_containing_class is None:
- # This is a weird and rare special case for w_nil
- return ListStorageStrategy.singleton
+ # This is a weird and rare special case for w_nil
+ return ListStorageStrategy.singleton
try:
is_variable = s_containing_class.isvariable()
except AttributeError:
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
@@ -16,7 +16,7 @@
def __init__(self, stack):
size = 6 + len(stack) + 6
self.strategy = strategies.ListStorageStrategy.singleton
- self.set_storage(self.strategy.initial_storage(space, size))
+ self.set_storage(space, size)
self.store_all(space, [None] * 6 + stack + [space.w_nil] * 6)
s_self = self.as_blockcontext_get_shadow()
s_self.init_stack_and_temps()
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit