[pypy-svn] r47357 - in pypy/dist/pypy/rpython: . lltypesystem memory memory/test

cfbolz at codespeak.net cfbolz at codespeak.net
Tue Oct 9 18:31:53 CEST 2007


Author: cfbolz
Date: Tue Oct  9 18:31:52 2007
New Revision: 47357

Modified:
   pypy/dist/pypy/rpython/llinterp.py
   pypy/dist/pypy/rpython/lltypesystem/llheap.py
   pypy/dist/pypy/rpython/memory/gc.py
   pypy/dist/pypy/rpython/memory/gcwrapper.py
   pypy/dist/pypy/rpython/memory/test/test_gc.py
Log:
attempt to implement weakrefs with the semispace GC. does not work completely
yet, but some tests are passing.


Modified: pypy/dist/pypy/rpython/llinterp.py
==============================================================================
--- pypy/dist/pypy/rpython/llinterp.py	(original)
+++ pypy/dist/pypy/rpython/llinterp.py	Tue Oct  9 18:31:52 2007
@@ -723,10 +723,10 @@
     op_weakref_deref.need_result_type = True
 
     def op_cast_ptr_to_weakrefptr(self, obj):
-        return self.heap.cast_ptr_to_weakrefptr(obj)
+        return llmemory.cast_ptr_to_weakrefptr(obj)
 
     def op_cast_weakrefptr_to_ptr(self, PTRTYPE, obj):
-        return self.heap.cast_weakrefptr_to_ptr(PTRTYPE, obj)
+        return llmemory.cast_weakrefptr_to_ptr(PTRTYPE, obj)
     op_cast_weakrefptr_to_ptr.need_result_type = True
 
     def op_gc__collect(self):
@@ -1236,12 +1236,26 @@
         if index != 0:
             raise IndexError("address of local vars only support [0] indexing")
         p = self.frame.getval(self.v)
-        return llmemory.cast_ptr_to_adr(p)
+        result = llmemory.cast_ptr_to_adr(p)
+        # the GC should never see instances of _gctransformed_wref
+        result = self.unwrap_possible_weakref(result)
+        return result
     def __setitem__(self, index, newvalue):
         if index != 0:
             raise IndexError("address of local vars only support [0] indexing")
-        p = llmemory.cast_adr_to_ptr(newvalue, self.v.concretetype)
+        if self.v.concretetype == llmemory.WeakRefPtr:
+            # fish some more
+            assert isinstance(newvalue, llmemory.fakeaddress)
+            p = llmemory.cast_ptr_to_weakrefptr(newvalue.ptr)
+        else:
+            p = llmemory.cast_adr_to_ptr(newvalue, self.v.concretetype)
         self.frame.setvar(self.v, p)
+    def unwrap_possible_weakref(self, addr):
+        # fish fish fish
+        if isinstance(addr.ptr._obj, llmemory._gctransformed_wref):
+            return llmemory.fakeaddress(addr.ptr._obj._ptr)
+        return addr
+
 
 # by default we route all logging messages to nothingness
 # e.g. tests can then switch on logging to get more help

Modified: pypy/dist/pypy/rpython/lltypesystem/llheap.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/llheap.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/llheap.py	Tue Oct  9 18:31:52 2007
@@ -4,8 +4,7 @@
 from pypy.rpython.lltypesystem.llmemory import raw_malloc, raw_free
 from pypy.rpython.lltypesystem.llmemory import raw_memclear, raw_memcopy
 from pypy.rpython.lltypesystem.llmemory import raw_malloc_usage, \
-    weakref_create, weakref_deref, cast_weakrefptr_to_ptr, \
-    cast_ptr_to_weakrefptr
+    weakref_create, weakref_deref
 
 setfield = setattr
 from operator import setitem as setarrayitem

