[pypy-svn] r51812 - in pypy/branch/unified-rtti/pypy/rpython/memory: . gc gctransform test

arigo at codespeak.net arigo at codespeak.net
Fri Feb 22 22:09:32 CET 2008


Author: arigo
Date: Fri Feb 22 22:09:31 2008
New Revision: 51812

Modified:
   pypy/branch/unified-rtti/pypy/rpython/memory/gc/base.py
   pypy/branch/unified-rtti/pypy/rpython/memory/gc/generation.py
   pypy/branch/unified-rtti/pypy/rpython/memory/gc/marksweep.py
   pypy/branch/unified-rtti/pypy/rpython/memory/gc/semispace.py
   pypy/branch/unified-rtti/pypy/rpython/memory/gctransform/boehm.py
   pypy/branch/unified-rtti/pypy/rpython/memory/gctransform/framework.py
   pypy/branch/unified-rtti/pypy/rpython/memory/gctransform/refcounting.py
   pypy/branch/unified-rtti/pypy/rpython/memory/gctransform/transform.py
   pypy/branch/unified-rtti/pypy/rpython/memory/gcwrapper.py
   pypy/branch/unified-rtti/pypy/rpython/memory/lltypelayout.py
   pypy/branch/unified-rtti/pypy/rpython/memory/test/test_gc.py
Log:
Progress in updating the Semispace and Generation GCs.


Modified: pypy/branch/unified-rtti/pypy/rpython/memory/gc/base.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/memory/gc/base.py	(original)
+++ pypy/branch/unified-rtti/pypy/rpython/memory/gc/base.py	Fri Feb 22 22:09:31 2008
@@ -1,5 +1,4 @@
 from pypy.rpython.lltypesystem import lltype, llmemory
-from pypy.rpython.memory import gcheader, gctypelayout
 from pypy.rlib.debug import ll_assert
 
 class GCBase(object):
@@ -9,10 +8,6 @@
     needs_zero_gc_pointers = True
     prebuilt_gc_objects_are_static_roots = True
 
