[pypy-commit] pypy stmgc-c7: Finalizers, step 1

arigo noreply at buildbot.pypy.org
Fri Oct 17 16:16:33 CEST 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: stmgc-c7
Changeset: r73998:3159fb66123b
Date: 2014-10-17 16:16 +0200
http://bitbucket.org/pypy/pypy/changeset/3159fb66123b/

Log:	Finalizers, step 1

diff --git a/rpython/memory/gc/stmgc.py b/rpython/memory/gc/stmgc.py
--- a/rpython/memory/gc/stmgc.py
+++ b/rpython/memory/gc/stmgc.py
@@ -73,13 +73,13 @@
                                needs_finalizer=False,
                                is_finalizer_light=False,
                                contains_weakptr=False):
-        # XXX finalizers are ignored for now
-        #ll_assert(not needs_finalizer, 'XXX needs_finalizer')
-        #ll_assert(not is_finalizer_light, 'XXX is_finalizer_light')
         if size < 16:
             size = 16     # minimum size (test usually constant-folded)
         if contains_weakptr:    # check constant-folded
             return llop.stm_allocate_weakref(llmemory.GCREF, size, typeid16)
+        if needs_finalizer:
+            #is_finalizer_light  XXX ignored now
+            return llop.stm_allocate_finalizer(llmemory.GCREF, size, typeid16)
         return llop.stm_allocate_tid(llmemory.GCREF, size, typeid16)
 
     def malloc_varsize_clear(self, typeid16, length, size, itemsize,
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
@@ -1257,8 +1257,6 @@
         super(TransformerLayoutBuilder, self).__init__(GCClass, lltype2vtable)
 
     def has_finalizer(self, TYPE):
-        if self.translator.config.translation.stm:
-            return False  # XXX no finalizer support for now
         rtti = get_rtti(TYPE)
         return rtti is not None and getattr(rtti._obj, 'destructor_funcptr',
                                             None)
@@ -1275,22 +1273,24 @@
     def make_finalizer_funcptr_for_type(self, TYPE):
         if not self.has_finalizer(TYPE):
             return None, False
+        stm = self.translator.config.translation.stm
         rtti = get_rtti(TYPE)
         destrptr = rtti._obj.destructor_funcptr
         DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0]
         typename = TYPE.__name__
         def ll_finalizer(addr):
-            v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG)
+            if stm:
+                from rpython.rtyper.lltypesystem.lloperation import llop
+                v = llop.stm_really_force_cast_ptr(DESTR_ARG, addr)
+            else:
+                v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG)
             ll_call_destructor(destrptr, v, typename)
         fptr = self.transformer.annotate_finalizer(ll_finalizer,
                 [llmemory.Address], lltype.Void)
         try:
             g = destrptr._obj.graph
-            if self.translator.config.translation.stm:
-                light = False    # XXX no working finalizers with STM so far
-            else:
-                analyzer = FinalizerAnalyzer(self.translator)
-                light = not analyzer.analyze_light_finalizer(g)
+            analyzer = FinalizerAnalyzer(self.translator)
+            light = not analyzer.analyze_light_finalizer(g)
         except lltype.DelayedPointer:
             light = False    # XXX bah, too bad
         return fptr, light
diff --git a/rpython/memory/gctransform/stmframework.py b/rpython/memory/gctransform/stmframework.py
--- a/rpython/memory/gctransform/stmframework.py
+++ b/rpython/memory/gctransform/stmframework.py
@@ -1,7 +1,8 @@
 from rpython.annotator import model as annmodel
-from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
+from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, llgroup
 from rpython.rtyper.lltypesystem.lloperation import llop
-from rpython.memory.gctransform.framework import ( TYPE_ID,
+from rpython.memory.gctransform.support import get_rtti
+from rpython.memory.gctransform.framework import (TYPE_ID,
      BaseFrameworkGCTransformer, BaseRootWalker, sizeofaddr)
 from rpython.memory.gctypelayout import WEAKREF, WEAKREFPTR
 from rpython.rtyper import rmodel, llannotation
@@ -66,6 +67,15 @@
                   [llannotation.SomeAddress(),
                    llannotation.SomePtr(rffi.CArrayPtr(lltype.Unsigned))],
                   annmodel.s_None))
