[pypy-svn] r58811 - in pypy/dist/pypy: config rpython rpython/lltypesystem rpython/lltypesystem/test rpython/memory/gc rpython/memory/gc/test rpython/memory/test translator/c/src translator/c/test

arigo at codespeak.net arigo at codespeak.net
Wed Oct 8 14:10:37 CEST 2008


Author: arigo
Date: Wed Oct  8 14:10:36 2008
New Revision: 58811

Added:
   pypy/dist/pypy/rpython/memory/gc/markcompact.py
      - copied unchanged from r58809, pypy/branch/gc-experiments/pypy/rpython/memory/gc/markcompact.py
Modified:
   pypy/dist/pypy/config/translationoption.py
   pypy/dist/pypy/rpython/llinterp.py
   pypy/dist/pypy/rpython/lltypesystem/llarena.py
   pypy/dist/pypy/rpython/lltypesystem/llmemory.py
   pypy/dist/pypy/rpython/lltypesystem/lloperation.py
   pypy/dist/pypy/rpython/lltypesystem/test/test_llarena.py
   pypy/dist/pypy/rpython/lltypesystem/test/test_llmemory.py
   pypy/dist/pypy/rpython/memory/gc/base.py
   pypy/dist/pypy/rpython/memory/gc/hybrid.py
   pypy/dist/pypy/rpython/memory/gc/marksweep.py
   pypy/dist/pypy/rpython/memory/gc/semispace.py
   pypy/dist/pypy/rpython/memory/gc/test/test_direct.py
   pypy/dist/pypy/rpython/memory/test/test_gc.py
   pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py
   pypy/dist/pypy/translator/c/src/mem.h
   pypy/dist/pypy/translator/c/test/test_lladdresses.py
   pypy/dist/pypy/translator/c/test/test_newgc.py
Log:
(fijal, arigo)

Merge the gc-experiments branch, adding the markcompact gc.

svn merge svn+ssh://codespeak.net/svn/pypy/dist@58225 \
          svn+ssh://codespeak.net/svn/pypy/branch/gc-experiments


Modified: pypy/dist/pypy/config/translationoption.py
==============================================================================
--- pypy/dist/pypy/config/translationoption.py	(original)
+++ pypy/dist/pypy/config/translationoption.py	Wed Oct  8 14:10:36 2008
@@ -45,7 +45,7 @@
     # gc
     ChoiceOption("gc", "Garbage Collection Strategy",
                  ["boehm", "ref", "marksweep", "semispace", "statistics",
-                  "generation", "hybrid", "none"],
+                  "generation", "hybrid", "markcompact", "none"],
                   "ref", requires={
                      "ref": [("translation.rweakref", False), # XXX
                              ("translation.gctransformer", "ref")],
@@ -57,6 +57,7 @@
                      "generation": [("translation.gctransformer", "framework")],
                      "hybrid": [("translation.gctransformer", "framework")],
                      "boehm": [("translation.gctransformer", "boehm")],
+                     "markcompact": [("translation.gctransformer", "framework")],
                      },
                   cmdline="--gc"),
     ChoiceOption("gctransformer", "GC transformer that is used - internal",
@@ -299,7 +300,7 @@
     '0':    'boehm       nobackendopt',
     '1':    'boehm       lowinline',
     'size': 'boehm       lowinline     remove_asserts',
-    'mem':  'generation  lowinline     remove_asserts',
+    'mem':  'markcompact lowinline     remove_asserts',
     '2':    'hybrid      extraopts',
     '3':    'hybrid      extraopts     remove_asserts',
     }

Modified: pypy/dist/pypy/rpython/llinterp.py
==============================================================================
--- pypy/dist/pypy/rpython/llinterp.py	(original)
+++ pypy/dist/pypy/rpython/llinterp.py	Wed Oct  8 14:10:36 2008
@@ -895,6 +895,8 @@
         checkadr(toaddr)
         llmemory.raw_memcopy(fromaddr, toaddr, size)
 
