Author: Armin Rigo <ar...@tunes.org>
Branch: gc-del-3
Changeset: r84179:979bc16d2cc9
Date: 2016-05-03 22:48 +0200
http://bitbucket.org/pypy/pypy/changeset/979bc16d2cc9/

Log:    in-progress

diff --git a/rpython/memory/gc/base.py b/rpython/memory/gc/base.py
--- a/rpython/memory/gc/base.py
+++ b/rpython/memory/gc/base.py
@@ -6,6 +6,9 @@
 from rpython.memory.support import DEFAULT_CHUNK_SIZE
 from rpython.memory.support import get_address_stack, get_address_deque
 from rpython.memory.support import AddressDict, null_address_dict
+from rpython.memory.support import make_list_of_nongc_instances
+from rpython.memory.support import list_set_nongc_instance
+from rpython.memory.support import list_get_nongc_instance
 from rpython.rtyper.lltypesystem.llmemory import NULL, raw_malloc_usage
 
 TYPEID_MAP = lltype.GcStruct('TYPEID_MAP', ('count', lltype.Signed),
@@ -33,7 +36,7 @@
         self.config = config
         assert isinstance(translated_to_c, bool)
         self.translated_to_c = translated_to_c
-        self._finalizer_queue_objects = []
+        self.run_finalizer_queues = make_list_of_nongc_instances(0)
 
     def setup(self):
         # all runtime mutable values' setup should happen here
@@ -42,17 +45,23 @@
 
     def register_finalizer_index(self, fq, index):
         "NOT_RPYTHON"
-        while len(self._finalizer_queue_objects) <= index:
-            self._finalizer_queue_objects.append(None)
-        if self._finalizer_queue_objects[index] is None:
-            fq._reset()
-            fq._gc_deque = self.AddressDeque()
-            self._finalizer_queue_objects[index] = fq
-        else:
-            assert self._finalizer_queue_objects[index] is fq
+        if len(self.run_finalizer_queues) <= index:
+            array = make_list_of_nongc_instances(index + 1)
+            for i in range(len(self.run_finalizer_queues)):
+                array[i] = self.run_finalizer_queues[i]
+            self.run_finalizer_queues = array
+        #
+        fdold = list_get_nongc_instance(self.AddressDeque,
+                                       self.run_finalizer_queues, index)
+        list_set_nongc_instance(self.run_finalizer_queues, index,
+                                self.AddressDeque())
+        if fdold is not None:
+            fdold.delete()
 
     def mark_finalizer_to_run(self, fq_index, obj):
-        self._finalizer_queue_objects[fq_index]._gc_deque.append(obj)
+        fdeque = list_get_nongc_instance(self.AddressDeque,
+                                         self.run_finalizer_queues, fq_index)
+        fdeque.append(obj)
 
     def post_setup(self):
         # More stuff that needs to be initialized when the GC is already
@@ -61,7 +70,7 @@
         self.DEBUG = env.read_from_env('PYPY_GC_DEBUG')
 
     def _teardown(self):
-        self._finalizer_queue_objects = []     # for tests
+        pass
 
     def can_optimize_clean_setarrayitems(self):
         return True     # False in case of card marking
@@ -342,10 +351,11 @@
 
     def enum_pending_finalizers(self, callback, arg):
         i = 0
-        while i < len(self._finalizer_queue_objects):
-            fq = self._finalizer_queue_objects[i]
-            if fq is not None:
-                fq._gc_deque.foreach(callback, arg)
+        while i < len(self.run_finalizer_queues):
+            fdeque = list_get_nongc_instance(self.AddressDeque,
+                                             self.run_finalizer_queues, i)
+            if fdeque is not None:
+                fdeque.foreach(callback, arg)
             i += 1
     enum_pending_finalizers._annspecialcase_ = 'specialize:arg(1)'
 
@@ -393,14 +403,24 @@
         self.finalizer_lock = True
         try:
             i = 0
-            while i < len(self._finalizer_queue_objects):
-                fq = self._finalizer_queue_objects[i]
-                if fq is not None and fq._gc_deque.non_empty():
+            while i < len(self.run_finalizer_queues):
+                fdeque = list_get_nongc_instance(self.AddressDeque,
+                                                 self.run_finalizer_queues, i)
+                if fdeque is not None and fdeque.non_empty():
                     self.finalizer_trigger(i)
                 i += 1
         finally:
             self.finalizer_lock = False
 
+    def finalizer_next_dead(self, fq_index):
+        fdeque = list_get_nongc_instance(self.AddressDeque,
+                                         self.run_finalizer_queues, fq_index)
+        if fdeque.non_empty():
+            obj = fdeque.popleft()
+        else:
+            obj = llmemory.NULL
+        return llmemory.cast_adr_to_ptr(obj, llmemory.GCREF)
+
 
 class MovingGCBase(GCBase):
     moving_gc = True
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
@@ -255,6 +255,7 @@
 
         self.layoutbuilder.encode_type_shapes_now()
         self.create_custom_trace_funcs(gcdata.gc, translator.rtyper)
+        self.create_finalizer_trigger(gcdata)
 
         annhelper.finish()   # at this point, annotate all mix-level helpers
         annhelper.backend_optimize()
@@ -301,7 +302,6 @@
                 [s_gc, s_typeid16,
                 annmodel.SomeInteger(nonneg=True),
                 annmodel.SomeBool(),
-                annmodel.SomeBool(),
                 annmodel.SomeBool()], s_gcref,
                 inline = False)
             self.malloc_varsize_ptr = getfn(
@@ -316,7 +316,6 @@
                 [s_gc, s_typeid16,
                  annmodel.SomeInteger(nonneg=True),
                  annmodel.SomeBool(),
-                 annmodel.SomeBool(),
                  annmodel.SomeBool()], s_gcref,
                 inline = False)
             self.malloc_varsize_ptr = getfn(
@@ -379,7 +378,7 @@
                 malloc_fast,
                 [s_gc, s_typeid16,
                  annmodel.SomeInteger(nonneg=True),
-                 s_False, s_False, s_False], s_gcref,
+                 s_False, s_False], s_gcref,
                 inline = True)
         else:
             self.malloc_fast_ptr = None