+        #
+        def pypy_stmcb_fetch_finalizer(typeid):
+            typeid = lltype.cast_primitive(llgroup.HALFWORD, typeid)
+            return llmemory.cast_ptr_to_adr(gc.getfinalizer(typeid))
+        pypy_stmcb_fetch_finalizer.c_name = (
+            "pypy_stmcb_fetch_finalizer")
+        self.autoregister_ptrs.append(
+            getfn(pypy_stmcb_fetch_finalizer,
+                  [annmodel.s_Int], llannotation.SomeAddress()))
 
     def build_root_walker(self):
         return StmRootWalker(self)
diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -417,6 +417,7 @@
     'stm_can_move':           LLOp(),
     'stm_allocate_tid':       LLOp(sideeffects=False, canmallocgc=True),
     'stm_allocate_weakref':   LLOp(sideeffects=False, canmallocgc=True),
+    'stm_allocate_finalizer': LLOp(sideeffects=False, canmallocgc=True),
     'stm_get_from_obj':       LLOp(sideeffects=False),
     'stm_get_from_obj_const': LLOp(canfold=True),
     'stm_set_into_obj':       LLOp(),
@@ -456,7 +457,8 @@
     'stm_expand_marker':      LLOp(),
     'stm_setup_expand_marker_for_pypy': LLOp(),
 
-    'stm_count':              LLOp(),
+    'stm_count':                 LLOp(),
+    'stm_really_force_cast_ptr': LLOp(),
 
     # __________ address operations __________
 
diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py
--- a/rpython/translator/c/genc.py
+++ b/rpython/translator/c/genc.py
@@ -766,15 +766,6 @@
     print >> f
     print >> f, "#ifndef _PYPY_STRUCTDEF_H"
     print >> f, "#define _PYPY_STRUCTDEF_H"
-    if database.with_stm:
-        print >> f
-        print >> f, 'typedef TLPREFIX struct rpyobj_s {'
-        print >> f, '\tstruct object_s lib;'
-        print >> f, '\tuint32_t tid;'
-        print >> f, '} rpyobj_t;'
-        print >> f, 'typedef TLPREFIX char rpygcchar_t;'
-    else:
-        print >> f, 'typedef char rpygcchar_t;'
     print >> f
     for node in structdeflist:
         if hasattr(node, 'forward_decl'):
@@ -798,7 +789,7 @@
     if database.with_stm:
         print >> f
         print >> f, 'extern object_t *rpy_prebuilt[];'
-        print >> f
+    print >> f
     for node in database.globalcontainers():
         for line in node.forward_declaration():
             print >> f, line
diff --git a/rpython/translator/c/src/g_prerequisite.h b/rpython/translator/c/src/g_prerequisite.h
--- a/rpython/translator/c/src/g_prerequisite.h
+++ b/rpython/translator/c/src/g_prerequisite.h
@@ -25,8 +25,18 @@
 
 #ifdef RPY_STM
 #define rpy_duck()  asm("":::"memory")   // work around an llvm bug :-/
+
+typedef TLPREFIX struct rpyobj_s {
+    struct object_s lib;
+    uint32_t tid;
+} rpyobj_t;
+typedef TLPREFIX char rpygcchar_t;
+
 #else
+
 #define rpy_duck()  /* nothing */
+typedef char rpygcchar_t;
+
 #endif
 
 
diff --git a/rpython/translator/stm/funcgen.py b/rpython/translator/stm/funcgen.py
--- a/rpython/translator/stm/funcgen.py
+++ b/rpython/translator/stm/funcgen.py
@@ -89,6 +89,15 @@
     return ('%s = (rpygcchar_t *)stm_allocate_weakref(%s); ' % (result, arg_size) +
             '((rpyobj_t *)%s)->tid = %s;' % (result, arg_type_id))
 