+    op_raw_memmove = op_raw_memcopy # this is essentially the same here
+
     def op_raw_load(self, addr, typ, offset):
         checkadr(addr)
         value = getattr(addr, str(typ).lower())[offset]

Modified: pypy/dist/pypy/rpython/lltypesystem/llarena.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/llarena.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/llarena.py	Wed Oct  8 14:10:36 2008
@@ -264,6 +264,9 @@
 # work with fakearenaaddresses on which arbitrary arithmetic is
 # possible even on top of the llinterpreter.
 
+# arena_new_view(ptr) is a no-op when translated, returns fresh view
+# on previous arena when run on top of llinterp
+
 def arena_malloc(nbytes, zero):
     """Allocate and return a new arena, optionally zero-initialized."""
     return Arena(nbytes, zero).getaddr(0)
@@ -299,6 +302,11 @@
     following an object.  For arenas containing heterogenous objects."""
     return RoundedUpForAllocation(size)
 
+def arena_new_view(ptr):
+    """Return a fresh memory view on an arena
+    """
+    return Arena(ptr.arena.nbytes, False).getaddr(0)
+
 # ____________________________________________________________
 #
 # Translation support: the functions above turn into the code below.
@@ -399,3 +407,9 @@
                   llimpl=llimpl_round_up_for_allocation,
                   llfakeimpl=round_up_for_allocation,
                   sandboxsafe=True)
+
+def llimpl_arena_new_view(addr):
+    return addr
+register_external(arena_new_view, [llmemory.Address], llmemory.Address,
+                  'll_arena.arena_new_view', llimpl=llimpl_arena_new_view,
+                  llfakeimpl=arena_new_view, sandboxsafe=True)

Modified: pypy/dist/pypy/rpython/lltypesystem/llmemory.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/llmemory.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/llmemory.py	Wed Oct  8 14:10:36 2008
@@ -736,6 +736,12 @@
     assert lltype.typeOf(dest)   == Address
     size.raw_memcopy(source, dest)
 
+def raw_memmove(source, dest, size):
+    # for now let's assume that raw_memmove is the same as raw_memcopy,
+    # when run on top of fake addresses, but we _free the source object
+    raw_memcopy(source, dest, size)
+    source.ptr._as_obj()._free()
+
 def cast_any_ptr(EXPECTED_TYPE, ptr):
     # this is a generalization of the various cast_xxx_ptr() functions.
     PTRTYPE = lltype.typeOf(ptr)
@@ -785,3 +791,19 @@
                 setattr(dest._obj, name, llvalue)
     else:
         raise TypeError(T)
+
+from pypy.rpython.extregistry import ExtRegistryEntry
+
+class RawMemmoveEntry(ExtRegistryEntry):
+    _about_ = raw_memmove
+
+    def compute_result_annotation(self, s_from, s_to, s_size):
+        from pypy.annotation.model import SomeAddress, SomeInteger
+        assert isinstance(s_from, SomeAddress)
+        assert isinstance(s_to, SomeAddress)
+        assert isinstance(s_size, SomeInteger)
+    
+    def specialize_call(self, hop):
+        hop.exception_cannot_occur()
+        v_list = hop.inputargs(Address, Address, lltype.Signed)
+        return hop.genop('raw_memmove', v_list)

Modified: pypy/dist/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lloperation.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/lloperation.py	Wed Oct  8 14:10:36 2008
@@ -368,6 +368,7 @@
     'raw_free':             LLOp(),
     'raw_memclear':         LLOp(),
     'raw_memcopy':          LLOp(),
+    'raw_memmove':          LLOp(),
     'raw_load':             LLOp(sideeffects=False),
     'raw_store':            LLOp(),
     'stack_malloc':         LLOp(), # mmh

Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_llarena.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/test/test_llarena.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/test/test_llarena.py	Wed Oct  8 14:10:36 2008
@@ -4,7 +4,7 @@
 from pypy.rpython.lltypesystem.llarena import arena_malloc, arena_reset
 from pypy.rpython.lltypesystem.llarena import arena_reserve, arena_free
 from pypy.rpython.lltypesystem.llarena import round_up_for_allocation
-from pypy.rpython.lltypesystem.llarena import ArenaError
+from pypy.rpython.lltypesystem.llarena import ArenaError, arena_new_view
 
 def test_arena():
     S = lltype.Struct('S', ('x',lltype.Signed))
@@ -150,6 +150,13 @@
     arena_free(a)
     return 42
 
+def test_arena_new_view():
+    a = arena_malloc(50, False)
+    arena_reserve(a, precomputed_size)
+    # we can now allocate the same space in new view
+    b = arena_new_view(a)
+    arena_reserve(b, precomputed_size)
+
 def test_partial_arena_reset():
     a = arena_malloc(50, False)
     def reserve(i):

Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_llmemory.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/test/test_llmemory.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/test/test_llmemory.py	Wed Oct  8 14:10:36 2008
@@ -504,6 +504,18 @@
     raw_memcopy(at1, at2, sizeof(T))
     assert t2.x == 1
 
+def test_raw_memmove():
+    T = lltype.GcStruct('T', ('x', lltype.Signed))
+    t1 = lltype.malloc(T)
+    t2 = lltype.malloc(T)
+    t1.x = 1
+    t2.x = 2
+    at1 = cast_ptr_to_adr(t1)
+    at2 = cast_ptr_to_adr(t2)
+    raw_memmove(at1, at2, sizeof(T))
+    assert t2.x == 1
+    py.test.raises(RuntimeError, "t1.x")
+
 def test_raw_memcopy_nonrec():
     T = lltype.GcStruct('T', ('x', lltype.Signed))
     A = lltype.FixedSizeArray(lltype.Ptr(T), 1)

Modified: pypy/dist/pypy/rpython/memory/gc/base.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc/base.py	(original)
+++ pypy/dist/pypy/rpython/memory/gc/base.py	Wed Oct  8 14:10:36 2008
@@ -1,5 +1,10 @@
-from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.lltypesystem import lltype, llmemory, llarena
 from pypy.rlib.debug import ll_assert
+from pypy.rpython.memory.gcheader import GCHeaderBuilder
+from pypy.rpython.memory.support import DEFAULT_CHUNK_SIZE
+from pypy.rpython.memory.support import get_address_stack, get_address_deque
+from pypy.rpython.memory.support import AddressDict
+from pypy.rpython.lltypesystem.llmemory import NULL, raw_malloc_usage
 
 class GCBase(object):
     _alloc_flavor_ = "raw"
@@ -9,6 +14,13 @@
     prebuilt_gc_objects_are_static_roots = True
     can_realloc = False
 
+    def __init__(self, chunk_size=DEFAULT_CHUNK_SIZE):
+        self.gcheaderbuilder = GCHeaderBuilder(self.HDR)
+        self.AddressStack = get_address_stack(chunk_size)
+        self.AddressDeque = get_address_deque(chunk_size)
+        self.AddressDict = AddressDict
+        self.finalizer_lock_count = 0
+
     def can_malloc_nonmovable(self):
         return not self.moving_gc
 
@@ -46,7 +58,7 @@
         pass
 
     def setup(self):
-        pass
+        self.run_finalizers = self.AddressDeque()
 
     def statistics(self, index):
         return -1
@@ -54,6 +66,23 @@
     def size_gc_header(self, typeid=0):
         return self.gcheaderbuilder.size_gc_header
 
+    def header(self, addr):
+        addr -= self.gcheaderbuilder.size_gc_header
+        return llmemory.cast_adr_to_ptr(addr, lltype.Ptr(self.HDR))
+
+    def get_size(self, obj):
+        typeid = self.get_type_id(obj)
+        size = self.fixed_size(typeid)
+        if self.is_varsize(typeid):
+            lenaddr = obj + self.varsize_offset_to_length(typeid)
+            length = lenaddr.signed[0]
+            size += length * self.varsize_item_sizes(typeid)
+            size = llarena.round_up_for_allocation(size)
+            # XXX maybe we should parametrize round_up_for_allocation()
+            # per GC; if we do, we also need to fix the call in
+            # gctypelayout.encode_type_shape()
+        return size
+
     def malloc(self, typeid, length=0, zero=False):
         """For testing.  The interface used by the gctransformer is
         the four malloc_[fixed,var]size[_clear]() functions.