Modified: pypy/dist/pypy/rpython/memory/gc.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc.py	(original)
+++ pypy/dist/pypy/rpython/memory/gc.py	Tue Oct  9 18:31:52 2007
@@ -56,7 +56,14 @@
         """
         size = self.fixed_size(typeid)
         needs_finalizer = bool(self.getfinalizer(typeid))
-        contains_weakptr = self.weakpointer_offset(typeid) != -1
+        weakptr_offset = self.weakpointer_offset(typeid)
+        #XXX cannot compare weakptr_offset with -1
+        #contains_weakptr = weakpointer_offset. != -1
+        if isinstance(weakptr_offset, int):
+            assert weakptr_offset == -1
+            contains_weakptr = False
+        else:
+            contains_weakptr = True
         assert not (needs_finalizer and contains_weakptr)
         if self.is_varsize(typeid):
             assert not contains_weakptr
@@ -966,11 +973,10 @@
         self.free = self.tospace
         self.objects_with_finalizers = self.AddressLinkedList()
         self.run_finalizers = self.AddressLinkedList()
+        self.objects_with_weakrefs = self.AddressLinkedList()
 
     def malloc_fixedsize(self, typeid, size, can_collect, has_finalizer=False,
                          contains_weakptr=False):
-        if contains_weakptr:
-            raise NotImplementedError("weakptr in SemiSpaceGC")
         size_gc_header = self.gcheaderbuilder.size_gc_header
         totalsize = size_gc_header + size
         if raw_malloc_usage(totalsize) > self.top_of_space - self.free:
@@ -987,12 +993,12 @@
         self.free += totalsize
         if has_finalizer:
             self.objects_with_finalizers.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)
 
     def malloc_varsize(self, typeid, length, size, itemsize, offset_to_length,
                        can_collect, has_finalizer=False):
-        if has_finalizer:
-            raise NotImplementedError("finalizers in SemiSpaceGC")
         size_gc_header = self.gcheaderbuilder.size_gc_header
         nonvarsize = size_gc_header + size
         try:
@@ -1037,6 +1043,25 @@
             root.address[0] = self.copy(root.address[0])
         free_non_gc_object(roots)
         scan = self.scan_copied(scan)
+        # walk over list of objects that contain weakrefs
+        # if the object it references survives and invalidate it otherwise
+        new_with_weakref = self.AddressLinkedList()
+        while self.objects_with_weakrefs.non_empty():
+            obj = self.objects_with_weakrefs.pop()
+            if not self.is_forwarded(obj):
+                continue # weakref itself dies
+            obj = self.get_forwarding_address(obj)
+            offset = self.weakpointer_offset(self.header(obj).typeid)
+            pointing_to = (obj + offset).address[0]
+            if pointing_to:
+                if self.is_forwarded(pointing_to):
+                    (obj + offset).address[0] = self.get_forwarding_address(
+                        pointing_to)
+                else:
+                    (obj + offset).address[0] = NULL
+            new_with_weakref.append(obj)
+        self.objects_with_weakrefs.delete()
+        self.objects_with_weakrefs = new_with_weakref
         # walk over list of objects with finalizers
         # if it is not copied, add it to the list of to-be-called finalizers
         # and copy it, to me make the finalizer runnable

Modified: pypy/dist/pypy/rpython/memory/gcwrapper.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gcwrapper.py	(original)
+++ pypy/dist/pypy/rpython/memory/gcwrapper.py	Tue Oct  9 18:31:52 2007
@@ -67,6 +67,17 @@
     def collect(self):
         self.gc.collect()
 
+    def weakref_create(self, obj):
+        type_id = self.get_type_id(gctypelayout.WEAKREF)
+        addr = self.gc.malloc(type_id, None, zero=False)
+        result = llmemory.cast_adr_to_ptr(addr, gctypelayout.WEAKREFPTR)
+        result.weakptr = llmemory.cast_ptr_to_adr(obj)
+        return llmemory.cast_ptr_to_weakrefptr(result)
+    
+    def weakref_deref(self, PTRTYPE, obj):
+        addr = gctypelayout.ll_weakref_deref(obj)
+        return llmemory.cast_adr_to_ptr(addr, PTRTYPE)
+
     # ____________________________________________________________
 
 
@@ -89,11 +100,15 @@
 
         assert not type_contains_pyobjs(TYPE), "not implemented"
         def ll_finalizer(addr):
+            old_active_frame = self.llinterp.active_frame
             try:
                 v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG)
                 self.llinterp.eval_graph(destrgraph, [v])
             except llinterp.LLException:
-                print "a destructor raised an exception, ignoring it"
+                raise RuntimeError(
+                    "a finalizer raised an exception, shouldn't happen")
+            finally:
+                self.llinterp.active_frame = old_active_frame
         return ll_finalizer
 
 

Modified: pypy/dist/pypy/rpython/memory/test/test_gc.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/test/test_gc.py	(original)
+++ pypy/dist/pypy/rpython/memory/test/test_gc.py	Tue Oct  9 18:31:52 2007
@@ -183,6 +183,46 @@
         res = self.interpret(f, [5])
         assert 160 <= res <= 165
 
+    def test_weakref(self):
+        import weakref, gc
+        class A(object):
+            pass
+        def g():
+            a = A()
+            return weakref.ref(a)
+        def f():
+            a = A()
+            ref = weakref.ref(a)
+            result = ref() is a
+            ref = g()
+            llop.gc__collect(lltype.Void)
+            result = result and (ref() is None)
+            # check that a further collection is fine
+            llop.gc__collect(lltype.Void)
+            result = result and (ref() is None)
+            return result
+        res = self.interpret(f, [])
+        assert res
+
+    def test_weakref_to_object_with_finalizer(self):
+        import weakref, gc
+        class A(object):
+            count = 0
+        a = A()
+        class B(object):
+            def __del__(self):
+                a.count += 1
+        def g():
+            b = 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
+        res = self.interpret(f, [])
+        assert res
 
 class TestMarkSweepGC(GCTest):
     from pypy.rpython.memory.gc import MarkSweepGC as GCClass



More information about the Pypy-commit mailing list