-    def __init__(self):
-        TYPE_INFO = gctypelayout.GCData.TYPE_INFO
-        self.gcheaderbuilder = gcheader.GCHeaderBuilder(self.HDR, TYPE_INFO)
-
     def set_query_functions(self, is_varsize, has_gcptr_in_varsize,
                             is_gcarrayofgcptr,
                             getfinalizer,

Modified: pypy/branch/unified-rtti/pypy/rpython/memory/gc/generation.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/memory/gc/generation.py	(original)
+++ pypy/branch/unified-rtti/pypy/rpython/memory/gc/generation.py	Fri Feb 22 22:09:31 2008
@@ -31,13 +31,15 @@
     prebuilt_gc_objects_are_static_roots = False
     first_unused_gcflag = SemiSpaceGC.first_unused_gcflag << 2
 
-    def __init__(self, chunk_size=DEFAULT_CHUNK_SIZE,
+    def __init__(self, gcheaderbuilder,
+                 chunk_size=DEFAULT_CHUNK_SIZE,
                  nursery_size=128,
                  min_nursery_size=128,
                  auto_nursery_size=False,
                  space_size=4096,
                  max_space_size=sys.maxint//2+1):
-        SemiSpaceGC.__init__(self, chunk_size = chunk_size,
+        SemiSpaceGC.__init__(self, gcheaderbuilder,
+                             chunk_size = chunk_size,
                              space_size = space_size,
                              max_space_size = max_space_size)
         assert min_nursery_size <= nursery_size <= space_size // 2
@@ -196,9 +198,9 @@
     def init_gc_object(self, addr, typeid, flags=GCFLAG_NO_YOUNG_PTRS):
         SemiSpaceGC.init_gc_object(self, addr, typeid, flags)
 
-    def init_gc_object_immortal(self, addr, typeid,
+    def init_gc_object_immortal(self, hdr, typeid,
                                 flags=GCFLAG_NO_YOUNG_PTRS|GCFLAG_NO_HEAP_PTRS):
-        SemiSpaceGC.init_gc_object_immortal(self, addr, typeid, flags)
+        SemiSpaceGC.init_gc_object_immortal(self, hdr, typeid, flags)
 
     def semispace_collect(self, size_changing=False):
         self.reset_young_gcflags() # we are doing a full collection anyway
@@ -214,7 +216,7 @@
     def trace_and_copy(self, obj):
         # during a full collect, all objects copied might come from the nursery and
         # so must have this flag set:
-        self.header(obj).tid |= GCFLAG_NO_YOUNG_PTRS
+        self.header(obj).flags |= GCFLAG_NO_YOUNG_PTRS
         SemiSpaceGC.trace_and_copy(self, obj)
         # history: this was missing and caused an object to become old but without the
         # flag set.  Such an object is bogus in the sense that the write_barrier doesn't
@@ -227,7 +229,7 @@
         while oldlist.non_empty():
             obj = oldlist.pop()
             hdr = self.header(obj)
-            hdr.tid |= GCFLAG_NO_YOUNG_PTRS
+            hdr.flags |= GCFLAG_NO_YOUNG_PTRS
 
     def weakrefs_grow_older(self):
         while self.young_objects_with_weakrefs.non_empty():
@@ -308,7 +310,7 @@
         """obj must not be in the nursery.  This copies all the
         young objects it references out of the nursery.
         """
-        self.header(obj).tid |= GCFLAG_NO_YOUNG_PTRS
+        self.header(obj).flags |= GCFLAG_NO_YOUNG_PTRS
         self.trace(obj, self._trace_drag_out, None)
 
     def _trace_drag_out(self, pointer, ignored):
@@ -336,7 +338,7 @@
             self.objects_with_weakrefs.append(obj)
 
     def write_barrier(self, oldvalue, newvalue, addr_struct):
-        if self.header(addr_struct).tid & GCFLAG_NO_YOUNG_PTRS:
+        if self.header(addr_struct).flags & GCFLAG_NO_YOUNG_PTRS:
             self.remember_young_pointer(addr_struct, newvalue)
 
     def append_to_static_roots(self, pointer, arg):
@@ -344,7 +346,7 @@
 
     def move_to_static_roots(self, addr_struct):
         objhdr = self.header(addr_struct)
-        objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS
+        objhdr.flags &= ~GCFLAG_NO_HEAP_PTRS
         self.trace(addr_struct, self.append_to_static_roots, None)
 
     def remember_young_pointer(self, addr_struct, addr):
@@ -353,8 +355,8 @@
         oldhdr = self.header(addr_struct)
         if self.is_in_nursery(addr):
             self.old_objects_pointing_to_young.append(addr_struct)
-            oldhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS
-        if oldhdr.tid & GCFLAG_NO_HEAP_PTRS:
+            oldhdr.flags &= ~GCFLAG_NO_YOUNG_PTRS
+        if oldhdr.flags & GCFLAG_NO_HEAP_PTRS:
             self.move_to_static_roots(addr_struct)
     remember_young_pointer._dont_inline_ = True
 

Modified: pypy/branch/unified-rtti/pypy/rpython/memory/gc/marksweep.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/memory/gc/marksweep.py	(original)
+++ pypy/branch/unified-rtti/pypy/rpython/memory/gc/marksweep.py	Fri Feb 22 22:09:31 2008
@@ -74,8 +74,9 @@
     POOLNODE.become(lltype.Struct('gc_pool_node', ('linkedlisthdr', HDR),
                                                   ('nextnode', POOLNODEPTR)))
 
-    def __init__(self, chunk_size=DEFAULT_CHUNK_SIZE, start_heap_size=4096):
-        GCBase.__init__(self)
+    def __init__(self, gcheaderbuilder,
+                 chunk_size=DEFAULT_CHUNK_SIZE, start_heap_size=4096):
+        self.gcheaderbuilder = gcheaderbuilder
         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

Modified: pypy/branch/unified-rtti/pypy/rpython/memory/gc/semispace.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/memory/gc/semispace.py	(original)
+++ pypy/branch/unified-rtti/pypy/rpython/memory/gc/semispace.py	Fri Feb 22 22:09:31 2008
@@ -1,9 +1,8 @@
 from pypy.rpython.lltypesystem.llmemory import raw_malloc, raw_free
 from pypy.rpython.lltypesystem.llmemory import raw_memcopy, raw_memclear
 from pypy.rpython.lltypesystem.llmemory import NULL, raw_malloc_usage
-from pypy.rpython.memory.support import DEFAULT_CHUNK_SIZE
+from pypy.rpython.memory.support import DEFAULT_CHUNK_SIZE, RTTIPTR
 from pypy.rpython.memory.support import get_address_stack, get_address_deque
-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
@@ -14,7 +13,7 @@
 import sys, os
 
 TYPEID_MASK = 0xffff
-first_gcflag = 1 << 16
+first_gcflag = 1
 GCFLAG_FORWARDED = first_gcflag
 GCFLAG_IMMORTAL = first_gcflag << 1
 GCFLAG_FINALIZATION_ORDERING = first_gcflag << 2
@@ -31,17 +30,21 @@
     total_collection_time = 0.0
     total_collection_count = 0
 
-    HDR = lltype.Struct('header', ('tid', lltype.Signed))
-    FORWARDSTUB = lltype.GcStruct('forwarding_stub',
-                                  ('forw', llmemory.Address))
-    FORWARDSTUBPTR = lltype.Ptr(FORWARDSTUB)
+    # header structure:
+    #
+    #   * typeptr: normally a RTTIPTR, but if the object is forwarded,
+    #              this is used to hold the forwarding address
+    #   * flags: for GCFLAG_XXX
+    #
+    HDR = lltype.Struct('header', ('typeptr', llmemory.Address),
+                                  ('flags', lltype.Signed))
 
-    def __init__(self, chunk_size=DEFAULT_CHUNK_SIZE, space_size=4096,
-                 max_space_size=sys.maxint//2+1):
+    def __init__(self, gcheaderbuilder, chunk_size=DEFAULT_CHUNK_SIZE,
+                 space_size=4096, max_space_size=sys.maxint//2+1):
         MovingGCBase.__init__(self)
+        self.gcheaderbuilder = gcheaderbuilder
         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.finalizer_lock_count = 0
@@ -293,9 +296,10 @@
 
     def copy(self, obj):
         if self.is_forwarded(obj):
-            #llop.debug_print(lltype.Void, obj, "already copied to", self.get_forwarding_address(obj))
+            # 'obj' already copied to 'self.get_forwarding_address(obj)'
             return self.get_forwarding_address(obj)
         else:
+            # copying 'obj' to 'newobj'
             newaddr = self.free
             objsize = self.get_size(obj)
             totalsize = self.size_gc_header() + objsize
@@ -303,9 +307,6 @@
             raw_memcopy(obj - self.size_gc_header(), newaddr, totalsize)
             self.free += totalsize
             newobj = newaddr + self.size_gc_header()
-            #llop.debug_print(lltype.Void, obj, "copied to", newobj,
-            #                 "tid", self.header(obj).tid,
-            #                 "size", totalsize)
             self.set_forwarding_address(obj, newobj, objsize)
             return newobj
 
@@ -317,35 +318,26 @@
             pointer.address[0] = self.copy(pointer.address[0])
 
     def is_forwarded(self, obj):
-        return self.header(obj).tid & GCFLAG_FORWARDED != 0
+        return self.header(obj).flags & GCFLAG_FORWARDED != 0
         # note: all prebuilt objects also have this flag set
 
     def get_forwarding_address(self, obj):
-        tid = self.header(obj).tid
-        if tid & GCFLAG_IMMORTAL:
+        hdr = self.header(obj)
+        flags = hdr.flags
+        ll_assert(flags & GCFLAG_FORWARDED != 0, "object not forwarded!")
+        if flags & GCFLAG_IMMORTAL:
             return obj      # prebuilt objects are "forwarded" to themselves
         else:
-            stub = llmemory.cast_adr_to_ptr(obj, self.FORWARDSTUBPTR)
-            return stub.forw
+            return hdr.typeptr     # holds the forwarding address
 
     def set_forwarding_address(self, obj, newobj, objsize):
-        # To mark an object as forwarded, we set the GCFLAG_FORWARDED and
-        # overwrite the object with a FORWARDSTUB.  Doing so is a bit
-        # long-winded on llarena, but it all melts down to two memory
-        # writes after translation to C.
-        size_gc_header = self.size_gc_header()
-        stubsize = llmemory.sizeof(self.FORWARDSTUB)
-        tid = self.header(obj).tid
-        ll_assert(tid & GCFLAG_IMMORTAL == 0,  "unexpected GCFLAG_IMMORTAL")
-        ll_assert(tid & GCFLAG_FORWARDED == 0, "unexpected GCFLAG_FORWARDED")
-        # replace the object at 'obj' with a FORWARDSTUB.
-        hdraddr = obj - size_gc_header
-        llarena.arena_reset(hdraddr, size_gc_header + objsize, False)
-        llarena.arena_reserve(hdraddr, size_gc_header + stubsize)
-        hdr = llmemory.cast_adr_to_ptr(hdraddr, lltype.Ptr(self.HDR))
-        hdr.tid = tid | GCFLAG_FORWARDED
-        stub = llmemory.cast_adr_to_ptr(obj, self.FORWARDSTUBPTR)
-        stub.forw = newobj
+        # To mark an object as forwarded, we set the GCFLAG_FORWARDED bit.
+        hdr = self.header(obj)
+        flags = hdr.flags
+        ll_assert(flags & GCFLAG_IMMORTAL == 0,  "unexpected GCFLAG_IMMORTAL")
+        ll_assert(flags & GCFLAG_FORWARDED == 0, "unexpected GCFLAG_FORWARDED")
+        hdr.flags = flags | GCFLAG_FORWARDED
+        hdr.typeptr = newobj
 
     def get_size(self, obj):
         typeid = self.get_type_id(obj)
@@ -362,22 +354,22 @@
         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_IMMORTAL) != GCFLAG_FORWARDED,
-                  "get_type_id on forwarded obj")
-        # Non-prebuilt forwarded objects are overwritten with a FORWARDSTUB.
-        # Although calling get_type_id() on a forwarded object works by itself,
-        # we catch it as an error because it's likely that what is then
-        # done with the typeid is bogus.
-        return tid & TYPEID_MASK
+        hdr = self.header(addr)
+        # In non-prebuilt forwarded objects, the typeptr is used to hold
+        # the forwaring address.  So far, we don't need to do get_type_id()
+        # on forwarded objects, so we just assert that nobody tries to.
+        ll_assert(hdr.flags & (GCFLAG_FORWARDED|GCFLAG_IMMORTAL)
+                  != GCFLAG_FORWARDED, "get_type_id on forwarded obj")
+        return llmemory.cast_adr_to_ptr(hdr.typeptr, RTTIPTR)
 
     def init_gc_object(self, addr, typeid, flags=0):
         hdr = llmemory.cast_adr_to_ptr(addr, lltype.Ptr(self.HDR))
-        hdr.tid = typeid | flags
+        hdr.typeptr = llmemory.cast_ptr_to_adr(typeid)
+        hdr.flags = flags
 
-    def init_gc_object_immortal(self, addr, typeid, flags=0):
-        hdr = llmemory.cast_adr_to_ptr(addr, lltype.Ptr(self.HDR))
-        hdr.tid = typeid | flags | GCFLAG_IMMORTAL | GCFLAG_FORWARDED
+    def init_gc_object_immortal(self, hdr, typeid, flags=0):
+        hdr.typeptr = llmemory.cast_ptr_to_adr(typeid)
+        hdr.flags = flags | GCFLAG_IMMORTAL | GCFLAG_FORWARDED
         # immortal objects always have GCFLAG_FORWARDED set;
         # see get_forwarding_address().
 
@@ -442,13 +434,13 @@
         if self.is_forwarded(obj):
             newobj = self.get_forwarding_address(obj)
             hdr = self.header(newobj)
-            if hdr.tid & GCFLAG_FINALIZATION_ORDERING:
+            if hdr.flags & GCFLAG_FINALIZATION_ORDERING:
                 return 2
             else:
                 return 3
         else:
             hdr = self.header(obj)
-            if hdr.tid & GCFLAG_FINALIZATION_ORDERING:
+            if hdr.flags & GCFLAG_FINALIZATION_ORDERING:
                 return 1
             else:
                 return 0
@@ -457,7 +449,7 @@
         ll_assert(self._finalization_state(obj) == 0,
                   "unexpected finalization state != 0")
         hdr = self.header(obj)
-        hdr.tid |= GCFLAG_FINALIZATION_ORDERING
+        hdr.flags |= GCFLAG_FINALIZATION_ORDERING
 
     def _recursively_bump_finalization_state_from_2_to_3(self, obj):
         ll_assert(self._finalization_state(obj) == 2,
@@ -469,8 +461,8 @@
         while pending.non_empty():
             y = pending.pop()
             hdr = self.header(y)
-            if hdr.tid & GCFLAG_FINALIZATION_ORDERING:     # state 2 ?
-                hdr.tid &= ~GCFLAG_FINALIZATION_ORDERING   # change to state 3
+            if hdr.flags & GCFLAG_FINALIZATION_ORDERING:    # state 2 ?
+                hdr.flags &= ~GCFLAG_FINALIZATION_ORDERING  # change to state 3
                 self.trace(y, self._append_if_nonnull, pending)
 
     def _recursively_bump_finalization_state_from_1_to_2(self, obj, scan):

Modified: pypy/branch/unified-rtti/pypy/rpython/memory/gctransform/boehm.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/memory/gctransform/boehm.py	(original)
+++ pypy/branch/unified-rtti/pypy/rpython/memory/gctransform/boehm.py	Fri Feb 22 22:09:31 2008
@@ -16,7 +16,6 @@
 
     def __init__(self, translator, inline=False):
         super(BoehmGCTransformer, self).__init__(translator, inline=inline)
-        self.newgcheaderbuilder(self.HDR, self.TYPEINFO)
         self.finalizer_funcptrs = {}
 
         atomic_mh = mallocHelpers()

Modified: pypy/branch/unified-rtti/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/memory/gctransform/framework.py	(original)
+++ pypy/branch/unified-rtti/pypy/rpython/memory/gctransform/framework.py	Fri Feb 22 22:09:31 2008
@@ -95,9 +95,10 @@
     use_stackless = False
     root_stack_depth = 163840
 
+    TYPEINFO = gctypelayout.GCData.TYPE_INFO
+
     def __init__(self, translator):
         from pypy.rpython.memory.gc.base import choose_gc_from_config
-        super(FrameworkGCTransformer, self).__init__(translator, inline=True)
         if hasattr(self, 'GC_PARAMS'):
             # for tests: the GC choice can be specified as class attributes
             from pypy.rpython.memory.gc.marksweep import MarkSweepGC
@@ -107,13 +108,14 @@
             # for regular translation: pick the GC from the config
             GCClass, GC_PARAMS = choose_gc_from_config(translator.config)
 
-        gc = GCClass(**GC_PARAMS)
-        self.setgcheaderbuilder(gc.gcheaderbuilder)
+        self.HDR = GCClass.HDR
+        super(FrameworkGCTransformer, self).__init__(translator, inline=True)
+
         self.layoutbuilder = TransformerLayoutBuilder(self)
         self.get_type_id = self.layoutbuilder.get_type_id
 
         gcdata = gctypelayout.GCData(self.gcheaderbuilder)
-        gcdata.gc = gc
+        gcdata.gc = GCClass(self.gcheaderbuilder, **GC_PARAMS)
 
         # initialize the following two fields with a random non-NULL address,
         # to make the annotator happy.  The fields are patched in finish()

Modified: pypy/branch/unified-rtti/pypy/rpython/memory/gctransform/refcounting.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/memory/gctransform/refcounting.py	(original)
+++ pypy/branch/unified-rtti/pypy/rpython/memory/gctransform/refcounting.py	Fri Feb 22 22:09:31 2008
@@ -48,7 +48,6 @@
 
         # create incref, etc  graph
 
-        self.newgcheaderbuilder(self.HDR, self.TYPEINFO)
         gchelpers = self.gchelpers
         gc_header_offset = gchelpers.gc_header_offset
         HDRPTR = lltype.Ptr(self.HDR)

Modified: pypy/branch/unified-rtti/pypy/rpython/memory/gctransform/transform.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/memory/gctransform/transform.py	(original)
+++ pypy/branch/unified-rtti/pypy/rpython/memory/gctransform/transform.py	Fri Feb 22 22:09:31 2008
@@ -13,6 +13,7 @@
 from pypy.annotation import model as annmodel
 from pypy.rpython import rmodel, annlowlevel
 from pypy.rpython.memory import gc
+from pypy.rpython.memory.gcheader import GCHeaderBuilder
 from pypy.rpython.memory.gctransform.support import var_ispyobj
 from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
 from pypy.rpython.rtyper import LowLevelOpList
@@ -526,14 +527,10 @@
             self.stack_malloc_fixedsize_ptr = self.inittime_helper(
                 ll_stack_malloc_fixedsize, [lltype.Signed], llmemory.Address)
 
-    def newgcheaderbuilder(self, HDR, TYPEINFO):
-        from pypy.rpython.memory.gcheader import GCHeaderBuilder
-        self.setgcheaderbuilder(GCHeaderBuilder(HDR, TYPEINFO))
-
-    def setgcheaderbuilder(self, gcheaderbuilder):
-        # at the moment, all GC transformers are based on a GCHeaderBuilder.
-        self.gcheaderbuilder = gcheaderbuilder
-        self.gchelpers = GCHelpers(gcheaderbuilder)
+        # at the moment, all GC transformers are based on a GCHeaderBuilder
+        # built from self.HDR and self.TYPEINFO.
+        self.gcheaderbuilder = GCHeaderBuilder(self.HDR, self.TYPEINFO)
+        self.gchelpers = GCHelpers(self.gcheaderbuilder)
         if self.translator:
             self.gc_runtime_type_info_ptr = self.inittime_helper(
                 self.gchelpers.gc_runtime_type_info, [llmemory.Address],

Modified: pypy/branch/unified-rtti/pypy/rpython/memory/gcwrapper.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/memory/gcwrapper.py	(original)
+++ pypy/branch/unified-rtti/pypy/rpython/memory/gcwrapper.py	Fri Feb 22 22:09:31 2008
@@ -2,20 +2,23 @@
 from pypy.rpython import llinterp
 from pypy.rpython.annlowlevel import llhelper
 from pypy.rpython.memory import gctypelayout
+from pypy.rpython.memory.gcheader import GCHeaderBuilder
 from pypy.objspace.flow.model import Constant
 
 
 class GCManagedHeap(object):
 
     def __init__(self, llinterp, flowgraphs, gc_class, GC_PARAMS={}):
-        self.gc = gc_class(chunk_size = 10, **GC_PARAMS)
+        TYPEINFO = gctypelayout.GCData.TYPE_INFO
+        self.gcheaderbuilder = GCHeaderBuilder(gc_class.HDR, TYPEINFO)
+        self.gc = gc_class(self.gcheaderbuilder, chunk_size = 10, **GC_PARAMS)
         self.gc.set_root_walker(LLInterpRootWalker(self))
         self.llinterp = llinterp
         self.prepare_graphs(flowgraphs)
         self.gc.setup()
 
     def prepare_graphs(self, flowgraphs):
-        layoutbuilder = DirectRunLayoutBuilder(self.gc.gcheaderbuilder,
+        layoutbuilder = DirectRunLayoutBuilder(self.gcheaderbuilder,
                                                self.llinterp)
         self.get_type_id = layoutbuilder.get_type_id
         layoutbuilder.initialize_gc_query_function(self.gc)

Modified: pypy/branch/unified-rtti/pypy/rpython/memory/lltypelayout.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/memory/lltypelayout.py	(original)
+++ pypy/branch/unified-rtti/pypy/rpython/memory/lltypelayout.py	Fri Feb 22 22:09:31 2008
@@ -30,7 +30,7 @@
         for name in TYPE._names:
             layout[name] = curr
             curr += get_fixed_size(TYPE._flds[name])
-        layout["_size"] = curr
+        layout["_size"] = curr or 1    # sizeof(empty struct) == 1, as in C
         return layout
     elif isinstance(TYPE, lltype.Array):
         return (get_fixed_size(lltype.Signed), get_fixed_size(TYPE.OF))

Modified: pypy/branch/unified-rtti/pypy/rpython/memory/test/test_gc.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/memory/test/test_gc.py	(original)
+++ pypy/branch/unified-rtti/pypy/rpython/memory/test/test_gc.py	Fri Feb 22 22:09:31 2008
@@ -43,6 +43,22 @@
             res = ''.join(res.chars)
         return res
 
+    def test_empty_class(self):
+        class A(object):
+            pass
+        def func():
+            a1 = A()
+            a2 = A()
+            a3 = A()
+            assert a1 is not a2
+            assert a1 is not a3
+            assert a2 is not a3
+            llop.gc__collect(lltype.Void)
+            assert a1 is not a2
+            assert a1 is not a3
+            assert a2 is not a3
+        self.interpret(func, [])
+
     def test_llinterp_lists(self):
         #curr = simulator.current_size
         def malloc_a_lot():



More information about the Pypy-commit mailing list