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

mwh at codespeak.net mwh at codespeak.net
Sat May 20 17:07:17 CEST 2006


Author: mwh
Date: Sat May 20 17:07:15 2006
New Revision: 27509

Modified:
   pypy/dist/pypy/rpython/memory/gc.py
   pypy/dist/pypy/rpython/memory/gctransform.py
   pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py
Log:
a rather cheating implementation of x_become, basically copying collect() and
adding a couple of choice lines.

however it fails, in a way that doesn't seem to make much sense, even if you
make the body of x_become() exactly like that of collect() -- it seems the
frame chains get corrupted or something :(


Modified: pypy/dist/pypy/rpython/memory/gc.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc.py	(original)
+++ pypy/dist/pypy/rpython/memory/gc.py	Sat May 20 17:07:15 2006
@@ -456,7 +456,146 @@
         clonedata.pool = self.x_swap_pool(curpool)
 
     def x_become(self, target_addr, source_addr):
-        pass
+        # become is implemented very very much like collect currently...
+        import os, time
+        if DEBUG_PRINT:
+            os.write(2, 'becoming...\n')
+        start_time = time.time()
+        roots = self.get_roots()
+        size_gc_header = self.gcheaderbuilder.size_gc_header
+        objects = self.AddressLinkedList()
+        while 1:
+            curr = roots.pop()
+##             print "root: ", curr
+            if curr == NULL:
+                break
+            # roots is a list of addresses to addresses:
+            # -------------------------------------------------
+            # begin difference from collect
+            if curr.address[0] == target_addr:
+                raise RuntimeError("can't replace a root")
+            # end difference from collect
+            # -------------------------------------------------
+            objects.append(curr.address[0])
+            # the last sweep did not clear the mark bit of static roots, 
+            # since they are not in the malloced_objects list
+            gc_info = curr.address[0] - size_gc_header
+            hdr = llmemory.cast_adr_to_ptr(gc_info, self.HDRPTR)
+            hdr.typeid = hdr.typeid & (~1)
+        free_non_gc_object(roots)
+        # from this point onwards, no more mallocs should be possible
+        old_malloced = self.bytes_malloced
+        self.bytes_malloced = 0
+        while objects.non_empty():  #mark
+            curr = objects.pop()
+##             print "object: ", curr
+            gc_info = curr - size_gc_header
+            hdr = llmemory.cast_adr_to_ptr(gc_info, self.HDRPTR)
+            if hdr.typeid & 1:
+                continue
+            typeid = hdr.typeid >> 1
+            offsets = self.offsets_to_gc_pointers(typeid)
+            i = 0
+            while i < len(offsets):
+                pointer = curr + offsets[i]
+                objects.append(pointer.address[0])
+                # -------------------------------------------------
+                # begin difference from collect
+                if pointer.address[0] == target_addr:
+                    pointer.address[0] == source_addr
+                # end difference from collect
+                # -------------------------------------------------
+                i += 1
+            if self.is_varsize(typeid):
+                offset = self.varsize_offset_to_variable_part(
+                    typeid)
+                length = (curr + self.varsize_offset_to_length(typeid)).signed[0]
+                curr += offset
+                offsets = self.varsize_offsets_to_gcpointers_in_var_part(typeid)
+                itemlength = self.varsize_item_sizes(typeid)
+                i = 0
+                while i < length:
+                    item = curr + itemlength * i
+                    j = 0
+                    while j < len(offsets):
+                        objects.append((item + offsets[j]).address[0])
+                        # -------------------------------------------------
+                        # begin difference from collect
+                        pointer = item + offsets[j]
+                        if pointer.address[0] == target_addr:
+                            pointer.address[0] == source_addr
+                        ## end difference from collect
+                        # -------------------------------------------------
+                        j += 1
+                    i += 1
+            hdr.typeid = hdr.typeid | 1
+        objects.delete()
+        # also mark self.curpool
+        if self.curpool:
+            gc_info = llmemory.cast_ptr_to_adr(self.curpool) - size_gc_header
+            hdr = llmemory.cast_adr_to_ptr(gc_info, self.HDRPTR)
+            hdr.typeid = hdr.typeid | 1
+
+        curr_heap_size = 0
+        freed_size = 0
+        firstpoolnode = lltype.malloc(self.POOLNODE, flavor='raw')
+        firstpoolnode.linkedlist = self.malloced_objects
+        firstpoolnode.nextnode = self.poolnodes
+        prevpoolnode = lltype.nullptr(self.POOLNODE)
+        poolnode = firstpoolnode
+        while poolnode:   #sweep
+            ppnext = lltype.direct_fieldptr(poolnode, 'linkedlist')
+            hdr = poolnode.linkedlist
+            while hdr:  #sweep
+                typeid = hdr.typeid >> 1
+                next = hdr.next
+                addr = llmemory.cast_ptr_to_adr(hdr)
+                size = self.fixed_size(typeid)
+                if self.is_varsize(typeid):
+                    length = (addr + size_gc_header + self.varsize_offset_to_length(typeid)).signed[0]
+                    size += self.varsize_item_sizes(typeid) * length
+                estimate = raw_malloc_usage(size_gc_header + size)
+                if hdr.typeid & 1:
+                    hdr.typeid = hdr.typeid & (~1)
+                    ppnext[0] = hdr
+                    ppnext = lltype.direct_fieldptr(hdr, 'next')
+                    curr_heap_size += estimate
+                else:
+                    freed_size += estimate
+                    raw_free(addr)
+                hdr = next
+            ppnext[0] = lltype.nullptr(self.HDR)
+            next = poolnode.nextnode
+            if not poolnode.linkedlist and prevpoolnode:
+                # completely empty node
+                prevpoolnode.nextnode = next
+                lltype.free(poolnode, flavor='raw')
+            else:
+                prevpoolnode = poolnode
+            poolnode = next
+        self.malloced_objects = firstpoolnode.linkedlist
+        self.poolnodes = firstpoolnode.nextnode
+        lltype.free(firstpoolnode, flavor='raw')
+
+        if curr_heap_size > self.bytes_malloced_threshold:
+            self.bytes_malloced_threshold = curr_heap_size
+        end_time = time.time()
+        self.total_collection_time += end_time - start_time
+        # warning, the following debug prints allocate memory to manipulate
+        # the strings!  so they must be at the end
+        if DEBUG_PRINT:
+            os.write(2, "  malloced since previous collection: %s bytes\n" %
+                     old_malloced)
+            os.write(2, "  heap usage at start of collection:  %s bytes\n" %
+                     (self.heap_usage + old_malloced))
+            os.write(2, "  freed:                              %s bytes\n" %
+                     freed_size)
+            os.write(2, "  new heap usage:                     %s bytes\n" %
+                     curr_heap_size)
+            os.write(2, "  total time spent collecting:        %s seconds\n" %
+                     self.total_collection_time)
+        assert self.heap_usage + old_malloced == curr_heap_size + freed_size
+        self.heap_usage = curr_heap_size
 
 class SemiSpaceGC(GCBase):
     _alloc_flavor_ = "raw"

Modified: pypy/dist/pypy/rpython/memory/gctransform.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform.py	(original)
+++ pypy/dist/pypy/rpython/memory/gctransform.py	Sat May 20 17:07:15 2006
@@ -1197,7 +1197,9 @@
                                [self.x_become_ptr, self.c_const_gc,
                                 v_target, v_source],
                                op.result)
-        return [newop]
+        ops, index = self.protect_roots(newop, livevars, block,
+                                        block.operations.index(op))
+        return ops
 
     def push_alive_nopyobj(self, var):
         return []

Modified: pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py	(original)
+++ pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py	Sat May 20 17:07:15 2006
@@ -335,6 +335,7 @@
             GC_PARAMS = {'start_heap_size': 4096 }
 
     def test_x_become(self):
+        py.test.skip('fails mysteriously')
         S = lltype.GcStruct("S", ('x', lltype.Signed))
         def f():
             x = lltype.malloc(S)
@@ -342,6 +343,7 @@
             y = lltype.malloc(S)
             y.x = 20
             z = x
+            #llop.gc__collect(lltype.Void)
             llop.gc_x_become(lltype.Void,
                              llmemory.cast_ptr_to_adr(x),
                              llmemory.cast_ptr_to_adr(y))
@@ -349,7 +351,7 @@
         run = self.runner(f)
         res = run([])
         # not implemented yet!
-        #assert res == 20 
+        assert res == 20 
 
     def test_tree_cloning(self):
         py.test.skip("aaaaaaaaaaaaaaaaaaaaaaargh later")



More information about the Pypy-commit mailing list