@@ -181,13 +210,86 @@
     def debug_check_object(self, obj):
         pass
 
+    def execute_finalizers(self):
+        self.finalizer_lock_count += 1
+        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)
+        finally:
+            self.finalizer_lock_count -= 1
+
 
 class MovingGCBase(GCBase):
     moving_gc = True
 
+    def setup(self):
+        GCBase.setup(self)
+        self.objects_with_id = self.AddressDict()
+        self.id_free_list = self.AddressStack()
+        self.next_free_id = 1
+
     def can_move(self, addr):
         return True
 
+    def id(self, ptr):
+        # Default implementation for id(), assuming that "external" objects
+        # never move.  Overriden in the HybridGC.
+        obj = llmemory.cast_ptr_to_adr(ptr)
+        if self._is_external(obj):
+            result = obj
+        else:
+            result = self._compute_id(obj)
+        return llmemory.cast_adr_to_int(result)
+
+    def _next_id(self):
+        # return an id not currently in use (as an address instead of an int)
+        if self.id_free_list.non_empty():
+            result = self.id_free_list.pop()    # reuse a dead id
+        else:
+            # make up a fresh id number
+            result = llmemory.cast_int_to_adr(self.next_free_id)
+            self.next_free_id += 2    # only odd numbers, to make lltype
+                                      # and llmemory happy and to avoid
+                                      # clashes with real addresses
+        return result
+
+    def _compute_id(self, obj):
+        # look if the object is listed in objects_with_id
+        result = self.objects_with_id.get(obj)
+        if not result:
+            result = self._next_id()
+            self.objects_with_id.setitem(obj, result)
+        return result
+
+    def update_objects_with_id(self):
+        old = self.objects_with_id
+        new_objects_with_id = self.AddressDict(old.length())
+        old.foreach(self._update_object_id_FAST, new_objects_with_id)
+        old.delete()
+        self.objects_with_id = new_objects_with_id
+
+    def _update_object_id(self, obj, id, new_objects_with_id):
+        # safe version (used by subclasses)
+        if self.surviving(obj):
+            newobj = self.get_forwarding_address(obj)
+            new_objects_with_id.setitem(newobj, id)
+        else:
+            self.id_free_list.append(id)
+
+    def _update_object_id_FAST(self, obj, id, new_objects_with_id):
+        # unsafe version, assumes that the new_objects_with_id is large enough
+        if self.surviving(obj):
+            newobj = self.get_forwarding_address(obj)
+            new_objects_with_id.insertclean(newobj, id)
+        else:
+            self.id_free_list.append(id)
+
+
 def choose_gc_from_config(config):
     """Return a (GCClass, GC_PARAMS) from the given config object.
     """