@@ -597,6 +596,11 @@
                     "the custom trace hook %r for %r can cause "
                     "the GC to be called!" % (func, TP))
 
+    def create_finalizer_trigger(self, gcdata):
+        def ll_finalizer_trigger(fq_index):
+            pass #xxxxxxxxxxxxx
+        gcdata.init_finalizer_trigger(ll_finalizer_trigger)
+
     def consider_constant(self, TYPE, value):
         self.layoutbuilder.consider_constant(TYPE, value, self.gcdata.gc)
 
@@ -772,13 +776,10 @@
         info = self.layoutbuilder.get_info(type_id)
         c_size = rmodel.inputconst(lltype.Signed, info.fixedsize)
         fptrs = self.special_funcptr_for_type(TYPE)
-        has_finalizer = "finalizer" in fptrs
-        has_light_finalizer = "light_finalizer" in fptrs
-        if has_light_finalizer:
-            has_finalizer = True
-        c_has_finalizer = rmodel.inputconst(lltype.Bool, has_finalizer)
-        c_has_light_finalizer = rmodel.inputconst(lltype.Bool,
-                                                  has_light_finalizer)
+        has_destructor = "destructor" in fptrs
+        assert "finalizer" not in fptrs         # removed
+        assert "light_finalizer" not in fptrs   # removed
+        c_has_destructor = rmodel.inputconst(lltype.Bool, has_destructor)
 
         if flags.get('nonmovable'):
             assert op.opname == 'malloc'
@@ -788,16 +789,16 @@
         elif not op.opname.endswith('_varsize') and not flags.get('varsize'):
             zero = flags.get('zero', False)
             if (self.malloc_fast_ptr is not None and
-                not c_has_finalizer.value and
+                not c_has_destructor.value and
                 (self.malloc_fast_is_clearing or not zero)):
                 malloc_ptr = self.malloc_fast_ptr
             else:
                 malloc_ptr = self.malloc_fixedsize_ptr
             args = [self.c_const_gc, c_type_id, c_size,
-                    c_has_finalizer, c_has_light_finalizer,
+                    c_has_destructor,
                     rmodel.inputconst(lltype.Bool, False)]
         else:
