Author: Carl Friedrich Bolz <cfb...@gmx.de> Branch: Changeset: r75484:fd3d597fb6ea Date: 2015-01-22 16:49 +0100 http://bitbucket.org/pypy/pypy/changeset/fd3d597fb6ea/
Log: merge typed-cells diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -83,7 +83,7 @@ loops = log.loops_by_filename(self.filepath) assert len(loops) == 1 - def test_mutate_class(self): + def test_mutate_class_int(self): def fn(n): class A(object): count = 1 @@ -106,7 +106,7 @@ entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) ops = entry_bridge.ops_by_id('mutate', opcode='LOAD_ATTR') assert log.opnames(ops) == ['guard_value', 'guard_not_invalidated', - 'getfield_gc', 'guard_nonnull_class'] + 'getfield_gc'] # the STORE_ATTR is folded away assert list(entry_bridge.ops_by_id('meth1', opcode='STORE_ATTR')) == [] # @@ -114,19 +114,77 @@ # ---------------------- loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - i8 = getfield_gc_pure(p5, descr=...) - i9 = int_lt(i8, i7) - guard_true(i9, descr=.*) - guard_not_invalidated(descr=.*) - i82 = getfield_gc_pure(p8, descr=...) - i11 = int_add_ovf(i82, 1) + i58 = int_lt(i38, i31) + guard_true(i58, descr=...) + guard_not_invalidated(descr=...) + i59 = int_add_ovf(i57, 1) guard_no_overflow(descr=...) - i12 = force_token() - --TICK-- - p20 = new_with_vtable(ConstClass(W_IntObject)) - setfield_gc(p20, i11, descr=<FieldS.*W_IntObject.inst_intval .*>) - setfield_gc(ConstPtr(ptr21), p20, descr=<FieldP .*TypeCell.inst_w_value .*>) - jump(..., descr=...) + p60 = force_token() + i61 = getfield_raw(..., descr=...) + setfield_gc(ConstPtr(ptr39), i59, descr=...) + i62 = int_lt(i61, 0) + guard_false(i62, descr=...) + jump(p0, p1, p3, p6, p7, p12, i59, p18, i31, i59, descr=...) + """) + + def test_mutate_class(self): + def fn(n): + class LL(object): + def __init__(self, n): + self.n = n + class A(object): + count = None + def __init__(self, a): + self.a = a + def f(self): + return self.count + i = 0 + a = A(1) + while i < n: + A.count = LL(A.count) # ID: mutate + a.f() # ID: meth1 + i += 1 + return i + # + log = self.run(fn, [1000], threshold=10) + assert log.result == 1000 + # + # first, we test the entry bridge + # ------------------------------- + entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) + ops = entry_bridge.ops_by_id('mutate', opcode='LOAD_ATTR') + assert log.opnames(ops) == ['guard_value', 'guard_not_invalidated', + 'getfield_gc', 'guard_nonnull_class', + 'getfield_gc', 'guard_value', # type check on the attribute + ] + # the STORE_ATTR is folded away + assert list(entry_bridge.ops_by_id('meth1', opcode='STORE_ATTR')) == [] + # + # then, the actual loop + # ---------------------- + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i70 = int_lt(i58, i33) + guard_true(i70, descr=...) + guard_not_invalidated(descr=...) + p71 = getfield_gc(p64, descr=...) + guard_value(p71, ConstPtr(ptr42), descr=...) + p72 = force_token() + p73 = force_token() + i74 = int_add(i58, 1) + i75 = getfield_raw(..., descr=...) + i76 = int_lt(i75, 0) + guard_false(i76, descr=...) + p77 = new_with_vtable(...) + setfield_gc(p77, p64, descr=...) + setfield_gc(p77, ConstPtr(null), descr=...) + setfield_gc(p77, ConstPtr(null), descr=...) + setfield_gc(p77, ConstPtr(null), descr=...) + setfield_gc(p77, ConstPtr(null), descr=...) + setfield_gc(p77, ConstPtr(ptr42), descr=...) + setfield_gc(ConstPtr(ptr69), p77, descr=...) + jump(p0, p1, p3, p6, p7, p12, i74, p20, p26, i33, p77, descr=...) + """) def test_oldstyle_newstyle_mix(self): diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -9,23 +9,16 @@ from pypy.objspace.std.dictmultiobject import ( DictStrategy, ObjectDictStrategy, _never_equal_to_string, create_iterator_classes) +from pypy.objspace.std.typeobject import ( + MutableCell, IntMutableCell, ObjectMutableCell, write_cell) class VersionTag(object): pass - -class ModuleCell(W_Root): - def __init__(self, w_value=None): - self.w_value = w_value - - def __repr__(self): - return "<ModuleCell: %s>" % (self.w_value, ) - - -def unwrap_cell(w_value): - if isinstance(w_value, ModuleCell): - return w_value.w_value +def unwrap_cell(space, w_value): + if isinstance(w_value, MutableCell): + return w_value.unwrap_cell(space) return w_value @@ -71,15 +64,9 @@ 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 + w_value = write_cell(self.space, cell, w_value) + if w_value is None: 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 @@ -131,7 +118,7 @@ def getitem_str(self, w_dict, key): cell = self.getdictvalue_no_unwrapping(w_dict, key) - return unwrap_cell(cell) + return unwrap_cell(self.space, cell) def w_keys(self, w_dict): space = self.space @@ -140,12 +127,12 @@ def values(self, w_dict): iterator = self.unerase(w_dict.dstorage).itervalues - return [unwrap_cell(cell) for cell in iterator()] + return [unwrap_cell(self.space, cell) for cell in iterator()] def items(self, w_dict): space = self.space iterator = self.unerase(w_dict.dstorage).iteritems - return [space.newtuple([_wrapkey(space, key), unwrap_cell(cell)]) + return [space.newtuple([_wrapkey(space, key), unwrap_cell(self.space, cell)]) for key, cell in iterator()] def clear(self, w_dict): @@ -157,7 +144,7 @@ d = self.unerase(w_dict.dstorage) key, cell = d.popitem() self.mutated() - return _wrapkey(space, key), unwrap_cell(cell) + return _wrapkey(space, key), unwrap_cell(self.space, cell) def switch_to_object_strategy(self, w_dict): space = self.space @@ -165,7 +152,7 @@ strategy = space.fromcache(ObjectDictStrategy) d_new = strategy.unerase(strategy.get_empty_storage()) for key, cell in d.iteritems(): - d_new[_wrapkey(space, key)] = unwrap_cell(cell) + d_new[_wrapkey(space, key)] = unwrap_cell(self.space, cell) w_dict.strategy = strategy w_dict.dstorage = strategy.erase(d_new) @@ -181,7 +168,7 @@ wrapkey = _wrapkey def wrapvalue(space, value): - return unwrap_cell(value) + return unwrap_cell(space, value) create_iterator_classes(ModuleDictStrategy) diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -8,7 +8,7 @@ W_DictMultiObject, DictStrategy, ObjectDictStrategy, BaseKeyIterator, BaseValueIterator, BaseItemIterator, _never_equal_to_string ) -from pypy.objspace.std.typeobject import TypeCell +from pypy.objspace.std.typeobject import MutableCell # ____________________________________________________________ @@ -872,15 +872,15 @@ if version_tag is not None: name = space.str_w(w_name) # We need to care for obscure cases in which the w_descr is - # a TypeCell, which may change without changing the version_tag + # a MutableCell, which may change without changing the version_tag _, w_descr = w_type._pure_lookup_where_possibly_with_method_cache( name, version_tag) # selector = ("", INVALID) if w_descr is None: selector = (name, DICT) # common case: no such attr in the class - elif isinstance(w_descr, TypeCell): - pass # we have a TypeCell in the class: give up + elif isinstance(w_descr, MutableCell): + pass # we have a MutableCell in the class: give up elif space.is_data_descr(w_descr): # we have a data descriptor, which means the dictionary value # (if any) has no relevance. @@ -929,11 +929,11 @@ # We know here that w_obj.getdictvalue(space, name) just returned None, # so the 'name' is not in the instance. We repeat the lookup to find it # in the class, this time taking care of the result: it can be either a - # quasi-constant class attribute, or actually a TypeCell --- which we + # quasi-constant class attribute, or actually a MutableCell --- which we # must not cache. (It should not be None here, but you never know...) _, w_method = w_type._pure_lookup_where_possibly_with_method_cache( name, version_tag) - if w_method is None or isinstance(w_method, TypeCell): + if w_method is None or isinstance(w_method, MutableCell): return _fill_cache(pycode, nameindex, map, version_tag, -1, w_method) diff --git a/pypy/objspace/std/test/test_versionedtype.py b/pypy/objspace/std/test/test_versionedtype.py --- a/pypy/objspace/std/test/test_versionedtype.py +++ b/pypy/objspace/std/test/test_versionedtype.py @@ -210,6 +210,56 @@ assert w_A.version_tag() is atag assert space.int_w(space.getattr(w_A, w_x)) == 4 + def test_no_cell_when_writing_same_value(self): + space = self.space + w_x = space.wrap("x") + w_A, w_B, w_C = self.get_three_classes() + atag = w_A.version_tag() + w_val = space.newint(1) + space.setattr(w_A, w_x, w_val) + space.setattr(w_A, w_x, w_val) + w_val1 = w_A._getdictvalue_no_unwrapping(space, "x") + assert w_val1 is w_val + + def test_int_cells(self): + space = self.space + w_x = space.wrap("x") + w_A, w_B, w_C = self.get_three_classes() + atag = w_A.version_tag() + space.setattr(w_A, w_x, space.newint(1)) + assert w_A.version_tag() is not atag + assert space.int_w(space.getattr(w_A, w_x)) == 1 + + atag = w_A.version_tag() + space.setattr(w_A, w_x, space.newint(2)) + assert w_A.version_tag() is not atag + assert space.int_w(space.getattr(w_A, w_x)) == 2 + cell = w_A._getdictvalue_no_unwrapping(space, "x") + assert cell.intvalue == 2 + + atag = w_A.version_tag() + space.setattr(w_A, w_x, space.newint(3)) + assert w_A.version_tag() is atag + assert space.int_w(space.getattr(w_A, w_x)) == 3 + assert cell.intvalue == 3 + + space.setattr(w_A, w_x, space.newint(4)) + assert w_A.version_tag() is atag + assert space.int_w(space.getattr(w_A, w_x)) == 4 + assert cell.intvalue == 4 + + def test_int_cell_turns_into_cell(self): + space = self.space + w_x = space.wrap("x") + w_A, w_B, w_C = self.get_three_classes() + atag = w_A.version_tag() + space.setattr(w_A, w_x, space.newint(1)) + space.setattr(w_A, w_x, space.newint(2)) + space.setattr(w_A, w_x, space.newfloat(2.2)) + cell = w_A._getdictvalue_no_unwrapping(space, "x") + assert space.float_w(cell.w_value) == 2.2 + + class AppTestVersionedType(test_typeobject.AppTestTypeObject): spaceconfig = {"objspace.std.withtypeversion": True} diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -11,18 +11,57 @@ from rpython.rlib.objectmodel import current_object_addr_as_int, compute_hash from rpython.rlib.rarithmetic import intmask, r_uint +class MutableCell(W_Root): + def unwrap_cell(self, space): + raise NotImplementedError("abstract base") -class TypeCell(W_Root): +class ObjectMutableCell(MutableCell): def __init__(self, w_value=None): self.w_value = w_value + def unwrap_cell(self, space): + return self.w_value + + def __repr__(self): + return "<ObjectMutableCell: %s>" % (self.w_value, ) + + +class IntMutableCell(MutableCell): + def __init__(self, intvalue): + self.intvalue = intvalue + + def unwrap_cell(self, space): + return space.wrap(self.intvalue) + + def __repr__(self): + return "<IntMutableCell: %s>" % (self.intvalue, ) + def unwrap_cell(space, w_value): - if (space.config.objspace.std.withtypeversion and - isinstance(w_value, TypeCell)): - return w_value.w_value + if space.config.objspace.std.withtypeversion: + if isinstance(w_value, MutableCell): + return w_value.unwrap_cell(space) return w_value +def write_cell(space, w_cell, w_value): + from pypy.objspace.std.intobject import W_IntObject + if w_cell is None: + # attribute does not exist at all, write it without a cell first + return w_value + if isinstance(w_cell, ObjectMutableCell): + w_cell.w_value = w_value + return None + elif isinstance(w_cell, IntMutableCell) and type(w_value) is W_IntObject: + w_cell.intvalue = w_value.intval + return None + elif space.is_w(w_cell, w_value): + # If the new value and the current value are the same, don't + # create a level of indirection, or mutate the version. + return None + if type(w_value) is W_IntObject: + return IntMutableCell(w_value.intval) + else: + return ObjectMutableCell(w_value) class VersionTag(object): pass @@ -274,11 +313,9 @@ if version_tag is not None: w_curr = w_self._pure_getdictvalue_no_unwrapping( space, version_tag, name) - if w_curr is not None: - if isinstance(w_curr, TypeCell): - w_curr.w_value = w_value - return True - w_value = TypeCell(w_value) + w_value = write_cell(space, w_curr, w_value) + if w_value is None: + return True w_self.mutated(name) w_self.dict_w[name] = w_value return True @@ -369,8 +406,8 @@ tup_w = w_self._pure_lookup_where_with_method_cache(name, version_tag) w_class, w_value = tup_w if (space.config.objspace.std.withtypeversion and - isinstance(w_value, TypeCell)): - return w_class, w_value.w_value + isinstance(w_value, MutableCell)): + return w_class, w_value.unwrap_cell(space) return tup_w # don't make a new tuple, reuse the old one def _pure_lookup_where_possibly_with_method_cache(w_self, name, version_tag): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit