[pypy-commit] pypy gc-del-3: still progressing, slowly

arigo pypy.commits at gmail.com
Tue May 3 03:26:04 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: gc-del-3
Changeset: r84168:67a03224c02d
Date: 2016-05-03 09:26 +0200
http://bitbucket.org/pypy/pypy/changeset/67a03224c02d/

Log:	still progressing, slowly

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
@@ -1,6 +1,7 @@
 from rpython.rtyper.lltypesystem import lltype, llmemory, llarena, rffi
 from rpython.rtyper.lltypesystem.lloperation import llop
 from rpython.rlib.debug import ll_assert
+from rpython.rlib.objectmodel import we_are_translated
 from rpython.memory.gcheader import GCHeaderBuilder
 from rpython.memory.support import DEFAULT_CHUNK_SIZE
 from rpython.memory.support import get_address_stack, get_address_deque
@@ -36,8 +37,26 @@
     def setup(self):
         # all runtime mutable values' setup should happen here
         # and in its overriden versions! for the benefit of test_transformed_gc
-        self.finalizer_lock_count = 0
-        self.run_finalizers = self.AddressDeque()
+        self.finalizer_lock = False
+        if we_are_translated():
+            XXXXXX
+        else:
+            self._finalizer_queue_objects = []    # XXX FIX ME
+
+    def register_finalizer_index(self, fq, index):
+        while len(self._finalizer_queue_objects) <= index:
+            self._finalizer_queue_objects.append(None)
+        if self._finalizer_queue_objects[index] is None:
+            fq._reset()
+            self._finalizer_queue_objects[index] = fq
+        else:
+            assert self._finalizer_queue_objects[index] is fq
+
+    def add_finalizer_to_run(self, fq_index, obj):
+        if we_are_translated():
+            XXXXXX
+        else:
+            self._finalizer_queue_objects[fq_index]._queue.append(obj)
 
     def post_setup(self):
         # More stuff that needs to be initialized when the GC is already
@@ -60,6 +79,7 @@
 
     def set_query_functions(self, is_varsize, has_gcptr_in_varsize,
                             is_gcarrayofgcptr,
+                            finalizer_trigger,
                             destructor_or_custom_trace,
                             offsets_to_gc_pointers,
                             fixed_size, varsize_item_sizes,
@@ -73,6 +93,7 @@
                             fast_path_tracing,
                             has_gcptr,
                             cannot_pin):
+        self.finalizer_trigger = finalizer_trigger
         self.destructor_or_custom_trace = destructor_or_custom_trace
         self.is_varsize = is_varsize
         self.has_gcptr_in_varsize = has_gcptr_in_varsize
@@ -320,9 +341,17 @@
         callback2, attrname = _convert_callback_formats(callback)    # :-/
         setattr(self, attrname, arg)
         self.root_walker.walk_roots(callback2, callback2, callback2)
-        self.run_finalizers.foreach(callback, arg)
+        self.enum_pending_finalizers(callback, arg)
     enumerate_all_roots._annspecialcase_ = 'specialize:arg(1)'
 
