Commits

Maciej Fijalkowski  committed 78904ea

chained objects unallowed

  • Participants
  • Parent commits f53ec1d
  • Branches lightweight-finalizers

Comments (0)

Files changed (6)

File pypy/rpython/memory/gc/base.py

     def set_query_functions(self, is_varsize, has_gcptr_in_varsize,
                             is_gcarrayofgcptr,
                             getfinalizer,
+                            getlightfinalizer,
                             offsets_to_gc_pointers,
                             fixed_size, varsize_item_sizes,
                             varsize_offset_to_variable_part,
                             get_custom_trace,
                             fast_path_tracing):
         self.getfinalizer = getfinalizer
+        self.getlightfinalizer = getlightfinalizer
         self.is_varsize = is_varsize
         self.has_gcptr_in_varsize = has_gcptr_in_varsize
         self.is_gcarrayofgcptr = is_gcarrayofgcptr
 
         size = self.fixed_size(typeid)
         needs_finalizer = bool(self.getfinalizer(typeid))
+        finalizer_is_light = bool(self.getlightfinalizer(typeid))
         contains_weakptr = self.weakpointer_offset(typeid) >= 0
         assert not (needs_finalizer and contains_weakptr)
         if self.is_varsize(typeid):
             else:
                 malloc_fixedsize = self.malloc_fixedsize
             ref = malloc_fixedsize(typeid, size, needs_finalizer,
+                                   finalizer_is_light,
                                    contains_weakptr)
         # lots of cast and reverse-cast around...
         return llmemory.cast_ptr_to_adr(ref)

File pypy/rpython/memory/gc/semispace.py

         self.free = self.tospace
         MovingGCBase.setup(self)
         self.objects_with_finalizers = self.AddressDeque()
-        self.objects_with_raw_mem = self.AddressStack()
+        self.objects_with_light_finalizers = self.AddressStack()
         self.objects_with_weakrefs = self.AddressStack()
 
     def _teardown(self):
     # because the spaces are filled with zeroes in advance.
 
     def malloc_fixedsize_clear(self, typeid16, size,
-                               has_finalizer=False, contains_weakptr=False):
+                               has_finalizer=False,
+                               has_light_finalizer=False,
+                               contains_weakptr=False):
         size_gc_header = self.gcheaderbuilder.size_gc_header
         totalsize = size_gc_header + size
         result = self.free
         llarena.arena_reserve(result, totalsize)
         self.init_gc_object(result, typeid16)
         self.free = result + totalsize
-        if has_finalizer:
+        if has_light_finalizer:
+            self.objects_with_light_finalizers.append(result + size_gc_header)
+        elif has_finalizer:
             self.objects_with_finalizers.append(result + size_gc_header)
-        if self.has_raw_mem_ptr(typeid16):
-            self.objects_with_raw_mem.append(result + size_gc_header)
         if contains_weakptr:
             self.objects_with_weakrefs.append(result + size_gc_header)
         return llmemory.cast_adr_to_ptr(result+size_gc_header, llmemory.GCREF)
         if self.run_finalizers.non_empty():
             self.update_run_finalizers()
         scan = self.scan_copied(scan)
+        if self.objects_with_light_finalizers.non_empty():
+            self.deal_with_objects_with_light_finalizers()
         if self.objects_with_finalizers.non_empty():
             scan = self.deal_with_objects_with_finalizers(scan)
-        if self.objects_with_raw_mem.non_empty():
-            self.deal_with_objects_with_raw_mem()
         if self.objects_with_weakrefs.non_empty():
             self.invalidate_weakrefs()
         self.update_objects_with_id()
         # immortal objects always have GCFLAG_FORWARDED set;
         # see get_forwarding_address().
 
+    def deal_with_objects_with_light_finalizers(self):
+        """ This is a much simpler version of dealing with finalizers
+        and an optimization - we can reasonably assume that those finalizers
+        don't do anything fancy and *just* call them. Among other things
+        they won't resurrect objects
+        """
+        xxx
+
     def deal_with_objects_with_finalizers(self, scan):
         # walk over list of objects with finalizers
         # if it is not copied, add it to the list of to-be-called finalizers
         self.objects_with_finalizers = new_with_finalizer
         return scan
 
-    def deal_with_objects_with_raw_mem(self):
-        new_with_raw_mem = self.AddressStack()
-        while self.objects_with_raw_mem.non_empty():
-            addr = self.objects_with_raw_mem.pop()
-            if self.surviving(addr):
-                new_with_raw_mem.append(self.get_forwarding_address(addr))
-            else:
-                self._free_raw_mem_from(addr)
-        self.objects_with_raw_mem = new_with_raw_mem
-
-
     def _append_if_nonnull(pointer, stack):
         stack.append(pointer.address[0])
     _append_if_nonnull = staticmethod(_append_if_nonnull)

File pypy/rpython/memory/gctransform/framework.py

             [s_gc, s_typeid16,
              annmodel.SomeInteger(nonneg=True),
              annmodel.SomeBool(),
+             annmodel.SomeBool(),
              annmodel.SomeBool()], s_gcref,
             inline = False)
         if hasattr(GCClass, 'malloc_fixedsize'):

File pypy/rpython/memory/gctypelayout.py

         else:
             return lltype.nullptr(GCData.FINALIZER_OR_CT_FUNC)
 
+    def q_light_finalizer(self, typeid):
+        typeinfo = self.get(typeid)
+        if typeinfo.infobits & T_HAS_LIGHTWEIGHT_FINALIZER:
+            return typeinfo.finalizer_or_customtrace
+        else:
+            return lltype.nullptr(GCData.FINALIZER_OR_CT_FUNC)        
+
     def q_offsets_to_gc_pointers(self, typeid):
         return self.get(typeid).ofstoptrs
 
             self.q_has_gcptr_in_varsize,
             self.q_is_gcarrayofgcptr,
             self.q_finalizer,
+            self.q_light_finalizer,
             self.q_offsets_to_gc_pointers,
             self.q_fixed_size,
             self.q_varsize_item_sizes,

File pypy/translator/backendopt/finalizer.py

     * anything that escapes self
     * anything that can allocate
     """
-    ok_operations = ['getfield', 'ptr_nonzero', 'free', 'same_as',
+    ok_operations = ['ptr_nonzero', 'free', 'same_as',
                      'direct_ptradd', 'force_cast', 'cast_primitive',
                      'cast_pointer']
     
             if not isinstance(TP, lltype.Ptr) or TP.TO._gckind == 'raw':
                 # primitive type
                 return self.bottom_result()
+        if op.opname == 'getfield':
+            TP = op.result.concretetype
+            if not isinstance(TP, lltype.Ptr) or TP.TO._gckind == 'raw':
+                # primitive type
+                return self.bottom_result()            
         return self.top_result()

File pypy/translator/backendopt/test/test_finalizer.py

         r = self.analyze(g, [], f, backendopt=True)
         assert not r
 
+    def test_chain(self):
+        class B(object):
+            def __init__(self):
+                self.counter = 1
+        
+        class A(object):
+            def __init__(self):
+                self.x = B()
+
+            def __del__(self):
+                self.x.counter += 1
+
+        def f():
+            A()
+
+        r = self.analyze(f, [], A.__del__.im_func)
+        assert r
+
     def test_os_call(self):
         py.test.skip("can allocate OSError, but also can raise, ignore for now")
         import os