-            assert not c_has_finalizer.value
+            assert not c_has_destructor.value
             info_varsize = self.layoutbuilder.get_info_varsize(type_id)
             v_length = op.args[-1]
             c_ofstolength = rmodel.inputconst(lltype.Signed,
@@ -933,13 +934,12 @@
     def gct_do_malloc_fixedsize(self, hop):
         # used by the JIT (see rpython.jit.backend.llsupport.gc)
         op = hop.spaceop
-        [v_typeid, v_size,
-         v_has_finalizer, v_has_light_finalizer, v_contains_weakptr] = op.args
+        [v_typeid, v_size, v_has_destructor, v_contains_weakptr] = op.args
         livevars = self.push_roots(hop)
         hop.genop("direct_call",
                   [self.malloc_fixedsize_ptr, self.c_const_gc,
                    v_typeid, v_size,
-                   v_has_finalizer, v_has_light_finalizer,
+                   v_has_destructor,
                    v_contains_weakptr],
                   resultvar=op.result)
         self.pop_roots(hop, livevars)
@@ -1047,7 +1047,7 @@
         c_false = rmodel.inputconst(lltype.Bool, False)
         c_has_weakptr = rmodel.inputconst(lltype.Bool, True)
         args = [self.c_const_gc, c_type_id, c_size,
-                c_false, c_false, c_has_weakptr]
+                c_false, c_has_weakptr]
 
         # push and pop the current live variables *including* the argument
         # to the weakref_create operation, which must be kept alive and
@@ -1518,18 +1518,14 @@
         return rtti is not None and getattr(rtti._obj, 'destructor_funcptr',
                                             None)
 
-    def has_light_finalizer(self, TYPE):
-        fptrs = self.special_funcptr_for_type(TYPE)
-        return "light_finalizer" in fptrs
-
     def has_custom_trace(self, TYPE):
         rtti = get_rtti(TYPE)
         return rtti is not None and getattr(rtti._obj, 'custom_trace_funcptr',
                                             None)
 
-    def make_finalizer_funcptr_for_type(self, TYPE):
-        if not self.has_finalizer(TYPE):
-            return None, False
+    def make_destructor_funcptr_for_type(self, TYPE):
+        if not self.has_destructor(TYPE):
+            return None
         rtti = get_rtti(TYPE)
         destrptr = rtti._obj.destructor_funcptr
         DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0]
@@ -1539,12 +1535,9 @@
             ll_call_destructor(destrptr, v, typename)
         fptr = self.transformer.annotate_finalizer(ll_finalizer,
                 [llmemory.Address], lltype.Void)
-        try:
-            g = destrptr._obj.graph
-            light = not 
FinalizerAnalyzer(self.translator).analyze_light_finalizer(g)
-        except lltype.DelayedPointer:
-            light = False    # XXX bah, too bad
-        return fptr, light
+        g = destrptr._obj.graph
+        FinalizerAnalyzer(self.translator).check_light_finalizer(g)
+        return fptr
 
     def make_custom_trace_funcptr_for_type(self, TYPE):
         if not self.has_custom_trace(TYPE):
diff --git a/rpython/memory/gctypelayout.py b/rpython/memory/gctypelayout.py
--- a/rpython/memory/gctypelayout.py
+++ b/rpython/memory/gctypelayout.py
@@ -84,10 +84,10 @@
         return (typeinfo.infobits & ANY) != 0 or bool(typeinfo.customfunc)
 
     def init_finalizer_trigger(self, finalizer_trigger):
-        self.finalizer_trigger = finalizer_trigger
+        self._finalizer_trigger = finalizer_trigger
 
     def q_finalizer_trigger(self, fq_index):
-        self.finalizer_trigger(fq_index)
+        self._finalizer_trigger(fq_index)
 
     def q_destructor_or_custom_trace(self, typeid):
         return self.get(typeid).customfunc
diff --git a/rpython/memory/gcwrapper.py b/rpython/memory/gcwrapper.py
--- a/rpython/memory/gcwrapper.py
+++ b/rpython/memory/gcwrapper.py
@@ -214,12 +214,9 @@
         return (fq, index)
 
     def gc_fq_next_dead(self, fq_tag):
-        fq, _ = self.get_finalizer_queue_index(fq_tag)
-        if fq._gc_deque.non_empty():
-            addr = fq._gc_deque.popleft()
-        else:
-            addr = llmemory.NULL
-        return llmemory.cast_adr_to_ptr(addr, rclass.OBJECTPTR)
+        fq, index = self.get_finalizer_queue_index(fq_tag)
+        return lltype.cast_opaque_ptr(rclass.OBJECTPTR,
+                                      self.gc.finalizer_next_dead(index))
 
     def gc_fq_register(self, fq_tag, ptr):
         fq, index = self.get_finalizer_queue_index(fq_tag)