+    def enum_pending_finalizers(self, callback, arg):
+        if we_are_translated():
+            XXXXXX            #. foreach(callback, arg)
+        for fq in self._finalizer_queue_objects:
+            for obj in fq._queue:
+                callback(obj, arg)
+    enum_pending_finalizers._annspecialcase_ = 'specialize:arg(1)'
+
     def debug_check_consistency(self):
         """To use after a collection.  If self.DEBUG is set, this
         enumerates all roots and traces all objects to check if we didn't
@@ -362,17 +391,17 @@
         pass
 
     def execute_finalizers(self):
-        self.finalizer_lock_count += 1
+        if self.finalizer_lock:
+            return  # the outer invocation of execute_finalizers() will do it
+        self.finalizer_lock = True
         try:
-            while self.run_finalizers.non_empty():
-                if self.finalizer_lock_count > 1:
-                    # the outer invocation of execute_finalizers() will do it
-                    break
-                obj = self.run_finalizers.popleft()
-                finalizer = self.getfinalizer(self.get_type_id(obj))
-                finalizer(obj)
+            if we_are_translated():
+                XXXXXX
+            for i, fq in enumerate(self._finalizer_queue_objects):
+                if len(fq._queue) > 0:
+                    self.finalizer_trigger(i)
         finally:
-            self.finalizer_lock_count -= 1
+            self.finalizer_lock = False
 
 
 class MovingGCBase(GCBase):
diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -2422,7 +2422,7 @@
         #
         # If we are in an inner collection caused by a call to a finalizer,
         # the 'run_finalizers' objects also need to be kept alive.
-        self.run_finalizers.foreach(self._collect_obj, None)
+        self.enum_pending_finalizers(self._collect_obj, None)
 
     def enumerate_all_roots(self, callback, arg):
         self.prebuilt_root_objects.foreach(callback, arg)
@@ -2676,8 +2676,9 @@
             state = self._finalization_state(x)
             ll_assert(state >= 2, "unexpected finalization state < 2")
             if state == 2:
-                # XXX use fq_nr here
-                self.run_finalizers.append(x)
+                from rpython.rtyper.lltypesystem import rffi
+                fq_index = rffi.cast(lltype.Signed, fq_nr)
+                self.add_finalizer_to_run(fq_index, x)
                 # we must also fix the state from 2 to 3 here, otherwise
                 # we leave the GCFLAG_FINALIZATION_ORDERING bit behind
                 # which will confuse the next collection
diff --git a/rpython/memory/gctypelayout.py b/rpython/memory/gctypelayout.py
--- a/rpython/memory/gctypelayout.py
+++ b/rpython/memory/gctypelayout.py
@@ -83,6 +83,12 @@
         ANY = (T_HAS_GCPTR | T_IS_WEAKREF)
         return (typeinfo.infobits & ANY) != 0 or bool(typeinfo.customfunc)
 
+    def init_finalizer_trigger(self, finalizer_trigger):
+        self.finalizer_trigger = finalizer_trigger
+
+    def q_finalizer_trigger(self, fq_index):
+        self.finalizer_trigger(fq_index)
+
     def q_destructor_or_custom_trace(self, typeid):
         return self.get(typeid).customfunc
 
@@ -136,6 +142,7 @@
             self.q_is_varsize,
             self.q_has_gcptr_in_varsize,
             self.q_is_gcarrayofgcptr,
+            self.q_finalizer_trigger,
             self.q_destructor_or_custom_trace,
             self.q_offsets_to_gc_pointers,
             self.q_fixed_size,
@@ -374,13 +381,17 @@
         return result
 
     def make_destructor_funcptr_for_type(self, TYPE):
-        # must be overridden for proper finalizer support
+        # must be overridden for proper destructor support
         return None
 
     def make_custom_trace_funcptr_for_type(self, TYPE):
         # must be overridden for proper custom tracer support
         return None
 
+    def make_finalizer_trigger(self):
+        # must be overridden for proper finalizer support
+        return None
+
     def initialize_gc_query_function(self, gc):
         gcdata = GCData(self.type_info_group)
         gcdata.set_query_functions(gc)
diff --git a/rpython/memory/gcwrapper.py b/rpython/memory/gcwrapper.py
--- a/rpython/memory/gcwrapper.py
+++ b/rpython/memory/gcwrapper.py
@@ -1,6 +1,6 @@
 from rpython.translator.backendopt.finalizer import FinalizerAnalyzer
 from rpython.rtyper.lltypesystem import lltype, llmemory, llheap
-from rpython.rtyper import llinterp
+from rpython.rtyper import llinterp, rclass
 from rpython.rtyper.annlowlevel import llhelper
 from rpython.memory import gctypelayout
 from rpython.flowspace.model import Constant
@@ -16,12 +16,14 @@
                            chunk_size      = 10,
                            translated_to_c = False,
                            **GC_PARAMS)
+        self.translator = translator
         self.gc.set_root_walker(LLInterpRootWalker(self))
         self.gc.DEBUG = True
         self.llinterp = llinterp
         self.prepare_graphs(flowgraphs)
         self.gc.setup()
-        self.finalizer_queues = {}
+        self.finalizer_queue_indexes = {}
+        self.finalizer_queues = []
         self.has_write_barrier_from_array = hasattr(self.gc,
                                                     'write_barrier_from_array')
 
@@ -32,6 +34,7 @@
                                                self.llinterp)
         self.get_type_id = layoutbuilder.get_type_id
         gcdata = layoutbuilder.initialize_gc_query_function(self.gc)
+        gcdata.init_finalizer_trigger(self.finalizer_trigger)
 
         constants = collect_constants(flowgraphs)
         for obj in constants:
@@ -189,18 +192,38 @@
     def thread_run(self):
         pass
 
+    def finalizer_trigger(self, fq_index):
+        fq = self.finalizer_queues[fq_index]
+        graph = self.translator._graphof(fq.finalizer_trigger.im_func)
+        try:
+            self.llinterp.eval_graph(graph, [None], recursive=True)
+        except llinterp.LLException:
+            raise RuntimeError(
+                "finalizer_trigger() raised an exception, shouldn't happen")
+
     def get_finalizer_queue_index(self, fq_tag):
         assert fq_tag.expr == 'FinalizerQueue TAG'
         fq = fq_tag.default
-        return self.finalizer_queues.setdefault(fq, len(self.finalizer_queues))
+        try:
+            index = self.finalizer_queue_indexes[fq]
+        except KeyError:
+            index = len(self.finalizer_queue_indexes)
+            assert index == len(self.finalizer_queues)
+            self.finalizer_queue_indexes[fq] = index
+            self.finalizer_queues.append(fq)
+        return (fq, index)
 
     def gc_fq_next_dead(self, fq_tag):
-        index = self.get_finalizer_queue_index(fq_tag)
-        xxx
+        fq, _ = self.get_finalizer_queue_index(fq_tag)
+        addr = fq.next_dead()
+        if addr is None:
+            addr = llmemory.NULL
+        return llmemory.cast_adr_to_ptr(addr, rclass.OBJECTPTR)
 
     def gc_fq_register(self, fq_tag, ptr):
-        index = self.get_finalizer_queue_index(fq_tag)
+        fq, index = self.get_finalizer_queue_index(fq_tag)
         ptr = lltype.cast_opaque_ptr(llmemory.GCREF, ptr)
+        self.gc.register_finalizer_index(fq, index)
         self.gc.register_finalizer(index, ptr)
 
 # ____________________________________________________________
diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -390,7 +390,8 @@
             from rpython.rtyper.lltypesystem.lloperation import llop
             from rpython.rtyper.rclass import OBJECTPTR
             from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance
-            ptr = llop.gc_fq_next_dead(OBJECTPTR, self._get_tag())
+            tag = FinalizerQueue._get_tag(self)
+            ptr = llop.gc_fq_next_dead(OBJECTPTR, tag)
             return cast_base_ptr_to_instance(self.Class, ptr)
         try:
             return self._queue.popleft()
@@ -404,24 +405,27 @@
             from rpython.rtyper.lltypesystem.lloperation import llop
             from rpython.rtyper.rclass import OBJECTPTR
             from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr
+            tag = FinalizerQueue._get_tag(self)
             ptr = cast_instance_to_base_ptr(obj)
-            llop.gc_fq_register(lltype.Void, self._get_tag(), ptr)
+            llop.gc_fq_register(lltype.Void, tag, ptr)
             return
         else:
             self._untranslated_register_finalizer(obj)
 
-    @specialize.memo()
     def _get_tag(self):
-        return CDefinedIntSymbolic('FinalizerQueue TAG', default=self)
+        "NOT_RPYTHON: special-cased below"
+
+    def _reset(self):
+        import collections
+        self._weakrefs = set()
+        self._queue = collections.deque()
 
     def _untranslated_register_finalizer(self, obj):
         if hasattr(obj, '__enable_del_for_id'):
             return    # already called
 
         if not hasattr(self, '_queue'):
-            import collections
-            self._weakrefs = set()
-            self._queue = collections.deque()
+            self._reset()
 
         # Fetch and check the type of 'obj'
         objtyp = obj.__class__
@@ -483,6 +487,23 @@
 
 _fq_patched_classes = set()
 
+class FqTagEntry(ExtRegistryEntry):
+    _about_ = FinalizerQueue._get_tag.im_func
+
+    def compute_result_annotation(self, s_fq):
+        assert s_fq.is_constant()
+        fq = s_fq.const
+        s_func = self.bookkeeper.immutablevalue(fq.finalizer_trigger)
+        self.bookkeeper.emulate_pbc_call(self.bookkeeper.position_key,
+                                         s_func, [])
+        if not hasattr(fq, '_fq_tag'):
+            fq._fq_tag = CDefinedIntSymbolic('FinalizerQueue TAG', default=fq)
+        return self.bookkeeper.immutablevalue(fq._fq_tag)
+
+    def specialize_call(self, hop):
+        hop.exception_cannot_occur()
+        return hop.inputconst(lltype.Signed, hop.s_result.const)
+
 
 # ____________________________________________________________
 


More information about the pypy-commit mailing list