@@ -199,6 +301,7 @@
                "semispace": "semispace.SemiSpaceGC",
                "generation": "generation.GenerationGC",
                "hybrid": "hybrid.HybridGC",
+               "markcompact" : "markcompact.MarkCompactGC",
                }
     try:
         modulename, classname = classes[config.translation.gc].split('.')

Modified: pypy/dist/pypy/rpython/memory/gc/hybrid.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc/hybrid.py	(original)
+++ pypy/dist/pypy/rpython/memory/gc/hybrid.py	Wed Oct  8 14:10:36 2008
@@ -1,8 +1,8 @@
 import sys
 from pypy.rpython.memory.gc.semispace import SemiSpaceGC
 from pypy.rpython.memory.gc.semispace import DEBUG_PRINT
-from pypy.rpython.memory.gc.generation import GenerationGC, GCFLAG_FORWARDED
-from pypy.rpython.memory.gc.semispace import GCFLAG_EXTERNAL
+from pypy.rpython.memory.gc.generation import GenerationGC
+from pypy.rpython.memory.gc.semispace import GCFLAG_EXTERNAL, GCFLAG_FORWARDED
 from pypy.rpython.memory.gc.generation import GCFLAG_NO_YOUNG_PTRS
 from pypy.rpython.memory.gc.generation import GCFLAG_NO_HEAP_PTRS
 from pypy.rpython.lltypesystem import lltype, llmemory, llarena