diff --git a/rpython/memory/support.py b/rpython/memory/support.py
--- a/rpython/memory/support.py
+++ b/rpython/memory/support.py
@@ -2,6 +2,9 @@
 from rpython.rlib.objectmodel import free_non_gc_object, we_are_translated
 from rpython.rlib.debug import ll_assert
 from rpython.tool.identity_dict import identity_dict
+from rpython.rtyper.rclass import NONGCOBJECTPTR
+from rpython.rtyper.annlowlevel import cast_nongc_instance_to_base_ptr
+from rpython.rtyper.annlowlevel import cast_base_ptr_to_nongc_instance
 
 
 def mangle_hash(i):
@@ -393,3 +396,17 @@
 def _null_value_checker(key, value, arg):
     if value:
         arg.setitem(key, value)
+
+# ____________________________________________________________
+
+NONGCARRAY = lltype.Array(NONGCOBJECTPTR)
+
+def make_list_of_nongc_instances(count):
+    return lltype.malloc(NONGCARRAY, count, flavor='raw', zero=True,
+                         track_allocation=False)
+
+def list_get_nongc_instance(Class, array, index):
+    return cast_base_ptr_to_nongc_instance(Class, array[index])
+
+def list_set_nongc_instance(array, index, instance):
+    array[index] = cast_nongc_instance_to_base_ptr(instance)
diff --git a/rpython/memory/test/test_transformed_gc.py 
b/rpython/memory/test/test_transformed_gc.py
--- a/rpython/memory/test/test_transformed_gc.py
+++ b/rpython/memory/test/test_transformed_gc.py
@@ -293,7 +293,7 @@
         res = run([])
         assert res == 42
 
-    def define_finalizer(cls):
+    def define_destructor(cls):
         class B(object):
             pass
         b = B()
@@ -316,6 +316,39 @@
             return b.num_deleted
         return f
 
+    def test_destructor(self):
+        run = self.runner("destructor")
+        res = run([5, 42]) #XXX pure lazyness here too
+        assert res == 6
+
+    def define_finalizer(cls):
+        class B(object):
+            pass
+        b = B()
+        b.nextid = 0
+        b.num_deleted = 0
+        class A(object):
+            def __init__(self):
+                self.id = b.nextid
+                b.nextid += 1
+                fq.register_finalizer(self)
+        class FQ(rgc.FinalizerQueue):
+            Class = A
+            def finalizer_trigger(self):
+                while self.next_dead() is not None:
+                    b.num_deleted += 1
+        fq = FQ()
+        def f(x, y):
+            a = A()
+            i = 0
+            while i < x:
+                i += 1
+                a = A()
+            llop.gc__collect(lltype.Void)
+            llop.gc__collect(lltype.Void)
+            return b.num_deleted
+        return f
+
     def test_finalizer(self):
         run = self.runner("finalizer")
         res = run([5, 42]) #XXX pure lazyness here too
@@ -331,12 +364,20 @@
             def __init__(self):
                 self.id = b.nextid
                 b.nextid += 1
-            def __del__(self):
-                b.num_deleted += 1
-                C()
+                fq.register_finalizer(self)
         class C(AAA):
-            def __del__(self):
-                b.num_deleted += 1
+            pass
+        class FQ(rgc.FinalizerQueue):
+            Class = AAA
+            def finalizer_trigger(self):
+                while True:
+                    a = self.next_dead()
+                    if a is None:
+                        break
+                    b.num_deleted += 1
+                    if not isinstance(a, C):
+                        C()
+        fq = FQ()
         def f(x, y):
             a = AAA()
             i = 0
@@ -363,9 +404,17 @@
             def __init__(self):
                 self.id = b.nextid
                 b.nextid += 1
-            def __del__(self):
-                b.num_deleted += 1
-                b.a = self
+                fq.register_finalizer(self)
+        class FQ(rgc.FinalizerQueue):
+            Class = A
+            def finalizer_trigger(self):
+                while True:
+                    a = self.next_dead()
+                    if a is None:
+                        break
+                    b.num_deleted += 1
+                    b.a = a
+        fq = FQ()
         def f(x, y):
             a = A()
             i = 0
@@ -376,7 +425,7 @@
             llop.gc__collect(lltype.Void)
             aid = b.a.id
             b.a = None
-            # check that __del__ is not called again
+            # check that finalizer_trigger() is not called again
             llop.gc__collect(lltype.Void)
             llop.gc__collect(lltype.Void)
             return b.num_deleted * 10 + aid + 100 * (b.a is None)
