[pypy-commit] pypy default: cpyext: Correctly invalidate the type cache when tp_dict is updated directly.
amauryfa
noreply at buildbot.pypy.org
Mon Mar 11 22:33:56 CET 2013
Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch:
Changeset: r62297:4e520ab34e44
Date: 2013-03-11 22:33 +0100
http://bitbucket.org/pypy/pypy/changeset/4e520ab34e44/
Log: cpyext: Correctly invalidate the type cache when tp_dict is updated
directly. Fixes issue1106.
diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -85,6 +85,8 @@
"""Base class for all cpyext tests."""
spaceconfig = dict(usemodules=['cpyext', 'thread', '_rawffi', 'array',
'itertools', 'rctime', 'binascii'])
+ spaceconfig['std.withmethodcache'] = True
+
enable_leak_checking = True
@staticmethod
diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -288,7 +288,38 @@
class C(object):
pass
assert module.name_by_heaptype(C) == "C"
-
+
+ def test_type_dict(self):
+ foo = self.import_module("foo")
+ module = self.import_extension('test', [
+ ("hack_tp_dict", "METH_O",
+ '''
+ PyTypeObject *type = args->ob_type;
+ PyObject *a1 = PyLong_FromLong(1);
+ PyObject *a2 = PyLong_FromLong(2);
+ PyObject *value;
+
+ if (PyDict_SetItemString(type->tp_dict, "a",
+ a1) < 0)
+ return NULL;
+ Py_DECREF(a1);
+ PyType_Modified(type);
+ value = PyObject_GetAttrString(type, "a");
+ Py_DECREF(value);
+
+ if (PyDict_SetItemString(type->tp_dict, "a",
+ a2) < 0)
+ return NULL;
+ Py_DECREF(a2);
+ PyType_Modified(type);
+ value = PyObject_GetAttrString(type, "a");
+ return value;
+ '''
+ )
+ ])
+ obj = foo.new()
+ assert module.hack_tp_dict(obj) == 2
+
class TestTypes(BaseApiTest):
def test_type_attributes(self, space, api):
@@ -326,7 +357,7 @@
w_obj = api._PyType_Lookup(w_type, space.wrap("__invalid"))
assert w_obj is None
assert api.PyErr_Occurred() is None
-
+
class AppTestSlots(AppTestCpythonExtensionBase):
def test_some_slots(self):
module = self.import_extension('foo', [
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -729,6 +729,9 @@
subtypes. This function must be called after any manual
modification of the attributes or base classes of the type.
"""
- # PyPy already takes care of direct modifications to type.__dict__
- # (which is a W_DictProxyObject).
- pass
+ # Invalidate the type cache in case of a builtin type.
+ if not isinstance(w_obj, W_TypeObject):
+ return
+ if w_obj.is_cpytype():
+ w_obj.mutated(None)
+
diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py
--- a/pypy/objspace/std/dictproxyobject.py
+++ b/pypy/objspace/std/dictproxyobject.py
@@ -54,10 +54,11 @@
raise
if not w_type.is_cpytype():
raise
- # xxx obscure workaround: allow cpyext to write to type->tp_dict
- # xxx even in the case of a builtin type.
- # xxx like CPython, we assume that this is only done early after
- # xxx the type is created, and we don't invalidate any cache.
+ # Allow cpyext to write to type->tp_dict even in the case
+ # of a builtin type.
+ # Like CPython, we assume that this is only done early
+ # after the type is created, and we don't invalidate any
+ # cache. User code shoud call PyType_Modified().
w_type.dict_w[key] = w_value
def setdefault(self, w_dict, w_key, w_default):
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
@@ -161,7 +161,7 @@
generic mutation.
"""
space = w_self.space
- assert w_self.is_heaptype()
+ assert w_self.is_heaptype() or w_self.is_cpytype()
if (not space.config.objspace.std.withtypeversion and
not space.config.objspace.std.getattributeshortcut and
not space.config.objspace.std.withidentitydict and
More information about the pypy-commit
mailing list