@@ -550,19 +550,23 @@
                              dead_size, "bytes in",
                              dead_count, "objs")
 
-    def _compute_id_for_external(self, obj):
-        # the base classes make the assumption that all external objects
-        # have an id equal to their address.  This is wrong if the object
-        # is a generation 3 rawmalloced object that initially lived in
-        # the semispaces.
-        if self.is_last_generation(obj):
-            # in this case, we still need to check if the object had its
-            # id taken before.  If not, we can use its address as its id.
-            return self.objects_with_id.get(obj, obj)
-        else:
-            # a generation 2 external object was never non-external in
-            # the past, so it cannot be listed in self.objects_with_id.
-            return obj
+    def id(self, ptr):
+        obj = llmemory.cast_ptr_to_adr(ptr)
+        if self._is_external(obj):
+            # a prebuilt or rawmalloced object
+            if self.is_last_generation(obj):
+                # a generation 3 object may be one that used to live in
+                # the semispace.  So we still need to check if the object had
+                # its id taken before.  If not, we can use its address as its
+                # id as it is not going to move any more.
+                result = self.objects_with_id.get(obj, obj)
+            else:
+                # a generation 2 external object was never non-external in
+                # the past, so it cannot be listed in self.objects_with_id.
+                result = obj
+        else:
+            result = self._compute_id(obj)     # common case
+        return llmemory.cast_adr_to_int(result)
         # XXX a possible optimization would be to use three dicts, one
         # for each generation, instead of mixing gen2 and gen3 objects.
 

Modified: pypy/dist/pypy/rpython/memory/gc/marksweep.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc/marksweep.py	(original)
+++ pypy/dist/pypy/rpython/memory/gc/marksweep.py	Wed Oct  8 14:10:36 2008
@@ -22,8 +22,6 @@
 DEBUG_PRINT = False
 memoryError = MemoryError()
 class MarkSweepGC(GCBase):
-    _alloc_flavor_ = "raw"
-
     HDR = lltype.ForwardReference()
     HDRPTR = lltype.Ptr(HDR)
     # need to maintain a linked list of malloced objects, since we used the
@@ -44,17 +42,16 @@
     TRANSLATION_PARAMS = {'start_heap_size': 8*1024*1024} # XXX adjust
 
     def __init__(self, chunk_size=DEFAULT_CHUNK_SIZE, start_heap_size=4096):
+        GCBase.__init__(self, chunk_size)
         self.heap_usage = 0          # at the end of the latest collection
         self.bytes_malloced = 0      # since the latest collection
         self.bytes_malloced_threshold = start_heap_size
         self.total_collection_time = 0.0
-        self.AddressStack = get_address_stack(chunk_size)
         self.malloced_objects = lltype.nullptr(self.HDR)
         self.malloced_objects_with_finalizer = lltype.nullptr(self.HDR)
         # these are usually only the small bits of memory that make a
         # weakref object
         self.objects_with_weak_pointers = lltype.nullptr(self.HDR)
-        self.gcheaderbuilder = GCHeaderBuilder(self.HDR)
         # pools, for x_swap_pool():
         #   'curpool' is the current pool, lazily allocated (i.e. NULL means
         #   the current POOL object is not yet malloc'ed).  POOL objects are

Modified: pypy/dist/pypy/rpython/memory/gc/semispace.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc/semispace.py	(original)
+++ pypy/dist/pypy/rpython/memory/gc/semispace.py	Wed Oct  8 14:10:36 2008
@@ -4,7 +4,6 @@
 from pypy.rpython.memory.support import DEFAULT_CHUNK_SIZE
 from pypy.rpython.memory.support import get_address_stack, get_address_deque
 from pypy.rpython.memory.support import AddressDict
