[pypy-commit] pypy refactor-wrapped-del: Detect cases were an rpython __del__ method calls "too much".
arigo
noreply at buildbot.pypy.org
Mon Jul 11 19:16:59 CEST 2011
Author: Armin Rigo <arigo at tunes.org>
Branch: refactor-wrapped-del
Changeset: r45466:b484c65880dc
Date: 2011-07-11 11:20 +0200
http://bitbucket.org/pypy/pypy/changeset/b484c65880dc/
Log: Detect cases were an rpython __del__ method calls "too much". "Too
much" is undefined so far; it will be "something with a
jit_merge_point".
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -482,6 +482,13 @@
key[2:])
cache[key] = s_value
+ # add the attribute _dont_reach_me_in_del_ (see pypy.rpython.rclass)
+ try:
+ graph = self.bookkeeper.position_key[0]
+ graph.func._dont_reach_me_in_del_ = True
+ except (TypeError, AttributeError):
+ pass
+
return annmodel.s_None
def annotate_hooks(self, **kwds_s):
diff --git a/pypy/rpython/lltypesystem/rclass.py b/pypy/rpython/lltypesystem/rclass.py
--- a/pypy/rpython/lltypesystem/rclass.py
+++ b/pypy/rpython/lltypesystem/rclass.py
@@ -400,6 +400,7 @@
assert len(s_func.descriptions) == 1
funcdesc, = s_func.descriptions
graph = funcdesc.getuniquegraph()
+ self.check_graph_of_del_does_not_call_too_much(graph)
FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void)
destrptr = functionptr(FUNCTYPE, graph.name,
graph=graph,
diff --git a/pypy/rpython/rclass.py b/pypy/rpython/rclass.py
--- a/pypy/rpython/rclass.py
+++ b/pypy/rpython/rclass.py
@@ -374,6 +374,35 @@
def can_ll_be_null(self, s_value):
return s_value.can_be_none()
+ def check_graph_of_del_does_not_call_too_much(self, graph):
+ # RPython-level __del__() methods should not do "too much".
+ # In the PyPy Python interpreter, they usually do simple things
+ # like file.__del__() closing the file descriptor; or if they
+ # want to do more like call an app-level __del__() method, they
+ # enqueue the object instead, and the actual call is done later.
+ #
+ # Here, as a quick way to check "not doing too much", we check
+ # that from no RPython-level __del__() method we can reach a
+ # JitDriver.
+ #
+ # XXX wrong complexity, but good enough because the set of
+ # reachable graphs should be small
+ callgraph = self.rtyper.annotator.translator.callgraph.values()
+ seen = set([graph])
+ while True:
+ oldlength = len(seen)
+ for caller, callee in callgraph:
+ if caller in seen:
+ seen.add(callee)
+ if len(seen) == oldlength:
+ break
+ for reachable_graph in seen:
+ if (hasattr(reachable_graph, 'func') and
+ getattr(reachable_graph.func, '_dont_reach_me_in_del_',False)):
+ raise TyperError("the RPython-level __del__() method in %r "
+ "ends up indirectly calling %r" % (
+ graph, reachable_graph))
+
# ____________________________________________________________
def rtype_new_instance(rtyper, classdef, llops, classcallhop=None):
diff --git a/pypy/rpython/test/test_rclass.py b/pypy/rpython/test/test_rclass.py
--- a/pypy/rpython/test/test_rclass.py
+++ b/pypy/rpython/test/test_rclass.py
@@ -7,6 +7,7 @@
from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY
from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY
+from pypy.rpython.error import TyperError
from pypy.objspace.flow.model import summary
class EmptyBase(object):
@@ -1021,7 +1022,24 @@
assert typeOf(destrptra).TO.ARGS[0] != typeOf(destrptrb).TO.ARGS[0]
assert destrptra is not None
assert destrptrb is not None
-
+
+ def test_del_forbidden(self):
+ class A(object):
+ def __del__(self):
+ self.foo()
+ def foo(self):
+ self.bar()
+ def bar(self):
+ pass
+ bar._dont_reach_me_in_del_ = True
+ def f():
+ a = A()
+ a.foo()
+ a.bar()
+ t = TranslationContext()
+ t.buildannotator().build_types(f, [])
+ py.test.raises(TyperError, t.buildrtyper().specialize)
+
def test_instance_repr(self):
from pypy.rlib.objectmodel import current_object_addr_as_int
class FooBar(object):
More information about the pypy-commit
mailing list