+def stm_allocate_finalizer(funcgen, op):
+    arg_size    = funcgen.expr(op.args[0])
+    arg_type_id = funcgen.expr(op.args[1])
+    result      = funcgen.expr(op.result)
+    # XXX NULL returns?
+    return ('%s = (rpygcchar_t *)stm_allocate_with_finalizer(%s); ' % (
+        result, arg_size) +
+            '((rpyobj_t *)%s)->tid = %s;' % (result, arg_type_id))
+
 def stm_get_from_obj(funcgen, op):
     assert op.args[0].concretetype == llmemory.GCREF
     arg_obj = funcgen.expr(op.args[0])
@@ -254,3 +263,13 @@
 def stm_count(funcgen, op):
     result = funcgen.expr(op.result)
     return '%s = _pypy_stm_count();' % (result,)
+
+def stm_really_force_cast_ptr(funcgen, op):
+    # pffff, try very very hard to cast a pointer in one address space
+    # to consider it as a pointer in another address space, without
+    # changing it in any way.  It works if we cast via an integer
+    # (but not directly).
+    result = funcgen.expr(op.result)
+    arg = funcgen.expr(op.args[0])
+    typename = cdecl(funcgen.lltypename(op.result), '')
+    return '%s = (%s)(uintptr_t)%s;' % (result, typename, arg)
diff --git a/rpython/translator/stm/src_stm/extracode.h b/rpython/translator/stm/src_stm/extracode.h
--- a/rpython/translator/stm/src_stm/extracode.h
+++ b/rpython/translator/stm/src_stm/extracode.h
@@ -1,3 +1,9 @@
+
+static void _stm_call_finalizer(object_t *obj)
+{
+    void *funcptr = pypy_stmcb_fetch_finalizer(((rpyobj_t *)obj)->tid);
+    ((void(*)(object_t *))funcptr)(obj);
+}
 
 void pypy_stm_setup_prebuilt(void)
 {
@@ -23,6 +29,8 @@
     for ( ; cur != end; cur++) {
         **cur = stm_setup_prebuilt(**cur);
     }
+
+    stmcb_finalizer = &_stm_call_finalizer;
 }
 
 void pypy_stm_register_thread_local(void)
diff --git a/rpython/translator/stm/src_stm/stmgcintf.c b/rpython/translator/stm/src_stm/stmgcintf.c
--- a/rpython/translator/stm/src_stm/stmgcintf.c
+++ b/rpython/translator/stm/src_stm/stmgcintf.c
@@ -14,6 +14,7 @@
 extern void pypy_stmcb_trace(void*, void(*)(void*));
 extern void pypy_stmcb_trace_cards(void*, void(*)(void*), uintptr_t, uintptr_t);
 extern Signed pypy_stmcb_obj_supports_cards(void*);
+extern void *pypy_stmcb_fetch_finalizer(long);
 
 inline ssize_t stmcb_size_rounded_up(struct object_s *obj) {
     ssize_t result = pypy_stmcb_size_rounded_up(obj);
diff --git a/rpython/translator/stm/test/test_ztranslated.py b/rpython/translator/stm/test/test_ztranslated.py
--- a/rpython/translator/stm/test/test_ztranslated.py
+++ b/rpython/translator/stm/test/test_ztranslated.py
@@ -510,3 +510,24 @@
         assert ('starting some_extremely_longish_and_boring_function_name\n'
                 'File "<bla/br/project/foobaz.py", line 81,'
                 ' in some_extremely_longish_a>\n') in data
+
+    def test_finalizer(self):
+        class Counter:
+            num = 0
+        g_counter = Counter()
+        class X:
+            def __del__(self):
+                g_counter.num += 1
+
+        def g():
+            X()
+
+        def main(argv):
+            g()
+            rgc.collect()
+            print 'destructors called:', g_counter.num
+            return 0
+
+        t, cbuilder = self.compile(main)
+        data = cbuilder.cmdexec('')
+        assert 'destructors called: 1\n' in data


More information about the pypy-commit mailing list