[pypy-commit] pypy default: redo the equivalent of 994b78f6c6eb in a way that works (can't use rgc.no_collect for various reasons)

arigo noreply at buildbot.pypy.org
Sun Mar 29 21:30:01 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r76628:881354657952
Date: 2015-03-29 21:30 +0200
http://bitbucket.org/pypy/pypy/changeset/881354657952/

Log:	redo the equivalent of 994b78f6c6eb in a way that works (can't use
	rgc.no_collect for various reasons)

diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -251,6 +251,8 @@
         annhelper.finish()   # at this point, annotate all mix-level helpers
         annhelper.backend_optimize()
 
+        self.check_custom_trace_funcs(gcdata.gc, translator.rtyper)
+
         self.collect_analyzer = CollectAnalyzer(self.translator)
         self.collect_analyzer.analyze_all()
 
@@ -540,6 +542,24 @@
             self.gcdata._has_got_custom_trace(self.get_type_id(TP))
             specialize.arg(2)(func)
 
+    def check_custom_trace_funcs(self, gc, rtyper):
+        # detect if one of the custom trace functions uses the GC
+        # (it must not!)
+        for TP, func in rtyper.custom_trace_funcs:
+            def no_op_callback(obj, arg):
+                pass
+            def ll_check_no_collect(obj):
+                func(gc, obj, no_op_callback, None)
+            annhelper = annlowlevel.MixLevelHelperAnnotator(rtyper)
+            graph1 = annhelper.getgraph(ll_check_no_collect, [SomeAddress()],
+                                        annmodel.s_None)
+            annhelper.finish()
+            collect_analyzer = CollectAnalyzer(self.translator)
+            if collect_analyzer.analyze_direct_call(graph1):
+                raise Exception(
+                    "the custom trace hook %r for %r can cause "
+                    "the GC to be called!" % (func, TP))
+
     def consider_constant(self, TYPE, value):
         self.layoutbuilder.consider_constant(TYPE, value, self.gcdata.gc)
 
diff --git a/rpython/memory/gctransform/test/test_framework.py b/rpython/memory/gctransform/test/test_framework.py
--- a/rpython/memory/gctransform/test/test_framework.py
+++ b/rpython/memory/gctransform/test/test_framework.py
@@ -143,6 +143,31 @@
     expected = "'no_collect' function can trigger collection: <function g at "
     assert str(f.value).startswith(expected)
 
+def test_custom_trace_function_no_collect():
+    from rpython.rlib import rgc
+    from rpython.translator.c.genc import CStandaloneBuilder
+
+    S = lltype.GcStruct("MyStructure")
+    class Glob:
+        pass
+    glob = Glob()
+    def trace_func(gc, obj, callback, arg):
+        glob.foo = (gc, obj)
+    lambda_trace_func = lambda: trace_func
+    def entrypoint(argv):
+        lltype.malloc(S)
+        rgc.register_custom_trace_hook(S, lambda_trace_func)
+        return 0
+
+    t = rtype(entrypoint, [s_list_of_strings])
+    t.config.translation.gc = "minimark"
+    cbuild = CStandaloneBuilder(t, entrypoint, t.config,
+                                gcpolicy=FrameworkGcPolicy2)
+    f = py.test.raises(Exception, cbuild.generate_graphs_for_llinterp)
+    assert 'can cause the GC to be called' in str(f.value)
+    assert 'trace_func' in str(f.value)
+    assert 'MyStructure' in str(f.value)
+ 
 class WriteBarrierTransformer(ShadowStackFrameworkGCTransformer):
     clean_sets = {}
     GC_PARAMS = {}


More information about the pypy-commit mailing list