[pypy-svn] r69289 - in pypy/trunk/pypy: module/pypyjit/test objspace/std objspace/std/test
cfbolz at codespeak.net
cfbolz at codespeak.net
Sat Nov 14 15:56:33 CET 2009
Author: cfbolz
Date: Sat Nov 14 15:56:31 2009
New Revision: 69289
Modified:
pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py
pypy/trunk/pypy/objspace/std/callmethod.py
pypy/trunk/pypy/objspace/std/dictmultiobject.py
pypy/trunk/pypy/objspace/std/objspace.py
pypy/trunk/pypy/objspace/std/test/test_versionedtype.py
pypy/trunk/pypy/objspace/std/typeobject.py
pypy/trunk/pypy/objspace/std/typetype.py
Log:
clean up some code in typeobject to make sure that the version_tag of builtin
objects cannot change. Get rid of a few guards here and there.
Modified: pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py
==============================================================================
--- pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py (original)
+++ pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py Sat Nov 14 15:56:31 2009
@@ -187,7 +187,7 @@
assert len(ops) == 2
assert not ops[0].get_opnames("call")
assert not ops[0].get_opnames("new")
- assert len(ops[0].get_opnames("guard")) <= 8
+ assert len(ops[0].get_opnames("guard")) <= 7
assert not ops[1] # second LOOKUP_METHOD folded away
ops = self.get_by_bytecode("CALL_METHOD")
@@ -233,6 +233,7 @@
while i < n:
a = A()
assert isinstance(a, A)
+ assert not isinstance(a, int)
a.x = 2
i = i + a.x
return i
@@ -240,13 +241,42 @@
([20], 20),
([31], 32))
- callA, callisinstance = self.get_by_bytecode("CALL_FUNCTION")
+ callA, callisinstance1, callisinstance2 = (
+ self.get_by_bytecode("CALL_FUNCTION"))
assert not callA.get_opnames("call")
assert not callA.get_opnames("new")
- assert len(callA.get_opnames("guard")) <= 9
- assert not callisinstance.get_opnames("call")
- assert not callisinstance.get_opnames("new")
- assert len(callisinstance.get_opnames("guard")) <= 2
+ assert len(callA.get_opnames("guard")) <= 8
+ assert not callisinstance1.get_opnames("call")
+ assert not callisinstance1.get_opnames("new")
+ assert len(callisinstance1.get_opnames("guard")) <= 2
+ # calling isinstance on a builtin type gives zero guards
+ # because the version_tag of a builtin type is immutable
+ assert not len(callisinstance1.get_opnames("guard"))
+
+
+ bytecode, = self.get_by_bytecode("STORE_ATTR")
+ assert bytecode.get_opnames() == []
+
+ def test_load_attr(self):
+ self.run_source('''
+ class A(object):
+ pass
+ a = A()
+ a.x = 2
+ def main(n):
+ i = 0
+ while i < n:
+ i = i + a.x
+ return i
+ ''',
+ ([20], 20),
+ ([31], 32))
+
+ load = self.get_by_bytecode("LOAD_ATTR")
+ # 1 guard_value for the class
+ # 1 guard_value for the version_tag
+ # 1 guard_value for the structure
+ assert len(load.get_opnames("guard")) <= 3
bytecode, = self.get_by_bytecode("STORE_ATTR")
assert bytecode.get_opnames() == []
Modified: pypy/trunk/pypy/objspace/std/callmethod.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/callmethod.py (original)
+++ pypy/trunk/pypy/objspace/std/callmethod.py Sat Nov 14 15:56:31 2009
@@ -33,22 +33,8 @@
w_name = f.getname_w(nameindex)
w_value = None
- if space.config.objspace.std.getattributeshortcut:
- w_type = space.type(w_obj)
- fastpath = w_type.uses_object_getattribute
- # conservatively, 'uses_object_getattribute' can be False
- # even if __getattribute__ was not overridden. In this
- # case, the code below calls space.getattr(), which will
- # set 'uses_object_getattribute' to True for the next time.
- else:
- w_getattribute = space.lookup(w_obj, '__getattribute__')
- if w_getattribute is object_getattribute(space):
- w_type = space.type(w_obj)
- fastpath = True
- else:
- fastpath = False
-
- if fastpath:
+ w_type = space.type(w_obj)
+ if w_type.has_object_getattribute():
name = space.str_w(w_name)
w_descr = w_type.lookup(name)
if w_descr is None:
@@ -87,8 +73,8 @@
"""An optimized version of space.call_method()
based on the same principle as above.
"""
- w_getattribute = space.lookup(w_obj, '__getattribute__')
- if w_getattribute is object_getattribute(space):
+ w_type = space.type(w_obj)
+ if w_type.has_object_getattribute():
w_descr = space.lookup(w_obj, methname)
typ = type(w_descr)
if typ is function.Function or typ is function.FunctionWithFixedCode:
Modified: pypy/trunk/pypy/objspace/std/dictmultiobject.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/dictmultiobject.py (original)
+++ pypy/trunk/pypy/objspace/std/dictmultiobject.py Sat Nov 14 15:56:31 2009
@@ -393,7 +393,7 @@
def __init__(self, space, w_type):
StrDictImplementation.__init__(self, space)
self.w_type = w_type
- self.original_version_tag = w_type.version_tag
+ self.original_version_tag = w_type.version_tag()
if self.original_version_tag is None:
self._shadows_anything = True
else:
@@ -419,7 +419,7 @@
def impl_shadows_anything(self):
return (self._shadows_anything or
- self.w_type.version_tag is not self.original_version_tag)
+ self.w_type.version_tag() is not self.original_version_tag)
def impl_set_shadows_anything(self):
self._shadows_anything = True
Modified: pypy/trunk/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/objspace.py (original)
+++ pypy/trunk/pypy/objspace/std/objspace.py Sat Nov 14 15:56:31 2009
@@ -692,13 +692,8 @@
from pypy.objspace.descroperation import raiseattrerror
from pypy.objspace.descroperation import object_getattribute
w_type = self.type(w_obj)
- if not w_type.uses_object_getattribute:
- # slow path: look for a custom __getattribute__ on the class
- w_descr = w_type.lookup('__getattribute__')
- # if it was not actually overriden in the class, we remember this
- # fact for the next time.
- if w_descr is object_getattribute(self):
- w_type.uses_object_getattribute = True
+ w_descr = w_type.getattribute_if_not_from_object()
+ if w_descr is not None:
return self._handle_getattribute(w_descr, w_obj, w_name)
# fast path: XXX this is duplicating most of the logic
Modified: pypy/trunk/pypy/objspace/std/test/test_versionedtype.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/test/test_versionedtype.py (original)
+++ pypy/trunk/pypy/objspace/std/test/test_versionedtype.py Sat Nov 14 15:56:31 2009
@@ -23,59 +23,100 @@
def test_tag_changes(self):
space = self.space
w_A, w_B, w_C = self.get_three_classes()
- atag = w_A.version_tag
- btag = w_B.version_tag
+ atag = w_A.version_tag()
+ btag = w_B.version_tag()
assert atag is not None
assert btag is not None
- assert w_C.version_tag is None
+ assert w_C.version_tag() is None
assert atag is not btag
w_types = space.appexec([w_A, w_B], """(A, B):
B.g = lambda self: None
""")
- assert w_B.version_tag is not btag
- assert w_A.version_tag is atag
- btag = w_B.version_tag
+ assert w_B.version_tag() is not btag
+ assert w_A.version_tag() is atag
+ btag = w_B.version_tag()
w_types = space.appexec([w_A, w_B], """(A, B):
A.f = lambda self: None
""")
- assert w_B.version_tag is not btag
- assert w_A.version_tag is not atag
- atag = w_A.version_tag
- btag = w_B.version_tag
+ assert w_B.version_tag() is not btag
+ assert w_A.version_tag() is not atag
+ atag = w_A.version_tag()
+ btag = w_B.version_tag()
assert atag is not btag
w_types = space.appexec([w_A, w_B], """(A, B):
del A.f
""")
- assert w_B.version_tag is not btag
- assert w_A.version_tag is not atag
- atag = w_A.version_tag
- btag = w_B.version_tag
+ assert w_B.version_tag() is not btag
+ assert w_A.version_tag() is not atag
+ atag = w_A.version_tag()
+ btag = w_B.version_tag()
assert atag is not btag
def test_tag_changes_when_bases_change(self):
space = self.space
w_A, w_B, w_C = self.get_three_classes()
- atag = w_A.version_tag
- btag = w_B.version_tag
+ atag = w_A.version_tag()
+ btag = w_B.version_tag()
w_types = space.appexec([w_A, w_B, w_C], """(A, B, C):
class D(object):
pass
B.__bases__ = (D, )
""")
- assert w_B.version_tag is not btag
+ assert w_B.version_tag() is not btag
+
+ def test_tag_changes_only_when_dict_changes(self):
+ space = self.space
+ w_A, w_B, w_C = self.get_three_classes()
+ atag = w_A.version_tag()
+ # setting a descriptor does not change the version_tag
+ w_types = space.appexec([w_A, w_B, w_C], """(A, B, C):
+ A.__name__ = "hello"
+ """)
+
+ assert w_A.version_tag() is atag
+ # deleting via a descriptor does not change the version_tag
+ w_types = space.appexec([w_A, w_B, w_C], """(A, B, C):
+ try:
+ del A.__name__
+ except AttributeError:
+ pass
+ """)
+ assert w_A.version_tag() is atag
+
+ # deleting a non-existing key does not change the version_tag
+ w_types = space.appexec([w_A, w_B, w_C], """(A, B, C):
+ try:
+ del A.abc
+ except AttributeError:
+ pass
+ """)
+ assert w_A.version_tag() is atag
+
+ def test_tag_changes_When_module_changes(self):
+ space = self.space
+ w_A, w_B, w_C = self.get_three_classes()
+ atag = w_A.version_tag()
+ # setting a descriptor does not change the version_tag
+ w_types = space.appexec([w_A, w_B, w_C], """(A, B, C):
+ A.__module__ = "hello"
+ """)
+
+ assert w_A.version_tag() is not atag
+
+
def test_version_tag_of_builtin_types(self):
space = self.space
- assert space.w_list.version_tag is not None
- assert space.w_dict.version_tag is not None
- assert space.type(space.sys).version_tag is None
- assert space.w_type.version_tag is None
+ assert space.w_list.version_tag() is not None
+ assert space.w_dict.version_tag() is not None
+ assert space.type(space.sys).version_tag() is None
+ assert space.w_type.version_tag() is None
w_function = space.appexec([], """():
def f():
pass
return type(f)
""")
- assert w_function.version_tag is None
+ assert w_function.version_tag() is None
def test_version_tag_of_subclasses_of_builtin_types(self):
space = self.space
@@ -95,11 +136,11 @@
""")
(w_LIST, w_DICT, w_TYPE, w_MODULE,
w_OBJECT) = space.unpackiterable(w_types)
- assert w_LIST.version_tag is not None
- assert w_DICT.version_tag is not None
- assert w_TYPE.version_tag is None
- assert w_MODULE.version_tag is None
- assert w_OBJECT.version_tag is not None
+ assert w_LIST.version_tag() is not None
+ assert w_DICT.version_tag() is not None
+ assert w_TYPE.version_tag() is None
+ assert w_MODULE.version_tag() is None
+ assert w_OBJECT.version_tag() is not None
class AppTestVersionedType(test_typeobject.AppTestTypeObject):
def setup_class(cls):
Modified: pypy/trunk/pypy/objspace/std/typeobject.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/typeobject.py (original)
+++ pypy/trunk/pypy/objspace/std/typeobject.py Sat Nov 14 15:56:31 2009
@@ -48,7 +48,10 @@
from pypy.objspace.std.typetype import type_typedef as typedef
lazyloaders = {} # can be overridden by specific instances
- version_tag = None
+
+ # the version_tag changes if the dict or the inheritance hierarchy changes
+ # other changes to the type (e.g. the name) leave it unchanged
+ _version_tag = None
_immutable_fields_ = ["__flags__",
'needsdel',
@@ -92,10 +95,11 @@
if w_self.instancetypedef.hasdict or custom_metaclass:
pass
else:
- w_self.version_tag = VersionTag()
+ w_self._version_tag = VersionTag()
def mutated(w_self):
space = w_self.space
+ assert w_self.is_heaptype() or not space.config.objspace.std.immutable_builtintypes
if (not space.config.objspace.std.withtypeversion and
not space.config.objspace.std.getattributeshortcut and
not space.config.objspace.std.newshortcut):
@@ -109,14 +113,52 @@
w_self.w_bltin_new = None
if (space.config.objspace.std.withtypeversion
- and w_self.version_tag is not None):
- w_self.version_tag = VersionTag()
+ and w_self._version_tag is not None):
+ w_self._version_tag = VersionTag()
subclasses_w = w_self.get_subclasses()
for w_subclass in subclasses_w:
assert isinstance(w_subclass, W_TypeObject)
w_subclass.mutated()
+ def version_tag(w_self):
+ if (not we_are_jitted() or w_self.is_heaptype() or not
+ w_self.space.config.objspace.std.immutable_builtintypes):
+ return w_self._version_tag
+ # pure objects cannot get their version_tag changed
+ w_self = hint(w_self, promote=True)
+ return w_self._pure_version_tag()
+
+ def getattribute_if_not_from_object(w_self):
+ """ this method returns the applevel __getattribute__ if that is not
+ the one from object, in which case it returns None """
+ from pypy.objspace.descroperation import object_getattribute
+ if not we_are_jitted():
+ shortcut = w_self.space.config.objspace.std.getattributeshortcut
+ if not shortcut or not w_self.uses_object_getattribute:
+ # slow path: look for a custom __getattribute__ on the class
+ w_descr = w_self.lookup('__getattribute__')
+ # if it was not actually overriden in the class, we remember this
+ # fact for the next time.
+ if w_descr is object_getattribute(w_self.space):
+ if shortcut:
+ w_self.uses_object_getattribute = True
+ else:
+ return w_descr
+ return None
+ # in the JIT case, just use a lookup, because it is folded away
+ # correctly using the version_tag
+ w_descr = w_self.lookup('__getattribute__')
+ if w_descr is not object_getattribute(w_self.space):
+ return w_descr
+
+ def has_object_getattribute(w_self):
+ return w_self.getattribute_if_not_from_object() is None
+
+ @purefunction
+ def _pure_version_tag(w_self):
+ return w_self._version_tag
+
def ready(w_self):
for w_base in w_self.bases_w:
if not isinstance(w_base, W_TypeObject):
@@ -195,21 +237,11 @@
return w_class, w_value
return None, None
- @purefunction
- def _pure_lookup_where_builtin_type(w_self, name):
- assert not w_self.is_heaptype()
- return w_self._lookup_where(name)
-
def lookup_where_with_method_cache(w_self, name):
space = w_self.space
w_self = hint(w_self, promote=True)
assert space.config.objspace.std.withmethodcache
- if (space.config.objspace.std.immutable_builtintypes and
- we_are_jitted() and not w_self.is_heaptype()):
- w_self = hint(w_self, promote=True)
- name = hint(name, promote=True)
- return w_self._pure_lookup_where_builtin_type(name)
- version_tag = w_self.version_tag
+ version_tag = w_self.version_tag()
version_tag = hint(version_tag, promote=True)
if version_tag is None:
tup = w_self._lookup_where(name)
@@ -594,7 +626,15 @@
else:
return space.type(w_obj)
# invoke the __new__ of the type
- w_bltin_new = w_type.w_bltin_new
+ if not we_are_jitted():
+ # note that the annotator will figure out that w_type.w_bltin_new can
+ # only be None if the newshortcut config option is not set
+ w_bltin_new = w_type.w_bltin_new
+ else:
+ # for the JIT it is better to take the slow path because normal lookup
+ # is nicely optimized, but the w_type.w_bltin_new attribute is not
+ # known to the JIT
+ w_bltin_new = None
call_init = True
if w_bltin_new is not None:
w_newobject = space.call_obj_args(w_bltin_new, w_type, __args__)
@@ -602,6 +642,7 @@
w_newtype, w_newdescr = w_type.lookup_where('__new__')
w_newfunc = space.get(w_newdescr, w_type)
if (space.config.objspace.std.newshortcut and
+ not we_are_jitted() and
isinstance(w_newtype, W_TypeObject) and
not w_newtype.is_heaptype() and
not space.is_w(w_newtype, space.w_type)):
@@ -622,10 +663,6 @@
return w_type2 in w_type1.mro_w
@purefunction
-def _pure_issubtype_builtin(w_type1, w_type2):
- return _issubtype(w_type1, w_type2)
-
- at purefunction
def _pure_issubtype(w_type1, w_type2, version_tag1, version_tag2):
return _issubtype(w_type1, w_type2)
@@ -633,19 +670,13 @@
w_type1 = hint(w_type1, promote=True)
w_type2 = hint(w_type2, promote=True)
if space.config.objspace.std.withtypeversion and we_are_jitted():
- if (space.config.objspace.std.immutable_builtintypes and
- not w_type1.is_heaptype() and
- not w_type2.is_heaptype()):
- res = _pure_issubtype_builtin(w_type1, w_type2)
+ version_tag1 = w_type1.version_tag()
+ version_tag2 = w_type2.version_tag()
+ version_tag1 = hint(version_tag1, promote=True)
+ version_tag2 = hint(version_tag2, promote=True)
+ if version_tag1 is not None and version_tag2 is not None:
+ res = _pure_issubtype(w_type1, w_type2, version_tag1, version_tag2)
return space.newbool(res)
- else:
- version_tag1 = w_type1.version_tag
- version_tag2 = w_type2.version_tag
- version_tag1 = hint(version_tag1, promote=True)
- version_tag2 = hint(version_tag2, promote=True)
- if version_tag1 is not None and version_tag2 is not None:
- res = _pure_issubtype(w_type1, w_type2, version_tag1, version_tag2)
- return space.newbool(res)
res = _issubtype(w_type1, w_type2)
return space.newbool(res)
@@ -684,7 +715,6 @@
# Note. This is exactly the same thing as descroperation.descr__setattr__,
# but it is needed at bootstrap to avoid a call to w_type.getdict() which
# would un-lazify the whole type.
- w_type.mutated()
name = space.str_w(w_name)
w_descr = space.lookup(w_type, name)
if w_descr is not None:
@@ -699,10 +729,10 @@
if name == "__del__" and name not in w_type.dict_w:
msg = "a __del__ method added to an existing type will not be called"
space.warn(msg, space.w_RuntimeWarning)
+ w_type.mutated()
w_type.dict_w[name] = w_value
def delattr__Type_ANY(space, w_type, w_name):
- w_type.mutated()
if w_type.lazyloaders:
w_type._freeze_() # force un-lazification
name = space.str_w(w_name)
@@ -717,9 +747,11 @@
raise OperationError(space.w_TypeError, space.wrap(msg))
try:
del w_type.dict_w[name]
- return
except KeyError:
raise OperationError(space.w_AttributeError, w_name)
+ else:
+ w_type.mutated()
+ return
# ____________________________________________________________
Modified: pypy/trunk/pypy/objspace/std/typetype.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/typetype.py (original)
+++ pypy/trunk/pypy/objspace/std/typetype.py Sat Nov 14 15:56:31 2009
@@ -194,6 +194,7 @@
raise OperationError(space.w_TypeError,
space.wrap("can't set %s.__module__" %
w_type.name))
+ w_type.mutated()
w_type.dict_w['__module__'] = w_value
def descr___subclasses__(space, w_type):
More information about the Pypy-commit
mailing list