@@ -440,7 +489,7 @@
         res = run([])
         assert res
 
-    def define_weakref_to_object_with_finalizer(cls):
+    def define_weakref_to_object_with_destructor(cls):
         import weakref, gc
         class A(object):
             count = 0
@@ -459,6 +508,36 @@
             return result
         return f
 
+    def test_weakref_to_object_with_destructor(self):
+        run = self.runner("weakref_to_object_with_destructor")
+        res = run([])
+        assert res
+
+    def define_weakref_to_object_with_finalizer(cls):
+        import weakref, gc
+        class A(object):
+            count = 0
+        a = A()
+        class B(object):
+            pass
+        class FQ(rgc.FinalizerQueue):
+            Class = B
+            def finalizer_trigger(self):
+                while self.next_dead() is not None:
+                    a.count += 1
+        fq = FQ()
+        def g():
+            b = B()
+            fq.register_finalizer(b)
+            return weakref.ref(b)
+        def f():
+            ref = g()
+            llop.gc__collect(lltype.Void)
+            llop.gc__collect(lltype.Void)
+            result = a.count == 1 and (ref() is None)
+            return result
+        return f
+
     def test_weakref_to_object_with_finalizer(self):
         run = self.runner("weakref_to_object_with_finalizer")
         res = run([])
@@ -475,15 +554,24 @@
             def __init__(self):
                 self.id = b.nextid
                 b.nextid += 1
-            def __del__(self):
-                llop.gc__collect(lltype.Void)
-                b.num_deleted += 1
-                C()
-                C()
+                fq.register_finalizer(self)
         class C(A):
-            def __del__(self):
-                b.num_deleted += 1
-                b.num_deleted_c += 1
+            pass
+        class FQ(rgc.FinalizerQueue):
+            Class = A
+            def finalizer_trigger(self):
+                while True:
+                    a = self.next_dead()
+                    if a is None:
+                        break
+                    llop.gc__collect(lltype.Void)
+                    b.num_deleted += 1
+                    if isinstance(a, C):
+                        b.num_deleted_c += 1
+                    else:
+                        C()
+                        C()
+        fq = FQ()
         def f(x, y):
             persistent_a1 = A()
             persistent_a2 = A()
@@ -756,8 +844,7 @@
                 if op.opname == 'do_malloc_fixedsize':
                     op.args = [Constant(type_id, llgroup.HALFWORD),
                                Constant(llmemory.sizeof(P), lltype.Signed),
-                               Constant(False, lltype.Bool), # has_finalizer
-                               Constant(False, lltype.Bool), # 
is_finalizer_light
+                               Constant(False, lltype.Bool), # has_destructor
                                Constant(False, lltype.Bool)] # contains_weakptr
                     break
             else:
@@ -793,8 +880,7 @@
                 if op.opname == 'do_malloc_fixedsize':
                     op.args = [Constant(type_id, llgroup.HALFWORD),
                                Constant(llmemory.sizeof(P), lltype.Signed),
-                               Constant(False, lltype.Bool), # has_finalizer
-                               Constant(False, lltype.Bool), # 
is_finalizer_light
+                               Constant(False, lltype.Bool), # has_destructor
                                Constant(False, lltype.Bool)] # contains_weakptr
                     break
             else:
diff --git a/rpython/rtyper/annlowlevel.py b/rpython/rtyper/annlowlevel.py
--- a/rpython/rtyper/annlowlevel.py
+++ b/rpython/rtyper/annlowlevel.py
@@ -471,6 +471,11 @@
     return lltype.cast_opaque_ptr(llmemory.GCREF,
                                   cast_instance_to_base_ptr(instance))
 
+@specialize.argtype(0)
+def cast_nongc_instance_to_base_ptr(instance):
+    from rpython.rtyper.rclass import NONGCOBJECTPTR
+    return cast_object_to_ptr(NONGCOBJECTPTR, instance)
+
 class CastObjectToPtrEntry(extregistry.ExtRegistryEntry):
     _about_ = cast_object_to_ptr
 
@@ -512,6 +517,8 @@
                                   % (ptr, Class))
     return ptr
 
+cast_base_ptr_to_nongc_instance = cast_base_ptr_to_instance
+
 @specialize.arg(0)
 def cast_gcref_to_instance(Class, ptr):
     """Reverse the hacking done in cast_instance_to_gcref()."""
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to