[pypy-commit] pypy default: merge typed-cells
cfbolz
noreply at buildbot.pypy.org
Thu Jan 22 16:50:47 CET 2015
Author: Carl Friedrich Bolz <cfbolz at 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):
More information about the pypy-commit
mailing list