def test_unerased_pointers_in_short_preamble(self): from pypy.rlib.rerased import new_erasing_pair from pypy.rpython.lltypesystem import lltype class A(object): def __init__(self, val): self.val = val erase_A, unerase_A = new_erasing_pair('A') erase_TP, unerase_TP = new_erasing_pair('TP') TP = lltype.GcArray(lltype.Signed) myjitdriver = JitDriver(greens = [], reds = ['n', 'm', 'i', 'j', 'sa', 'p']) def f(n, m, j): i = sa = 0 p = erase_A(A(7)) while i < n: myjitdriver.jit_merge_point(n=n, m=m, i=i, j=j, sa=sa, p=p) if i < m: sa += unerase_A(p).val elif i == m: a = lltype.malloc(TP, 5) a[0] = 42 p = erase_TP(a) else: sa += unerase_TP(p)[0] sa += A(i).val assert n>0 and m>0 i += j return sa res = self.meta_interp(f, [20, 10, 1]) assert res == f(20, 10, 1)
def test_unerased_pointers_in_short_preamble(self): from pypy.rlib.rerased import new_erasing_pair from pypy.rpython.lltypesystem import lltype class A(object): def __init__(self, val): self.val = val erase_A, unerase_A = new_erasing_pair('A') erase_TP, unerase_TP = new_erasing_pair('TP') TP = lltype.GcArray(lltype.Signed) myjitdriver = JitDriver(greens=[], reds=['n', 'm', 'i', 'j', 'sa', 'p']) def f(n, m, j): i = sa = 0 p = erase_A(A(7)) while i < n: myjitdriver.jit_merge_point(n=n, m=m, i=i, j=j, sa=sa, p=p) if i < m: sa += unerase_A(p).val elif i == m: a = lltype.malloc(TP, 5) a[0] = 42 p = erase_TP(a) else: sa += unerase_TP(p)[0] sa += A(i).val assert n > 0 and m > 0 i += j return sa res = self.meta_interp(f, [20, 10, 1]) assert res == f(20, 10, 1)
class FloatListStrategy(AbstractUnwrappedStrategy, ListStrategy): _none_value = 0.0 _applevel_repr = "float" def wrap(self, floatval): return self.space.wrap(floatval) def unwrap(self, w_float): return self.space.float_w(w_float) erase, unerase = rerased.new_erasing_pair("float") erase = staticmethod(erase) unerase = staticmethod(unerase) def is_correct_type(self, w_obj): return is_W_FloatObject(w_obj) def list_is_correct_type(self, w_list): return w_list.strategy is self.space.fromcache(FloatListStrategy) def sort(self, w_list, reverse): l = self.unerase(w_list.lstorage) sorter = FloatSort(l, len(l)) sorter.sort() if reverse: l.reverse()
class ObjectListStrategy(AbstractUnwrappedStrategy, ListStrategy): _none_value = None _applevel_repr = "object" def unwrap(self, w_obj): return w_obj def wrap(self, item): return item erase, unerase = rerased.new_erasing_pair("object") erase = staticmethod(erase) unerase = staticmethod(unerase) def is_correct_type(self, w_obj): return True def list_is_correct_type(self, w_list): return w_list.strategy is self.space.fromcache(ObjectListStrategy) def init_from_list_w(self, w_list, list_w): w_list.lstorage = self.erase(list_w) def contains(self, w_list, w_obj): return ListStrategy.contains(self, w_list, w_obj) def getitems(self, w_list): return self.unerase(w_list.lstorage)
class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("object") erase = staticmethod(erase) unerase = staticmethod(unerase) def wrap(self, unwrapped): return unwrapped def unwrap(self, wrapped): return wrapped def is_correct_type(self, w_obj): return True def get_empty_storage(self): new_dict = r_dict(self.space.eq_w, self.space.hash_w, force_non_null=True) return self.erase(new_dict) def _never_equal_to(self, w_lookup_type): return False def iter(self, w_dict): return ObjectIteratorImplementation(self.space, self, w_dict) def w_keys(self, w_dict): return self.space.newlist(self.unerase(w_dict.dstorage).keys())
class StringListStrategy(AbstractUnwrappedStrategy, ListStrategy): _none_value = None _applevel_repr = "str" def wrap(self, stringval): return self.space.wrap(stringval) def unwrap(self, w_string): return self.space.str_w(w_string) erase, unerase = rerased.new_erasing_pair("string") erase = staticmethod(erase) unerase = staticmethod(unerase) def is_correct_type(self, w_obj): return is_W_StringObject(w_obj) def list_is_correct_type(self, w_list): return w_list.strategy is self.space.fromcache(StringListStrategy) def sort(self, w_list, reverse): l = self.unerase(w_list.lstorage) sorter = StringSort(l, len(l)) sorter.sort() if reverse: l.reverse() def getitems_str(self, w_list): return self.unerase(w_list.lstorage)
class DictProxyStrategy(DictStrategy): erase, unerase = rerased.new_erasing_pair("dictproxy") erase = staticmethod(erase) unerase = staticmethod(unerase) def __init__(w_self, space): DictStrategy.__init__(w_self, space) def getitem(self, w_dict, w_key): space = self.space w_lookup_type = space.type(w_key) if (space.is_w(w_lookup_type, space.w_str) or # Most common path first space.abstract_issubclass_w(w_lookup_type, space.w_str)): return self.getitem_str(w_dict, space.str_w(w_key)) elif space.abstract_issubclass_w(w_lookup_type, space.w_unicode): try: w_key = space.str(w_key) except OperationError, e: if not e.match(space, space.w_UnicodeEncodeError): raise # non-ascii unicode is never equal to a byte string return None return self.getitem_str(w_dict, space.str_w(w_key)) else:
def test_opaque_list(self): from pypy.rlib.rerased import new_erasing_pair erase, unerase = new_erasing_pair("test_opaque_list") def fn(n, ca, cb): l1 = [n] l2 = [n] a1 = erase(l1) a2 = erase(l1) a = a1 if ca: a = a2 if n < -100: unerase(a).append(5) b = a1 if cb: b = a return unerase(a)[0] + unerase(b)[0] res = self.interp_operations(fn, [7, 0, 1]) assert res == 7 * 2 self.check_operations_history(getarrayitem_gc=0, getfield_gc=0) res = self.interp_operations(fn, [-7, 1, 1]) assert res == -7 * 2 self.check_operations_history(getarrayitem_gc=0, getfield_gc=0)
class IntegerSetStrategy(AbstractUnwrappedSetStrategy, SetStrategy): erase, unerase = rerased.new_erasing_pair("integer") erase = staticmethod(erase) unerase = staticmethod(unerase) def get_empty_storage(self): return self.erase({}) def get_empty_dict(self): return {} def listview_int(self, w_set): return self.unerase(w_set.sstorage).keys() def is_correct_type(self, w_key): from pypy.objspace.std.intobject import W_IntObject return type(w_key) is W_IntObject def may_contain_equal_elements(self, strategy): if strategy is self.space.fromcache(StringSetStrategy): return False if strategy is self.space.fromcache(EmptySetStrategy): return False return True def unwrap(self, w_item): return self.space.int_w(w_item) def wrap(self, item): return self.space.wrap(item) def iter(self, w_set): return IntegerIteratorImplementation(self.space, self, w_set)
class IntDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("int") erase = staticmethod(erase) unerase = staticmethod(unerase) def wrap(self, unwrapped): return self.space.wrap(unwrapped) def unwrap(self, wrapped): return self.space.int_w(wrapped) def get_empty_storage(self): return self.erase({}) def is_correct_type(self, w_obj): space = self.space return space.is_w(space.type(w_obj), space.w_int) def _never_equal_to(self, w_lookup_type): space = self.space # XXX there are many more types return (space.is_w(w_lookup_type, space.w_NoneType) or space.is_w(w_lookup_type, space.w_str) or space.is_w(w_lookup_type, space.w_unicode) ) def iter(self, w_dict): return IntIteratorImplementation(self.space, self, w_dict) def listview_int(self, w_dict): return self.unerase(w_dict.dstorage).keys()
def define_erased(cls): from pypy.rlib import rerased erase, unerase = rerased.new_erasing_pair("test") class Unrelated(object): pass u = Unrelated() u.tagged = True u.x = rerased.erase_int(41) class A(object): pass def fn(): n = 1 while n >= 0: if u.tagged: n = rerased.unerase_int(u.x) a = A() a.n = n - 1 u.x = erase(a) u.tagged = False else: n = unerase(u.x).n u.x = rerased.erase_int(n - 1) u.tagged = True def func(): rgc.collect() # check that a prebuilt erased integer doesn't explode u.x = rerased.erase_int(1000) u.tagged = True fn() return 1 return func
class StringDictStrategy(AbstractTypedStrategy, DictStrategy): erase, unerase = rerased.new_erasing_pair("string") erase = staticmethod(erase) unerase = staticmethod(unerase) def wrap(self, unwrapped): return self.space.wrap(unwrapped) def unwrap(self, wrapped): return self.space.str_w(wrapped) def is_correct_type(self, w_obj): space = self.space return space.is_w(space.type(w_obj), space.w_str) def get_empty_storage(self): res = {} mark_dict_non_null(res) return self.erase(res) def _never_equal_to(self, w_lookup_type): return _never_equal_to_string(self.space, w_lookup_type) def setitem_str(self, w_dict, key, w_value): assert key is not None self.unerase(w_dict.dstorage)[key] = w_value def getitem(self, w_dict, w_key): space = self.space # -- This is called extremely often. Hack for performance -- if type(w_key) is space.StringObjectCls: return self.getitem_str(w_dict, w_key.unwrap(space)) # -- End of performance hack -- return AbstractTypedStrategy.getitem(self, w_dict, w_key) def getitem_str(self, w_dict, key): assert key is not None return self.unerase(w_dict.dstorage).get(key, None) def listview_str(self, w_dict): return self.unerase(w_dict.dstorage).keys() def iter(self, w_dict): return StrIteratorImplementation(self.space, self, w_dict) def w_keys(self, w_dict): return self.space.newlist_str(self.listview_str(w_dict))
class DictProxyStrategy(DictStrategy): erase, unerase = rerased.new_erasing_pair("dictproxy") erase = staticmethod(erase) unerase = staticmethod(unerase) def __init__(w_self, space): DictStrategy.__init__(w_self, space) def getitem(self, w_dict, w_key): space = self.space w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): return self.getitem_str(w_dict, space.str_w(w_key)) else: return None def getitem_str(self, w_dict, key): return self.unerase(w_dict.dstorage).getdictvalue(self.space, key) def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: raise OperationError(space.w_TypeError, space.wrap("cannot add non-string keys to dict of a type")) def setitem_str(self, w_dict, key, w_value): w_type = self.unerase(w_dict.dstorage) try: w_type.setdictvalue(self.space, key, w_value) except OperationError, e: if not e.match(self.space, self.space.w_TypeError): raise if not w_type.is_cpytype(): raise # xxx obscure workaround: allow cpyext to write to type->tp_dict. # xxx like CPython, we assume that this is only done early after # xxx the type is created, and we don't invalidate any cache. w_type.dict_w[key] = w_value
class ObjectSetStrategy(AbstractUnwrappedSetStrategy, SetStrategy): erase, unerase = rerased.new_erasing_pair("object") erase = staticmethod(erase) unerase = staticmethod(unerase) def get_empty_storage(self): return self.erase(self.get_empty_dict()) def get_empty_dict(self): return newset(self.space) def is_correct_type(self, w_key): return True def may_contain_equal_elements(self, strategy): if strategy is self.space.fromcache(EmptySetStrategy): return False return True def unwrap(self, w_item): return w_item def wrap(self, item): return item def iter(self, w_set): return RDictIteratorImplementation(self.space, self, w_set) def update(self, w_set, w_other): d_obj = self.unerase(w_set.sstorage) w_iterator = w_other.iter() while True: w_item = w_iterator.next_entry() if w_item is None: break d_obj[w_item] = None
class RangeListStrategy(ListStrategy): """RangeListStrategy is used when a list is created using the range method. The storage is a tuple containing only three integers start, step and length and elements are calculated based on these values. On any operation destroying the range (inserting, appending non-ints) the strategy is switched to IntegerListStrategy.""" _applevel_repr = "range" def switch_to_integer_strategy(self, w_list): items = self._getitems_range(w_list, False) strategy = w_list.strategy = self.space.fromcache(IntegerListStrategy) w_list.lstorage = strategy.erase(items) def wrap(self, intval): return self.space.wrap(intval) def unwrap(self, w_int): return self.space.int_w(w_int) def init_from_list_w(self, w_list, list_w): raise NotImplementedError erase, unerase = rerased.new_erasing_pair("range") erase = staticmethod(erase) unerase = staticmethod(unerase) def clone(self, w_list): storage = w_list.lstorage # lstorage is tuple, no need to clone w_clone = W_ListObject.from_storage_and_strategy( self.space, storage, self) return w_clone def copy_into(self, w_list, w_other): w_other.strategy = self w_other.lstorage = w_list.lstorage def contains(self, w_list, w_obj): if is_W_IntObject(w_obj): start, step, length = self.unerase(w_list.lstorage) obj = self.unwrap(w_obj) i = start if step > 0 and start <= obj <= start + (length - 1) * step and ( start - obj) % step == 0: return True elif step < 0 and start + (length - 1) * step <= obj <= start and ( start - obj) % step == 0: return True else: return False return ListStrategy.contains(self, w_list, w_obj) def length(self, w_list): return self.unerase(w_list.lstorage)[2] def _getitem_unwrapped(self, w_list, i): v = self.unerase(w_list.lstorage) start = v[0] step = v[1] length = v[2] if i < 0: i += length if i < 0: raise IndexError elif i >= length: raise IndexError return start + i * step def getitem(self, w_list, i): return self.wrap(self._getitem_unwrapped(w_list, i)) def getitems_copy(self, w_list): return self._getitems_range(w_list, True) def getstorage_copy(self, w_list): # tuple is unmutable return w_list.lstorage @specialize.arg(2) def _getitems_range(self, w_list, wrap_items): l = self.unerase(w_list.lstorage) start = l[0] step = l[1] length = l[2] if wrap_items: r = [None] * length else: r = [0] * length i = start n = 0 while n < length: if wrap_items: r[n] = self.wrap(i) else: r[n] = i i += step n += 1 return r @jit.dont_look_inside def getitems_fixedsize(self, w_list): return self._getitems_range_unroll(w_list, True) def getitems_unroll(self, w_list): return self._getitems_range_unroll(w_list, True) _getitems_range_unroll = jit.unroll_safe( func_with_new_name(_getitems_range, "_getitems_range_unroll")) def getslice(self, w_list, start, stop, step, length): v = self.unerase(w_list.lstorage) old_start = v[0] old_step = v[1] old_length = v[2] new_start = self._getitem_unwrapped(w_list, start) new_step = old_step * step return make_range_list(self.space, new_start, new_step, length) def append(self, w_list, w_item): if is_W_IntObject(w_item): l = self.unerase(w_list.lstorage) step = l[1] last_in_range = self._getitem_unwrapped(w_list, -1) if self.unwrap(w_item) - step == last_in_range: new = self.erase((l[0], l[1], l[2] + 1)) w_list.lstorage = new return self.switch_to_integer_strategy(w_list) else: w_list.switch_to_object_strategy() w_list.append(w_item) def inplace_mul(self, w_list, times): self.switch_to_integer_strategy(w_list) w_list.inplace_mul(times) def deleteslice(self, w_list, start, step, slicelength): self.switch_to_integer_strategy(w_list) w_list.deleteslice(start, step, slicelength) def pop_end(self, w_list): start, step, length = self.unerase(w_list.lstorage) w_result = self.wrap(start + (length - 1) * step) new = self.erase((start, step, length - 1)) w_list.lstorage = new return w_result def pop(self, w_list, index): l = self.unerase(w_list.lstorage) start = l[0] step = l[1] length = l[2] if index == 0: w_result = self.wrap(start) new = self.erase((start + step, step, length - 1)) w_list.lstorage = new return w_result elif index == length - 1: return self.pop_end(w_list) else: self.switch_to_integer_strategy(w_list) return w_list.pop(index) def setitem(self, w_list, index, w_item): self.switch_to_integer_strategy(w_list) w_list.setitem(index, w_item) def setslice(self, w_list, start, step, slicelength, sequence_w): self.switch_to_integer_strategy(w_list) w_list.setslice(start, step, slicelength, sequence_w) def sort(self, w_list, reverse): start, step, length = self.unerase(w_list.lstorage) if step > 0 and reverse or step < 0 and not reverse: start = start + step * (length - 1) step = step * (-1) else: return w_list.lstorage = self.erase((start, step, length)) def insert(self, w_list, index, w_item): self.switch_to_integer_strategy(w_list) w_list.insert(index, w_item) def extend(self, w_list, items_w): self.switch_to_integer_strategy(w_list) w_list.extend(items_w) def reverse(self, w_list): v = self.unerase(w_list.lstorage) last = self._getitem_unwrapped(w_list, -1) length = v[2] skip = v[1] new = self.erase((last, -skip, length)) w_list.lstorage = new
class EmptySetStrategy(SetStrategy): erase, unerase = rerased.new_erasing_pair("empty") erase = staticmethod(erase) unerase = staticmethod(unerase) def get_empty_storage(self): return self.erase(None) def is_correct_type(self, w_key): return False def length(self, w_set): return 0 def clear(self, w_set): pass def copy_real(self, w_set): storage = self.erase(None) clone = w_set.from_storage_and_strategy(storage, self) return clone def add(self, w_set, w_key): if type(w_key) is W_IntObject: strategy = self.space.fromcache(IntegerSetStrategy) elif type(w_key) is W_StringObject: strategy = self.space.fromcache(StringSetStrategy) else: strategy = self.space.fromcache(ObjectSetStrategy) w_set.strategy = strategy w_set.sstorage = strategy.get_empty_storage() w_set.add(w_key) def remove(self, w_set, w_item): return False def getdict_w(self, w_set): return newset(self.space) def get_storage_copy(self, w_set): return w_set.sstorage def getkeys(self, w_set): return [] def has_key(self, w_set, w_key): return False def equals(self, w_set, w_other): if w_other.strategy is self or w_other.length() == 0: return True return False def difference(self, w_set, w_other): return w_set.copy_real() def difference_update(self, w_set, w_other): pass def intersect(self, w_set, w_other): return w_set.copy_real() def intersect_update(self, w_set, w_other): pass def isdisjoint(self, w_set, w_other): return True def issubset(self, w_set, w_other): return True def symmetric_difference(self, w_set, w_other): return w_other.copy_real() def symmetric_difference_update(self, w_set, w_other): w_set.strategy = w_other.strategy w_set.sstorage = w_other.get_storage_copy() def update(self, w_set, w_other): w_set.strategy = w_other.strategy w_set.sstorage = w_other.get_storage_copy() def iter(self, w_set): return EmptyIteratorImplementation(self.space, self, w_set) def popitem(self, w_set): raise OperationError(self.space.w_KeyError, self.space.wrap('pop from an empty set'))
class KwargsDictStrategy(DictStrategy): erase, unerase = rerased.new_erasing_pair("kwargsdict") erase = staticmethod(erase) unerase = staticmethod(unerase) def wrap(self, key): return self.space.wrap(key) def unwrap(self, wrapped): return self.space.str_w(wrapped) def get_empty_storage(self): d = ([], []) return self.erase(d) def is_correct_type(self, w_obj): space = self.space return space.is_w(space.type(w_obj), space.w_str) def _never_equal_to(self, w_lookup_type): return False def iter(self, w_dict): return KwargsDictIterator(self.space, self, w_dict) def w_keys(self, w_dict): return self.space.newlist( [self.space.wrap(key) for key in self.unerase(w_dict.dstorage)[0]]) def setitem(self, w_dict, w_key, w_value): space = self.space if self.is_correct_type(w_key): self.setitem_str(w_dict, self.unwrap(w_key), w_value) return else: self.switch_to_object_strategy(w_dict) w_dict.setitem(w_key, w_value) def setitem_str(self, w_dict, key, w_value): self._setitem_str_indirection(w_dict, key, w_value) @jit.look_inside_iff(lambda self, w_dict, key, w_value: jit.isconstant( self.length(w_dict)) and jit.isconstant(key)) def _setitem_str_indirection(self, w_dict, key, w_value): keys, values_w = self.unerase(w_dict.dstorage) result = [] for i in range(len(keys)): if keys[i] == key: values_w[i] = w_value break else: # limit the size so that the linear searches don't become too long if len(keys) >= 16: self.switch_to_string_strategy(w_dict) w_dict.setitem_str(key, w_value) else: keys.append(key) values_w.append(w_value) def setdefault(self, w_dict, w_key, w_default): # XXX could do better, but is it worth it? self.switch_to_object_strategy(w_dict) return w_dict.setdefault(w_key, w_default) def delitem(self, w_dict, w_key): # XXX could do better, but is it worth it? self.switch_to_object_strategy(w_dict) return w_dict.delitem(w_key) def length(self, w_dict): return len(self.unerase(w_dict.dstorage)[0]) def getitem_str(self, w_dict, key): return self._getitem_str_indirection(w_dict, key) @jit.look_inside_iff(lambda self, w_dict, key: jit.isconstant( self.length(w_dict)) and jit.isconstant(key)) def _getitem_str_indirection(self, w_dict, key): keys, values_w = self.unerase(w_dict.dstorage) result = [] for i in range(len(keys)): if keys[i] == key: return values_w[i] return None def getitem(self, w_dict, w_key): space = self.space if self.is_correct_type(w_key): return self.getitem_str(w_dict, self.unwrap(w_key)) elif self._never_equal_to(space.type(w_key)): return None else: self.switch_to_object_strategy(w_dict) return w_dict.getitem(w_key) def w_keys(self, w_dict): l = self.unerase(w_dict.dstorage)[0] return self.space.newlist_str(l[:]) def values(self, w_dict): return self.unerase(w_dict.dstorage)[1][:] # to make non-resizable def items(self, w_dict): space = self.space keys, values_w = self.unerase(w_dict.dstorage) result = [] for i in range(len(keys)): result.append(space.newtuple([self.wrap(keys[i]), values_w[i]])) return result def popitem(self, w_dict): keys, values_w = self.unerase(w_dict.dstorage) key = keys.pop() w_value = values_w.pop() return (self.wrap(key), w_value) def clear(self, w_dict): w_dict.dstorage = self.get_empty_storage() def switch_to_object_strategy(self, w_dict): strategy = self.space.fromcache(ObjectDictStrategy) keys, values_w = self.unerase(w_dict.dstorage) d_new = strategy.unerase(strategy.get_empty_storage()) for i in range(len(keys)): d_new[self.wrap(keys[i])] = values_w[i] w_dict.strategy = strategy w_dict.dstorage = strategy.erase(d_new) def switch_to_string_strategy(self, w_dict): strategy = self.space.fromcache(StringDictStrategy) keys, values_w = self.unerase(w_dict.dstorage) storage = strategy.get_empty_storage() d_new = strategy.unerase(storage) for i in range(len(keys)): d_new[keys[i]] = values_w[i] w_dict.strategy = strategy w_dict.dstorage = storage def view_as_kwargs(self, w_dict): return self.unerase(w_dict.dstorage)
class MapDictStrategy(DictStrategy): erase, unerase = rerased.new_erasing_pair("map") erase = staticmethod(erase) unerase = staticmethod(unerase) def __init__(self, space): self.space = space def switch_to_object_strategy(self, w_dict): w_obj = self.unerase(w_dict.dstorage) strategy = self.space.fromcache(ObjectDictStrategy) dict_w = strategy.unerase(strategy.get_empty_storage()) w_dict.strategy = strategy w_dict.dstorage = strategy.erase(dict_w) assert w_obj.getdict(self.space) is w_dict materialize_r_dict(self.space, w_obj, dict_w) def getitem(self, w_dict, w_key): space = self.space w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): return self.getitem_str(w_dict, space.str_w(w_key)) elif _never_equal_to_string(space, w_lookup_type): return None else: self.switch_to_object_strategy(w_dict) return w_dict.getitem(w_key) def getitem_str(self, w_dict, key): w_obj = self.unerase(w_dict.dstorage) return w_obj.getdictvalue(self.space, key) def setitem_str(self, w_dict, key, w_value): w_obj = self.unerase(w_dict.dstorage) flag = w_obj.setdictvalue(self.space, key, w_value) assert flag def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: self.switch_to_object_strategy(w_dict) w_dict.setitem(w_key, w_value) def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): key = space.str_w(w_key) w_result = self.getitem_str(w_dict, key) if w_result is not None: return w_result self.setitem_str(w_dict, key, w_default) return w_default else: self.switch_to_object_strategy(w_dict) return w_dict.setdefault(w_key, w_default) def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) w_obj = self.unerase(w_dict.dstorage) if space.is_w(w_key_type, space.w_str): key = self.space.str_w(w_key) flag = w_obj.deldictvalue(space, key) if not flag: raise KeyError elif _never_equal_to_string(space, w_key_type): raise KeyError else: self.switch_to_object_strategy(w_dict) w_dict.delitem(w_key) def length(self, w_dict): res = 0 curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) while curr is not None: curr = curr.back curr = curr.search(DICT) res += 1 return res def iter(self, w_dict): return MapDictIteratorImplementation(self.space, self, w_dict) def clear(self, w_dict): w_obj = self.unerase(w_dict.dstorage) new_obj = w_obj._get_mapdict_map().remove_dict_entries(w_obj) _become(w_obj, new_obj) def popitem(self, w_dict): curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) if curr is None: raise KeyError key = curr.selector[0] w_value = self.getitem_str(w_dict, key) w_key = self.space.wrap(key) self.delitem(w_dict, w_key) return (w_key, w_value)
class EmptyListStrategy(ListStrategy): """EmptyListStrategy is used when a W_List withouth elements is created. The storage is None. When items are added to the W_List a new RPython list is created and the strategy and storage of the W_List are changed depending to the added item. W_Lists do not switch back to EmptyListStrategy when becoming empty again.""" _applevel_repr = "empty" def __init__(self, space): ListStrategy.__init__(self, space) # cache an empty list that is used whenever getitems is called (i.e. sorting) self.cached_emptylist_w = [] def init_from_list_w(self, w_list, list_w): assert len(list_w) == 0 w_list.lstorage = self.erase(None) erase, unerase = rerased.new_erasing_pair("empty") erase = staticmethod(erase) unerase = staticmethod(unerase) def clone(self, w_list): return W_ListObject.from_storage_and_strategy(self.space, w_list.lstorage, self) def copy_into(self, w_list, w_other): pass def contains(self, w_list, w_obj): return False def length(self, w_list): return 0 def getitem(self, w_list, index): raise IndexError def getslice(self, w_list, start, stop, step, length): # will never be called because the empty list case is already caught in # getslice__List_ANY_ANY and getitem__List_Slice return W_ListObject(self.space, self.cached_emptylist_w) def getitems(self, w_list): return self.cached_emptylist_w def getitems_copy(self, w_list): return [] getitems_fixedsize = func_with_new_name(getitems_copy, "getitems_fixedsize") getitems_unroll = getitems_fixedsize def getstorage_copy(self, w_list): return self.erase(None) def switch_to_correct_strategy(self, w_list, w_item): if is_W_IntObject(w_item): strategy = self.space.fromcache(IntegerListStrategy) elif is_W_StringObject(w_item): strategy = self.space.fromcache(StringListStrategy) elif is_W_FloatObject(w_item): strategy = self.space.fromcache(FloatListStrategy) else: strategy = self.space.fromcache(ObjectListStrategy) storage = strategy.get_empty_storage() w_list.strategy = strategy w_list.lstorage = storage def append(self, w_list, w_item): self.switch_to_correct_strategy(w_list, w_item) w_list.append(w_item) def inplace_mul(self, w_list, times): return def deleteslice(self, w_list, start, step, slicelength): pass def pop(self, w_list, index): # will not be called because IndexError was already raised in # list_pop__List_ANY raise IndexError def setitem(self, w_list, index, w_item): raise IndexError def setslice(self, w_list, start, step, slicelength, w_other): strategy = w_other.strategy storage = strategy.getstorage_copy(w_other) w_list.strategy = strategy w_list.lstorage = storage def sort(self, w_list, reverse): return def insert(self, w_list, index, w_item): assert index == 0 self.append(w_list, w_item) def extend(self, w_list, w_other): w_other.copy_into(w_list) def reverse(self, w_list): pass
class EmptyDictStrategy(DictStrategy): erase, unerase = rerased.new_erasing_pair("empty") erase = staticmethod(erase) unerase = staticmethod(unerase) def get_empty_storage(self): return self.erase(None) def switch_to_correct_strategy(self, w_dict, w_key): withidentitydict = self.space.config.objspace.std.withidentitydict if type(w_key) is self.space.StringObjectCls: self.switch_to_string_strategy(w_dict) return w_type = self.space.type(w_key) if self.space.is_w(w_type, self.space.w_int): self.switch_to_int_strategy(w_dict) elif withidentitydict and w_type.compares_by_identity(): self.switch_to_identity_strategy(w_dict) else: self.switch_to_object_strategy(w_dict) def switch_to_string_strategy(self, w_dict): strategy = self.space.fromcache(StringDictStrategy) storage = strategy.get_empty_storage() w_dict.strategy = strategy w_dict.dstorage = storage def switch_to_int_strategy(self, w_dict): strategy = self.space.fromcache(IntDictStrategy) storage = strategy.get_empty_storage() w_dict.strategy = strategy w_dict.dstorage = storage def switch_to_identity_strategy(self, w_dict): from pypy.objspace.std.identitydict import IdentityDictStrategy strategy = self.space.fromcache(IdentityDictStrategy) storage = strategy.get_empty_storage() w_dict.strategy = strategy w_dict.dstorage = storage def switch_to_object_strategy(self, w_dict): strategy = self.space.fromcache(ObjectDictStrategy) storage = strategy.get_empty_storage() w_dict.strategy = strategy w_dict.dstorage = storage def getitem(self, w_dict, w_key): #return w_value or None # in case the key is unhashable, try to hash it self.space.hash(w_key) # return None anyway return None def getitem_str(self, w_dict, key): #return w_value or None return None def setdefault(self, w_dict, w_key, w_default): # here the dict is always empty self.switch_to_correct_strategy(w_dict, w_key) w_dict.setitem(w_key, w_default) return w_default def setitem(self, w_dict, w_key, w_value): self.switch_to_correct_strategy(w_dict, w_key) w_dict.setitem(w_key, w_value) def setitem_str(self, w_dict, key, w_value): self.switch_to_string_strategy(w_dict) w_dict.setitem_str(key, w_value) def delitem(self, w_dict, w_key): # in case the key is unhashable, try to hash it self.space.hash(w_key) raise KeyError def length(self, w_dict): return 0 def iter(self, w_dict): return EmptyIteratorImplementation(self.space, self, w_dict) def clear(self, w_dict): return def popitem(self, w_dict): raise KeyError def view_as_kwargs(self, w_dict): return ([], [])
class IdentityDictStrategy(AbstractTypedStrategy, DictStrategy): """ Strategy for custom instances which compares by identity (i.e., the default unless you override __hash__, __eq__ or __cmp__). The storage is just a normal RPython dict, which has already the correct by-identity semantics. Note that at a first sight, you might have problems if you mutate the class of an object which is already inside an identitydict. Consider this example:: class X(object): pass d = {x(): 1} X.__eq__ = ... d[y] # might trigger a call to __eq__? We want to be sure that x.__eq__ is called in the same cases as in CPython. However, as long as the strategy is IdentityDictStrategy, the __eq__ will never be called. It turns out that it's not a problem. In CPython (and in PyPy without this strategy), the __eq__ is called if ``hash(y) == hash(x)`` and ``x is not y``. Note that hash(x) is computed at the time when we insert x in the dict, not at the time we lookup y. Now, how can hash(y) == hash(x)? There are two possibilities: 1. we write a custom __hash__ for the class of y, thus making it a not "compares by reference" type 2. the class of y is "compares by reference" type, and by chance the hash is the same as x In the first case, the getitem immediately notice that y is not of the right type, and switches the strategy to ObjectDictStrategy, then the lookup works as usual. The second case is completely non-deterministic, even in CPython. Depending on the phase of the moon, you might call the __eq__ or not, so it is perfectly fine to *never* call it. Morever, in practice with the minimark GC we never have two live objects with the same hash, so it would never happen anyway. """ erase, unerase = rerased.new_erasing_pair("identitydict") erase = staticmethod(erase) unerase = staticmethod(unerase) def wrap(self, unwrapped): return unwrapped def unwrap(self, wrapped): return wrapped def get_empty_storage(self): d = {} mark_dict_non_null(d) return self.erase(d) def is_correct_type(self, w_obj): w_type = self.space.type(w_obj) return w_type.compares_by_identity() def _never_equal_to(self, w_lookup_type): return False def iter(self, w_dict): return IdentityDictIteratorImplementation(self.space, self, w_dict) def w_keys(self, w_dict): return self.space.newlist(self.unerase(w_dict.dstorage).keys())
return _subclass_cache[key] except KeyError: assert not hasattr(supercls, "__del__") result = [] for i in range(SUBCLASSES_MIN_FIELDS, SUBCLASSES_MAX_FIELDS+1): result.append(_make_subclass_size_n(supercls, i)) for i in range(SUBCLASSES_MIN_FIELDS): result.insert(0, result[0]) if SUBCLASSES_MIN_FIELDS == SUBCLASSES_MAX_FIELDS: assert len(set(result)) == 1 _subclass_cache[key] = result return result memo_get_subclass_of_correct_size._annspecialcase_ = "specialize:memo" _subclass_cache = {} erase_item, unerase_item = rerased.new_erasing_pair("mapdict storage item") erase_list, unerase_list = rerased.new_erasing_pair("mapdict storage list") def _make_subclass_size_n(supercls, n): from pypy.rlib import unroll rangen = unroll.unrolling_iterable(range(n)) nmin1 = n - 1 rangenmin1 = unroll.unrolling_iterable(range(nmin1)) class subcls(BaseMapdictObject, supercls): def _init_empty(self, map): from pypy.rlib.debug import make_sure_not_resized for i in rangen: setattr(self, "_value%s" % i, erase_item(None)) self.map = map def _has_storage_list(self):
class ModuleDictStrategy(DictStrategy): erase, unerase = rerased.new_erasing_pair("modulecell") erase = staticmethod(erase) unerase = staticmethod(unerase) _immutable_fields_ = ["version?"] def __init__(self, space): self.space = space self.version = VersionTag() def get_empty_storage(self): return self.erase({}) def mutated(self): self.version = VersionTag() def getdictvalue_no_unwrapping(self, w_dict, key): # NB: it's important to promote self here, so that self.version is a # no-op due to the quasi-immutable field self = jit.promote(self) return self._getdictvalue_no_unwrapping_pure(self.version, w_dict, key) @jit.elidable_promote('0,1,2') def _getdictvalue_no_unwrapping_pure(self, version, w_dict, key): return self.unerase(w_dict.dstorage).get(key, None) def setitem(self, w_dict, w_key, w_value): space = self.space if space.is_w(space.type(w_key), space.w_str): self.setitem_str(w_dict, self.space.str_w(w_key), w_value) else: self.switch_to_object_strategy(w_dict) w_dict.setitem(w_key, w_value) def setitem_str(self, w_dict, key, w_value): cell = self.getdictvalue_no_unwrapping(w_dict, key) if isinstance(cell, ModuleCell): cell.w_value = w_value return if cell is not None: # If the new value and the current value are the same, don't create a # level of indirection, or mutate the version. if self.space.is_w(w_value, cell): return w_value = ModuleCell(w_value) self.mutated() self.unerase(w_dict.dstorage)[key] = w_value def setdefault(self, w_dict, w_key, w_default): space = self.space if space.is_w(space.type(w_key), space.w_str): key = space.str_w(w_key) w_result = self.getitem_str(w_dict, key) if w_result is not None: return w_result self.setitem_str(w_dict, key, w_default) return w_default else: self.switch_to_object_strategy(w_dict) return w_dict.setdefault(w_key, w_default) def delitem(self, w_dict, w_key): space = self.space w_key_type = space.type(w_key) if space.is_w(w_key_type, space.w_str): key = space.str_w(w_key) dict_w = self.unerase(w_dict.dstorage) try: del dict_w[key] except KeyError: raise else: self.mutated() elif _never_equal_to_string(space, w_key_type): raise KeyError else: self.switch_to_object_strategy(w_dict) w_dict.delitem(w_key) def length(self, w_dict): return len(self.unerase(w_dict.dstorage)) def getitem(self, w_dict, w_key): space = self.space w_lookup_type = space.type(w_key) if space.is_w(w_lookup_type, space.w_str): return self.getitem_str(w_dict, space.str_w(w_key)) elif _never_equal_to_string(space, w_lookup_type): return None else: self.switch_to_object_strategy(w_dict) return w_dict.getitem(w_key) def getitem_str(self, w_dict, key): w_res = self.getdictvalue_no_unwrapping(w_dict, key) return unwrap_cell(w_res) def iter(self, w_dict): return ModuleDictIteratorImplementation(self.space, self, w_dict) def keys(self, w_dict): space = self.space iterator = self.unerase(w_dict.dstorage).iteritems return [space.wrap(key) for key, cell in iterator()] def values(self, w_dict): iterator = self.unerase(w_dict.dstorage).itervalues return [unwrap_cell(cell) for cell in iterator()] def items(self, w_dict): space = self.space iterator = self.unerase(w_dict.dstorage).iteritems return [ space.newtuple([space.wrap(key), unwrap_cell(cell)]) for key, cell in iterator() ] def clear(self, w_dict): iterator = self.unerase(w_dict.dstorage).clear() self.mutated() def popitem(self, w_dict): d = self.unerase(w_dict.dstorage) key, w_value = d.popitem() self.mutated() return self.space.wrap(key), unwrap_cell(w_value) def switch_to_object_strategy(self, w_dict): d = self.unerase(w_dict.dstorage) strategy = self.space.fromcache(ObjectDictStrategy) d_new = strategy.unerase(strategy.get_empty_storage()) for key, cell in d.iteritems(): d_new[self.space.wrap(key)] = unwrap_cell(cell) w_dict.strategy = strategy w_dict.dstorage = strategy.erase(d_new)
assert not hasattr(supercls, "__del__") result = [] for i in range(SUBCLASSES_MIN_FIELDS, SUBCLASSES_MAX_FIELDS + 1): result.append(_make_subclass_size_n(supercls, i)) for i in range(SUBCLASSES_MIN_FIELDS): result.insert(0, result[0]) if SUBCLASSES_MIN_FIELDS == SUBCLASSES_MAX_FIELDS: assert len(set(result)) == 1 _subclass_cache[key] = result return result memo_get_subclass_of_correct_size._annspecialcase_ = "specialize:memo" _subclass_cache = {} erase_item, unerase_item = rerased.new_erasing_pair("mapdict storage item") erase_list, unerase_list = rerased.new_erasing_pair("mapdict storage list") def _make_subclass_size_n(supercls, n): from pypy.rlib import unroll rangen = unroll.unrolling_iterable(range(n)) nmin1 = n - 1 rangenmin1 = unroll.unrolling_iterable(range(nmin1)) class subcls(BaseMapdictObject, supercls): def _init_empty(self, map): from pypy.rlib.debug import make_sure_not_resized for i in rangen: setattr(self, "_value%s" % i, erase_item(None)) self.map = map