-from pypy.rpython.memory.gcheader import GCHeaderBuilder
 from pypy.rpython.lltypesystem import lltype, llmemory, llarena
 from pypy.rlib.objectmodel import free_non_gc_object
 from pypy.rlib.debug import ll_assert
@@ -45,17 +44,10 @@
 
     def __init__(self, chunk_size=DEFAULT_CHUNK_SIZE, space_size=4096,
                  max_space_size=sys.maxint//2+1):
-        MovingGCBase.__init__(self)
+        MovingGCBase.__init__(self, chunk_size)
         self.space_size = space_size
         self.max_space_size = max_space_size
-        self.gcheaderbuilder = GCHeaderBuilder(self.HDR)
-        self.AddressStack = get_address_stack(chunk_size)
-        self.AddressDeque = get_address_deque(chunk_size)
-        self.AddressDict = AddressDict
-        self.finalizer_lock_count = 0
         self.red_zone = 0
-        self.id_free_list = self.AddressStack()
-        self.next_free_id = 1
 
     def setup(self):
         if DEBUG_PRINT:
@@ -67,10 +59,9 @@
         self.fromspace = llarena.arena_malloc(self.space_size, True)
         ll_assert(bool(self.fromspace), "couldn't allocate fromspace")
         self.free = self.tospace
+        MovingGCBase.setup(self)
         self.objects_with_finalizers = self.AddressDeque()
-        self.run_finalizers = self.AddressDeque()
         self.objects_with_weakrefs = self.AddressStack()
-        self.objects_with_id = self.AddressDict()
 
     # This class only defines the malloc_{fixed,var}size_clear() methods
     # because the spaces are filled with zeroes in advance.
@@ -388,20 +379,6 @@
         stub = llmemory.cast_adr_to_ptr(obj, self.FORWARDSTUBPTR)
         stub.forw = newobj
 
-    def get_size(self, obj):
-        typeid = self.get_type_id(obj)
-        size = self.fixed_size(typeid)
-        if self.is_varsize(typeid):
-            lenaddr = obj + self.varsize_offset_to_length(typeid)
-            length = lenaddr.signed[0]
-            size += length * self.varsize_item_sizes(typeid)
-            size = llarena.round_up_for_allocation(size)
-        return size
-
-    def header(self, addr):
-        addr -= self.gcheaderbuilder.size_gc_header
-        return llmemory.cast_adr_to_ptr(addr, lltype.Ptr(self.HDR))
-
     def get_type_id(self, addr):
         tid = self.header(addr).tid
         ll_assert(tid & (GCFLAG_FORWARDED|GCFLAG_EXTERNAL) != GCFLAG_FORWARDED,
@@ -556,75 +533,8 @@
         self.run_finalizers.delete()
         self.run_finalizers = new_run_finalizer
 
-    def execute_finalizers(self):
-        self.finalizer_lock_count += 1
-        try:
-            while self.run_finalizers.non_empty():
-                #print "finalizer"
-                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)
-        finally:
-            self.finalizer_lock_count -= 1
-
-    def id(self, ptr):
-        obj = llmemory.cast_ptr_to_adr(ptr)
-        if self.header(obj).tid & GCFLAG_EXTERNAL:
-            result = self._compute_id_for_external(obj)
-        else:
-            result = self._compute_id(obj)
-        return llmemory.cast_adr_to_int(result)
-
-    def _next_id(self):
-        # return an id not currently in use (as an address instead of an int)
-        if self.id_free_list.non_empty():
-            result = self.id_free_list.pop()    # reuse a dead id
-        else:
-            # make up a fresh id number
-            result = llmemory.cast_int_to_adr(self.next_free_id)
-            self.next_free_id += 2    # only odd numbers, to make lltype
-                                      # and llmemory happy and to avoid
-                                      # clashes with real addresses
-        return result
-
-    def _compute_id(self, obj):
-        # look if the object is listed in objects_with_id
-        result = self.objects_with_id.get(obj)
-        if not result:
-            result = self._next_id()
-            self.objects_with_id.setitem(obj, result)
-        return result
-
-    def _compute_id_for_external(self, obj):
-        # For prebuilt objects, we can simply return their address.
-        # This method is overriden by the HybridGC.
-        return obj
-
-    def update_objects_with_id(self):
-        old = self.objects_with_id
-        new_objects_with_id = self.AddressDict(old.length())
-        old.foreach(self._update_object_id_FAST, new_objects_with_id)
-        old.delete()
-        self.objects_with_id = new_objects_with_id
-
-    def _update_object_id(self, obj, id, new_objects_with_id):
-        # safe version (used by subclasses)
-        if self.surviving(obj):
-            newobj = self.get_forwarding_address(obj)
-            new_objects_with_id.setitem(newobj, id)
-        else:
-            self.id_free_list.append(id)
-
-    def _update_object_id_FAST(self, obj, id, new_objects_with_id):
-        # unsafe version, assumes that the new_objects_with_id is large enough
-        if self.surviving(obj):
-            newobj = self.get_forwarding_address(obj)
-            new_objects_with_id.insertclean(newobj, id)
-        else:
-            self.id_free_list.append(id)
+    def _is_external(self, obj):
+        return (self.header(obj).tid & GCFLAG_EXTERNAL) != 0
 
     def debug_check_object(self, obj):
         """Check the invariants about 'obj' that should be true

Modified: pypy/dist/pypy/rpython/memory/gc/test/test_direct.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc/test/test_direct.py	(original)
+++ pypy/dist/pypy/rpython/memory/gc/test/test_direct.py	Wed Oct  8 14:10:36 2008
@@ -279,3 +279,7 @@
                  'large_object_gcptrs': 12,
                  'generation3_collect_threshold': 5,
                  }
+
+class TestMarkCompactGC(DirectGCTest):
+    from pypy.rpython.memory.gc.markcompact import MarkCompactGC as GCClass
+

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	Wed Oct  8 14:10:36 2008
@@ -9,7 +9,7 @@
 from pypy.rpython.lltypesystem.rstr import STR
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib.objectmodel import compute_unique_id
+from pypy.rlib.objectmodel import compute_unique_id, keepalive_until_here
 
 
 def stdout_ignore_ll_functions(msg):
@@ -263,10 +263,6 @@
         assert res
 
     def test_id(self):
-        py.test.skip("the MovingGCBase.id() logic can't be directly run")
-        # XXX ^^^ the problem is that the MovingGCBase instance holds
-        # references to GC objects - a list of weakrefs and a dict - and
-        # there is no way we can return these from get_roots_from_llinterp().
         class A(object):
             pass
         a1 = A()
@@ -318,6 +314,44 @@
         res = self.interpret(f, [500])
         assert res == 1 + 500
 
+
+    def test_collect_during_collect(self):
+        class B(object):
+            pass
+        b = B()
+        b.nextid = 1
+        b.num_deleted = 0
+        b.num_deleted_c = 0
+        class A(object):
+            def __init__(self):
+                self.id = b.nextid
+                b.nextid += 1
+            def __del__(self):
+                llop.gc__collect(lltype.Void)
+                b.num_deleted += 1
+                C()
+                C()
+        class C(A):
+            def __del__(self):
+                b.num_deleted += 1
+                b.num_deleted_c += 1
+        def f(x, y):
+            persistent_a1 = A()
+            persistent_a2 = A()
+            i = 0
+            while i < x:
+                i += 1
+                a = A()
+            persistent_a3 = A()
+            persistent_a4 = A()
+            llop.gc__collect(lltype.Void)
+            llop.gc__collect(lltype.Void)
+            b.bla = persistent_a1.id + persistent_a2.id + persistent_a3.id + persistent_a4.id
+            print b.num_deleted_c
+            return b.num_deleted
+        res = self.interpret(f, [4, 42])
+        assert res == 12
+
     def test_weakref_across_minor_collection(self):
         import weakref
         class A:
@@ -455,6 +489,15 @@
 class TestGenerationalGC(TestSemiSpaceGC):
     from pypy.rpython.memory.gc.generation import GenerationGC as GCClass
 
+class TestMarkCompactGC(TestSemiSpaceGC):
+    from pypy.rpython.memory.gc.markcompact import MarkCompactGC as GCClass
+
+    def test_finalizer_order(self):
+        py.test.skip("Not implemented yet")
+
+class TestMarkCompactGCGrowing(TestMarkCompactGC):
+    GC_PARAMS = {'space_size': 64}
+
 class TestHybridGC(TestGenerationalGC):
     from pypy.rpython.memory.gc.hybrid import HybridGC as GCClass
     GC_CANNOT_MALLOC_NONMOVABLE = False

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	Wed Oct  8 14:10:36 2008
@@ -341,6 +341,7 @@
         b = B()
         b.nextid = 1
         b.num_deleted = 0
+        b.num_deleted_c = 0
         class A(object):
             def __init__(self):
                 self.id = b.nextid
@@ -353,6 +354,7 @@
         class C(A):
             def __del__(self):
                 b.num_deleted += 1
+                b.num_deleted_c += 1
         def f(x, y):
             persistent_a1 = A()
             persistent_a2 = A()
@@ -365,6 +367,7 @@
             llop.gc__collect(lltype.Void)
             llop.gc__collect(lltype.Void)
             b.bla = persistent_a1.id + persistent_a2.id + persistent_a3.id + persistent_a4.id
+            print b.num_deleted_c
             return b.num_deleted
         run = self.runner(f, nbargs=2)
         # runs collect recursively 4 times
@@ -798,6 +801,15 @@
             GC_PARAMS = {'space_size': 2048}
             root_stack_depth = 200
 
+class TestMarkCompactGC(GenericMovingGCTests):
+    gcname = 'markcompact'
+
+    class gcpolicy(gc.FrameworkGcPolicy):
+        class transformerclass(framework.FrameworkGCTransformer):
+            from pypy.rpython.memory.gc.markcompact import MarkCompactGC as GCClass
+            GC_PARAMS = {'space_size': 2048}
+            root_stack_depth = 200
+
 class TestGenerationGC(GenericMovingGCTests):
     gcname = "generation"
 

Modified: pypy/dist/pypy/translator/c/src/mem.h
==============================================================================
--- pypy/dist/pypy/translator/c/src/mem.h	(original)
+++ pypy/dist/pypy/translator/c/src/mem.h	Wed Oct  8 14:10:36 2008
@@ -90,6 +90,7 @@
     if (r != NULL) memset((void*) r, 0, size);
     
 #define OP_RAW_MEMCOPY(x,y,size,r) memcpy(y,x,size);
+#define OP_RAW_MEMMOVE(x,y,size,r) memmove(y,x,size);
 
 /************************************************************/
 

Modified: pypy/dist/pypy/translator/c/test/test_lladdresses.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_lladdresses.py	(original)
+++ pypy/dist/pypy/translator/c/test/test_lladdresses.py	Wed Oct  8 14:10:36 2008
@@ -96,6 +96,19 @@
     res = fc()
     assert res
 
+def test_raw_memmove():
+    def f():
+        addr = raw_malloc(100)
+        addr.signed[0] = 12
+        (addr + 10).signed[0] = 42
+        raw_memmove(addr, addr + 4, 96)
+        result = (addr + 4).signed[0] + (addr + 14).signed[0]
+        raw_free(addr)
+        return result
+    fc = compile(f, [])
+    res = fc()
+    assert res
+
 def test_pointer_comparison():
     def f():
         result = 0

Modified: pypy/dist/pypy/translator/c/test/test_newgc.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_newgc.py	(original)
+++ pypy/dist/pypy/translator/c/test/test_newgc.py	Wed Oct  8 14:10:36 2008
@@ -1028,3 +1028,13 @@
 
     def test_gc_set_max_heap_size(self):
         py.test.skip("not implemented")
+
+class TestMarkCompactGC(TestSemiSpaceGC):
+    gcpolicy = "markcompact"
+    should_be_moving = True
+
+    def test_gc_set_max_heap_size(self):
+        py.test.skip("not implemented")
+
+    def test_finalizer_order(self):
+        py.test.skip("not implemented")



More information about the Pypy-commit mailing list