[pypy-svn] r68701 - in pypy/trunk/pypy/rpython/memory: gc gctransform test

pedronis at codespeak.net pedronis at codespeak.net
Wed Oct 21 19:17:55 CEST 2009


Author: pedronis
Date: Wed Oct 21 19:17:54 2009
New Revision: 68701

Modified:
   pypy/trunk/pypy/rpython/memory/gc/base.py
   pypy/trunk/pypy/rpython/memory/gc/generation.py
   pypy/trunk/pypy/rpython/memory/gc/hybrid.py
   pypy/trunk/pypy/rpython/memory/gc/markcompact.py
   pypy/trunk/pypy/rpython/memory/gc/marksweep.py
   pypy/trunk/pypy/rpython/memory/gc/semispace.py
   pypy/trunk/pypy/rpython/memory/gctransform/framework.py
   pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py
Log:
- rewrite test_transformed_gc to compile the gcs only once per test class
- make sure all runtime values are setup in the gc setup methods
- add a _teardown() logic to some gc classes
both the latter for the benefit of test_transformed_gc

probably at some point need to do better about the cleanup calls in case 
of failures, also the global_list test didn't make it



Modified: pypy/trunk/pypy/rpython/memory/gc/base.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gc/base.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gc/base.py	Wed Oct 21 19:17:54 2009
@@ -20,9 +20,17 @@
         self.AddressStack = get_address_stack(chunk_size)
         self.AddressDeque = get_address_deque(chunk_size)
         self.AddressDict = AddressDict
-        self.finalizer_lock_count = 0
         self.config = config
 
+    def setup(self):
+        # all runtime mutable values' setup should happen here
+        # and in its overriden versions! for the benefit of test_transformed_gc
+        self.finalizer_lock_count = 0
+        self.run_finalizers = self.AddressDeque()
+
+    def _teardown(self):
+        pass
+
     def can_malloc_nonmovable(self):
         return not self.moving_gc
 
@@ -59,9 +67,6 @@
     def write_barrier(self, newvalue, addr_struct):
         pass
 
-    def setup(self):
-        self.run_finalizers = self.AddressDeque()
-
     def statistics(self, index):
         return -1
 

Modified: pypy/trunk/pypy/rpython/memory/gc/generation.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gc/generation.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gc/generation.py	Wed Oct 21 19:17:54 2009
@@ -55,12 +55,8 @@
         self.initial_nursery_size = nursery_size
         self.auto_nursery_size = auto_nursery_size
         self.min_nursery_size = min_nursery_size
-        self.old_objects_pointing_to_young = self.AddressStack()
-        # ^^^ a list of addresses inside the old objects space; it
-        # may contain static prebuilt objects as well.  More precisely,
-        # it lists exactly the old and static objects whose
-        # GCFLAG_NO_YOUNG_PTRS bit is not set.
-        self.young_objects_with_weakrefs = self.AddressStack()
+
+        # define nursery fields
         self.reset_nursery()
         self._setup_wb()
 
@@ -74,6 +70,13 @@
         self.lb_young_var_basesize = sz
 
     def setup(self):
+        self.old_objects_pointing_to_young = self.AddressStack()
+        # ^^^ a list of addresses inside the old objects space; it
+        # may contain static prebuilt objects as well.  More precisely,
+        # it lists exactly the old and static objects whose
+        # GCFLAG_NO_YOUNG_PTRS bit is not set.
+        self.young_objects_with_weakrefs = self.AddressStack()
+
         self.last_generation_root_objects = self.AddressStack()
         self.young_objects_with_id = self.AddressDict()
         SemiSpaceGC.setup(self)
@@ -87,6 +90,12 @@
             if newsize > 0:
                 self.set_nursery_size(newsize)
 
+        self.reset_nursery()
+
+    def _teardown(self):
+        self.collect() # should restore last gen objects flags
+        SemiSpaceGC._teardown(self)
+
     def reset_nursery(self):
         self.nursery      = NULL
         self.nursery_top  = NULL

Modified: pypy/trunk/pypy/rpython/memory/gc/hybrid.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gc/hybrid.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gc/hybrid.py	Wed Oct 21 19:17:54 2009
@@ -114,13 +114,14 @@
         self.nonlarge_gcptrs_max = large_object_gcptrs - 1
         assert self.nonlarge_gcptrs_max <= self.lb_young_var_basesize
         assert self.nonlarge_max <= self.nonlarge_gcptrs_max
-        self.large_objects_collect_trigger = self.space_size
+
+    def setup(self):
+        self.large_objects_collect_trigger = self.param_space_size
         if self.config.gcconfig.debugprint:
             self._initial_trigger = self.large_objects_collect_trigger
         self.rawmalloced_objects_to_trace = self.AddressStack()
         self.count_semispaceonly_collects = 0
 
-    def setup(self):
         self.gen2_rawmalloced_objects = self.AddressStack()
         self.gen3_rawmalloced_objects = self.AddressStack()
         self.gen2_resizable_objects = self.AddressStack()

Modified: pypy/trunk/pypy/rpython/memory/gc/markcompact.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gc/markcompact.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gc/markcompact.py	Wed Oct 21 19:17:54 2009
@@ -91,11 +91,13 @@
 
     def __init__(self, config, chunk_size=DEFAULT_CHUNK_SIZE, space_size=4096):
         import py; py.test.skip("Disabled for now, sorry")
+        self.param_space_size = space_size
         MovingGCBase.__init__(self, config, chunk_size)
-        self.space_size = space_size
-        self.next_collect_after = space_size/2 # whatever...
 
     def setup(self):
+        self.space_size = self.param_space_size
+        self.next_collect_after = self.param_space_size/2 # whatever...
+
         if self.config.gcconfig.debugprint:
             self.program_start_time = time.time()
         self.space = llarena.arena_malloc(self.space_size, True)

Modified: pypy/trunk/pypy/rpython/memory/gc/marksweep.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gc/marksweep.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gc/marksweep.py	Wed Oct 21 19:17:54 2009
@@ -48,10 +48,14 @@
     TRANSLATION_PARAMS = {'start_heap_size': 8*1024*1024} # XXX adjust
 
     def __init__(self, config, chunk_size=DEFAULT_CHUNK_SIZE, start_heap_size=4096):
+        self.param_start_heap_size = start_heap_size
         GCBase.__init__(self, config, chunk_size)
+
+    def setup(self):
+        GCBase.setup(self)
         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.bytes_malloced_threshold = self.param_start_heap_size
         self.total_collection_time = 0.0
         self.malloced_objects = lltype.nullptr(self.HDR)
         self.malloced_objects_with_finalizer = lltype.nullptr(self.HDR)

Modified: pypy/trunk/pypy/rpython/memory/gc/semispace.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gc/semispace.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gc/semispace.py	Wed Oct 21 19:17:54 2009
@@ -31,8 +31,6 @@
     inline_simple_malloc_varsize = True
     malloc_zero_filled = True
     first_unused_gcflag = first_gcflag << 5
-    total_collection_time = 0.0
-    total_collection_count = 0
 
     HDR = lltype.Struct('header', ('tid', lltype.Signed))   # XXX or rffi.INT?
     typeid_is_in_field = 'tid'
@@ -51,12 +49,18 @@
 
     def __init__(self, config, chunk_size=DEFAULT_CHUNK_SIZE, space_size=4096,
                  max_space_size=sys.maxint//2+1):
+        self.param_space_size = space_size
+        self.param_max_space_size = max_space_size
         MovingGCBase.__init__(self, config, chunk_size)
-        self.space_size = space_size
-        self.max_space_size = max_space_size
-        self.red_zone = 0
 
     def setup(self):
+        self.total_collection_time = 0.0
+        self.total_collection_count = 0
+
+        self.space_size = self.param_space_size
+        self.max_space_size = self.param_max_space_size
+        self.red_zone = 0
+
         if self.config.gcconfig.debugprint:
             self.program_start_time = time.time()
         self.tospace = llarena.arena_malloc(self.space_size, True)
@@ -69,6 +73,11 @@
         self.objects_with_finalizers = self.AddressDeque()
         self.objects_with_weakrefs = self.AddressStack()
 
+    def _teardown(self):
+        llop.debug_print(lltype.Void, "Teardown")
+        llarena.arena_free(self.fromspace)
+        llarena.arena_free(self.tospace)
+
     # This class only defines the malloc_{fixed,var}size_clear() methods
     # because the spaces are filled with zeroes in advance.
 

Modified: pypy/trunk/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gctransform/framework.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gctransform/framework.py	Wed Oct 21 19:17:54 2009
@@ -168,6 +168,10 @@
             root_walker.setup_root_walker()
             gcdata.gc.setup()
 
+        def frameworkgc__teardown():
+            # run-time teardown code for tests!
+            gcdata.gc._teardown()
+
         bk = self.translator.annotator.bookkeeper
         r_typeid16 = rffi.platform.numbertype_to_rclass[TYPE_ID]
         s_typeid16 = annmodel.SomeInteger(knowntype=r_typeid16)
@@ -198,6 +202,10 @@
 
         self.frameworkgc_setup_ptr = getfn(frameworkgc_setup, [],
                                            annmodel.s_None)
+        # for tests
+        self.frameworkgc__teardown_ptr = getfn(frameworkgc__teardown, [],
+                                               annmodel.s_None)
+        
         if root_walker.need_root_stack:
             self.incr_stack_ptr = getfn(root_walker.incr_stack,
                                        [annmodel.SomeInteger()],

Modified: pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py	(original)
+++ pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py	Wed Oct 21 19:17:54 2009
@@ -1,9 +1,10 @@
 import py
 import sys
-import struct
+import struct, inspect
 from pypy.translator.c import gc
 from pypy.annotation import model as annmodel
-from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.annotation import policy as annpolicy
+from pypy.rpython.lltypesystem import lltype, llmemory, llarena
 from pypy.rpython.memory.gctransform import framework
 from pypy.rpython.lltypesystem.lloperation import llop, void
 from pypy.rpython.memory.gc.marksweep import X_CLONE, X_POOL, X_POOL_PTR
@@ -26,7 +27,9 @@
     if stacklessgc:
         t.config.translation.gcrootfinder = "stackless"
     t.config.set(**extraconfigopts)
-    t.buildannotator().build_types(func, inputtypes)
+    ann = t.buildannotator(policy=annpolicy.StrictAnnotatorPolicy())
+    ann.build_types(func, inputtypes)
+                                   
     if specialize:
         t.buildrtyper().specialize()
     if backendopt:
@@ -36,64 +39,124 @@
         t.viewcg()
     return t
 
+ARGS = lltype.FixedSizeArray(lltype.Signed, 3)
+
 class GCTest(object):
     gcpolicy = None
     stacklessgc = False
     GC_CAN_MOVE = False
     GC_CANNOT_MALLOC_NONMOVABLE = False
+    taggedpointers = False
+    
+    def setup_class(cls):
+        funcs0 = []
+        funcs2 = []
+        cleanups = []
+        name_to_func = {}
+        mixlevelstuff = []
+        for fullname in dir(cls):
+            if not fullname.startswith('define'):
+                continue
+            definefunc = getattr(cls, fullname)
+            _, name = fullname.split('_', 1)
+            func_fixup = definefunc.im_func(cls)
+            cleanup = None
+            if isinstance(func_fixup, tuple):
+                func, cleanup, fixup = func_fixup
+                mixlevelstuff.append(fixup)
+            else:
+                func = func_fixup
+            func.func_name = "f_%s" % name
+            if cleanup:
+                cleanup.func_name = "clean_%s" % name
+
+            nargs = len(inspect.getargspec(func)[0])
+            name_to_func[name] = len(funcs0)
+            if nargs == 2:
+                funcs2.append(func)
+                funcs0.append(None)
+            elif nargs == 0:
+                funcs0.append(func)
+                funcs2.append(None)
+            else:
+                raise NotImplementedError(
+                         "defined test functions should have 0/2 arguments")
+            # used to let test cleanup static root pointing to runtime
+            # allocated stuff
+            cleanups.append(cleanup)
+
+        def entrypoint(args):
+            num = args[0]
+            func = funcs0[num]
+            if func:
+                res = func()
+            else:
+                func = funcs2[num]
+                res = func(args[1], args[2])
+            cleanup = cleanups[num]
+            if cleanup:
+                cleanup()
+            return res
 
-    def runner(self, f, nbargs=0, statistics=False, transformer=False,
-               mixlevelstuff=None, **extraconfigopts):
-        if nbargs == 2:
-            def entrypoint(args):
-                x = args[0]
-                y = args[1]
-                r = f(x, y)
-                return r
-        elif nbargs == 0:
-            def entrypoint(args):
-                return f()
-        else:
-            raise NotImplementedError("pure laziness")
-
-        from pypy.rpython.llinterp import LLInterpreter
         from pypy.translator.c.genc import CStandaloneBuilder
 
-        ARGS = lltype.FixedSizeArray(lltype.Signed, nbargs)
         s_args = annmodel.SomePtr(lltype.Ptr(ARGS))
-        t = rtype(entrypoint, [s_args], gcname=self.gcname,
-                                        stacklessgc=self.stacklessgc,
-                                        **extraconfigopts)
-        if mixlevelstuff:
-            mixlevelstuff(t)
+        t = rtype(entrypoint, [s_args], gcname=cls.gcname,
+                  stacklessgc=cls.stacklessgc,
+                  taggedpointers=cls.taggedpointers)
+
+        for fixup in mixlevelstuff:
+            if fixup:
+                fixup(t)
+
         cbuild = CStandaloneBuilder(t, entrypoint, config=t.config,
-                                    gcpolicy=self.gcpolicy)
+                                    gcpolicy=cls.gcpolicy)
         db = cbuild.generate_graphs_for_llinterp()
         entrypointptr = cbuild.getentrypointptr()
         entrygraph = entrypointptr._obj.graph
         if conftest.option.view:
             t.viewcg()
 
-        llinterp = LLInterpreter(t.rtyper)
+        cls.name_to_func = name_to_func
+        cls.entrygraph = entrygraph
+        cls.rtyper = t.rtyper
+        cls.db = db
+
+    def runner(self, name, statistics=False, transformer=False):
+        db = self.db
+        name_to_func = self.name_to_func
+        entrygraph = self.entrygraph
+        from pypy.rpython.llinterp import LLInterpreter
+
+        llinterp = LLInterpreter(self.rtyper)
+
+        gct = db.gctransformer
+
+        if self.__class__.__dict__.get('_used', False):
+            teardowngraph = gct.frameworkgc__teardown_ptr.value._obj.graph
+            llinterp.eval_graph(teardowngraph, [])
+        self.__class__._used = True
 
         # FIIIIISH
-        setupgraph = db.gctransformer.frameworkgc_setup_ptr.value._obj.graph
+        setupgraph = gct.frameworkgc_setup_ptr.value._obj.graph
+        # setup => resets the gc
         llinterp.eval_graph(setupgraph, [])
         def run(args):
             ll_args = lltype.malloc(ARGS, immortal=True)
-            for i in range(nbargs):
-                ll_args[i] = args[i]
+            ll_args[0] = name_to_func[name]
+            for i in range(len(args)):
+                ll_args[1+i] = args[i]
             res = llinterp.eval_graph(entrygraph, [ll_args])
             return res
 
         if statistics:
-            statisticsgraph = db.gctransformer.statistics_ptr.value._obj.graph
-            ll_gc = db.gctransformer.c_const_gc.value
+            statisticsgraph = gct.statistics_ptr.value._obj.graph
+            ll_gc = gct.c_const_gc.value
             def statistics(index):
                 return llinterp.eval_graph(statisticsgraph, [ll_gc, index])
             return run, statistics
         elif transformer:
-            return run, db.gctransformer
+            return run, gct
         else:
             return run
         
@@ -109,7 +172,7 @@
         else:
             return -1     # xxx
 
-    def test_instances(self):
+    def define_instances(cls):
         class A(object):
             pass
         class B(A):
@@ -129,12 +192,15 @@
                     b.last = first
                     j += 1
             return 0
-        run, statistics = self.runner(malloc_a_lot, statistics=True)
+        return malloc_a_lot
+    
+    def test_instances(self):
+        run, statistics = self.runner("instances", statistics=True)
         run([])
         heap_size = self.heap_usage(statistics)
 
 
-    def test_llinterp_lists(self):
+    def define_llinterp_lists(cls):
         def malloc_a_lot():
             i = 0
             while i < 10:
@@ -145,12 +211,15 @@
                     j += 1
                     a.append(j)
             return 0
-        run, statistics = self.runner(malloc_a_lot, statistics=True)
+        return malloc_a_lot
+
+    def test_llinterp_lists(self):
+        run, statistics = self.runner("llinterp_lists", statistics=True)
         run([])
         heap_size = self.heap_usage(statistics)
         assert heap_size < 16000 * INT_SIZE / 4 # xxx
 
-    def test_llinterp_tuples(self):
+    def define_llinterp_tuples(cls):
         def malloc_a_lot():
             i = 0
             while i < 10:
@@ -162,41 +231,51 @@
                     j += 1
                     b.append((1, j, i))
             return 0
-        run, statistics = self.runner(malloc_a_lot, statistics=True)
+        return malloc_a_lot
+
+    def test_llinterp_tuples(self):
+        run, statistics = self.runner("llinterp_tuples", statistics=True)
         run([])
         heap_size = self.heap_usage(statistics)
         assert heap_size < 16000 * INT_SIZE / 4 # xxx
 
-    def test_global_list(self):
+    def skipdefine_global_list(cls):
+        gl = []
         class Box:
             def __init__(self):
-                self.lst = []
+                self.lst = gl
         box = Box()
         def append_to_list(i, j):
             box.lst.append([i] * 50)
             llop.gc__collect(lltype.Void)
             return box.lst[j][0]
-        run = self.runner(append_to_list, nbargs=2)
+        return append_to_list, None, None
+
+    def test_global_list(self):
+        py.test.skip("doesn't fit in the model, tested elsewhere too")
+        run = self.runner("global_list")
         res = run([0, 0])
         assert res == 0
         for i in range(1, 5):
             res = run([i, i - 1])
             assert res == i - 1 # crashes if constants are not considered roots
             
-    def test_string_concatenation(self):
-
+    def define_string_concatenation(cls):
         def concat(j, dummy):
             lst = []
             for i in range(j):
                 lst.append(str(i))
             return len("".join(lst))
-        run, statistics = self.runner(concat, nbargs=2, statistics=True)
+        return concat
+
+    def test_string_concatenation(self):
+        run, statistics = self.runner("string_concatenation", statistics=True)
         res = run([100, 0])
-        assert res == concat(100, 0)
+        assert res == len(''.join([str(x) for x in range(100)]))
         heap_size = self.heap_usage(statistics)
         assert heap_size < 16000 * INT_SIZE / 4 # xxx
 
-    def test_nongc_static_root(self):
+    def define_nongc_static_root(cls):
         T1 = lltype.GcStruct("C", ('x', lltype.Signed))
         T2 = lltype.Struct("C", ('p', lltype.Ptr(T1)))
         static = lltype.malloc(T2, immortal=True)
@@ -206,11 +285,16 @@
             static.p = t1
             llop.gc__collect(lltype.Void)
             return static.p.x
-        run = self.runner(f, nbargs=0)
+        def cleanup():
+            static.p = lltype.nullptr(T1)
+        return f, cleanup, None
+
+    def test_nongc_static_root(self):
+        run = self.runner("nongc_static_root")
         res = run([])
         assert res == 42
 
-    def test_finalizer(self):
+    def define_finalizer(cls):
         class B(object):
             pass
         b = B()
@@ -231,11 +315,14 @@
             llop.gc__collect(lltype.Void)
             llop.gc__collect(lltype.Void)
             return b.num_deleted
-        run = self.runner(f, nbargs=2)
+        return f
+
+    def test_finalizer(self):
+        run = self.runner("finalizer")
         res = run([5, 42]) #XXX pure lazyness here too
         assert res == 6
 
-    def test_finalizer_calls_malloc(self):
+    def define_finalizer_calls_malloc(cls):
         class B(object):
             pass
         b = B()
@@ -260,11 +347,14 @@
             llop.gc__collect(lltype.Void)
             llop.gc__collect(lltype.Void)
             return b.num_deleted
-        run = self.runner(f, nbargs=2)
+        return f
+
+    def test_finalizer_calls_malloc(self):
+        run = self.runner("finalizer_calls_malloc")
         res = run([5, 42]) #XXX pure lazyness here too
         assert res == 12
 
-    def test_finalizer_resurrects(self):
+    def define_finalizer_resurrects(cls):
         class B(object):
             pass
         b = B()
@@ -291,11 +381,14 @@
             llop.gc__collect(lltype.Void)
             llop.gc__collect(lltype.Void)
             return b.num_deleted * 10 + aid + 100 * (b.a is None)
-        run = self.runner(f, nbargs=2)
+        return f
+
+    def test_finalizer_resurrects(self):
+        run = self.runner("finalizer_resurrects")
         res = run([5, 42]) #XXX pure lazyness here too
         assert 160 <= res <= 165
 
-    def test_weakref(self):
+    def define_weakref(cls):
         import weakref, gc
         class A(object):
             pass
@@ -313,11 +406,14 @@
             llop.gc__collect(lltype.Void)
             result = result and (ref() is None)
             return result
-        run = self.runner(f)
+        return f
+
+    def test_weakref(self):
+        run = self.runner("weakref")
         res = run([])
         assert res
 
-    def test_weakref_to_object_with_finalizer(self):
+    def define_weakref_to_object_with_finalizer(cls):
         import weakref, gc
         class A(object):
             count = 0
@@ -334,11 +430,14 @@
             llop.gc__collect(lltype.Void)
             result = a.count == 1 and (ref() is None)
             return result
-        run = self.runner(f)
+        return f
+
+    def test_weakref_to_object_with_finalizer(self):
+        run = self.runner("weakref_to_object_with_finalizer")
         res = run([])
         assert res
 
-    def test_collect_during_collect(self):
+    def define_collect_during_collect(cls):
         class B(object):
             pass
         b = B()
@@ -370,14 +469,18 @@
             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
+            # NB print would create a static root!
+            llop.debug_print(lltype.Void, b.num_deleted_c)
             return b.num_deleted
-        run = self.runner(f, nbargs=2)
+        return f
+
+    def test_collect_during_collect(self):
+        run = self.runner("collect_during_collect")
         # runs collect recursively 4 times
         res = run([4, 42]) #XXX pure lazyness here too
         assert res == 12
 
-    def test_collect_0(self):
+    def define_collect_0(cls):
         def concat(j, dummy):
             lst = []
             for i in range(j):
@@ -386,11 +489,14 @@
             if we_are_translated():
                 llop.gc__collect(lltype.Void, 0)
             return result
-        run = self.runner(concat, nbargs=2)
+        return concat
+
+    def test_collect_0(self):
+        run = self.runner("collect_0")
         res = run([100, 0])
-        assert res == concat(100, 0)
+        assert res == len(''.join([str(x) for x in range(100)]))
 
-    def test_interior_ptrs(self):
+    def define_interior_ptrs(cls):
         from pypy.rpython.lltypesystem.lltype import Struct, GcStruct, GcArray
         from pypy.rpython.lltypesystem.lltype import Array, Signed, malloc
 
@@ -444,11 +550,14 @@
                     f6())
 
         assert func() == 111111
-        run = self.runner(func)
+        return func
+
+    def test_interior_ptrs(self):
+        run = self.runner("interior_ptrs")
         res = run([])
         assert res == 111111
 
-    def test_id(self):
+    def define_id(cls):
         class A(object):
             pass
         a1 = A()
@@ -464,19 +573,25 @@
             if id2 != compute_unique_id(a2): error += 2
             if id3 != compute_unique_id(a3): error += 4
             return error
-        run = self.runner(func)
+        return func
+
+    def test_id(self):
+        run = self.runner("id")
         res = run([])
         assert res == 0
 
-    def test_can_move(self):
+    def define_can_move(cls):
         TP = lltype.GcArray(lltype.Float)
         def func():
             return rgc.can_move(lltype.malloc(TP, 1))
-        run = self.runner(func)
+        return func
+
+    def test_can_move(self):
+        run = self.runner("can_move")
         res = run([])
         assert res == self.GC_CAN_MOVE
 
-    def test_malloc_nonmovable(self):
+    def define_malloc_nonmovable(cls):
         TP = lltype.GcArray(lltype.Char)
         def func():
             #try:
@@ -489,10 +604,13 @@
             #except Exception, e:
             #    return 2
 
-        run = self.runner(func)
+        return func
+    
+    def test_malloc_nonmovable(self):
+        run = self.runner("malloc_nonmovable")
         assert int(self.GC_CANNOT_MALLOC_NONMOVABLE) == run([])
 
-    def test_malloc_nonmovable_fixsize(self):
+    def define_malloc_nonmovable_fixsize(cls):
         S = lltype.GcStruct('S', ('x', lltype.Float))
         TP = lltype.GcStruct('T', ('s', lltype.Ptr(S)))
         def func():
@@ -506,10 +624,13 @@
             except Exception, e:
                 return 2
 
-        run = self.runner(func)
+        return func
+    
+    def test_malloc_nonmovable_fixsize(self):
+        run = self.runner("malloc_nonmovable_fixsize")
         assert run([]) == int(self.GC_CANNOT_MALLOC_NONMOVABLE)
 
-    def test_resizable_buffer(self):
+    def define_resizable_buffer(cls):
         from pypy.rpython.lltypesystem.rstr import STR
         from pypy.rpython.annlowlevel import hlstr
 
@@ -520,10 +641,13 @@
             ptr.chars[1] = 'b'
             return hlstr(rgc.finish_building_buffer(ptr, 2)) == "ab"
 
-        run = self.runner(f)
+        return f
+
+    def test_resizable_buffer(self):
+        run = self.runner("resizable_buffer")
         assert run([]) == 1
 
-    def test_string_builder_over_allocation(self):
+    def define_string_builder_over_allocation(cls):
         import gc
         def fn():
             s = StringBuilder(4)
@@ -535,79 +659,19 @@
             s.append_multiple_char('y', 1000)
             res = s.build()[1000]
             gc.collect()
-            return res
-        fn = self.runner(fn)
-        res = fn([])
-        assert res == 'y'
-
-    def test_tagged_simple(self):
-        class Unrelated(object):
-            pass
-
-        u = Unrelated()
-        u.x = UnboxedObject(47)
-        def fn(n):
-            rgc.collect() # check that a prebuilt tagged pointer doesn't explode
-            if n > 0:
-                x = BoxedObject(n)
-            else:
-                x = UnboxedObject(n)
-            u.x = x # invoke write barrier
-            rgc.collect()
-            return x.meth(100)
-        def func():
-            return fn(1000) + fn(-1000)
-        func = self.runner(func, taggedpointers=True)
-        res = func([])
-        assert res == fn(1000) + fn(-1000)
-
-    def test_tagged_prebuilt(self):
-
-        class F:
-            pass
-
-        f = F()
-        f.l = [UnboxedObject(10)]
-        def fn(n):
-            if n > 0:
-                x = BoxedObject(n)
-            else:
-                x = UnboxedObject(n)
-            f.l.append(x)
-            rgc.collect()
-            return f.l[-1].meth(100)
-        def func():
-            return fn(1000) ^ fn(-1000)
-        func = self.runner(func, taggedpointers=True)
-        res = func([])
-        assert res == fn(1000) ^ fn(-1000)
-
-from pypy.rlib.objectmodel import UnboxedValue
-
-class TaggedBase(object):
-    __slots__ = ()
-    def meth(self, x):
-        raise NotImplementedError
-
-class BoxedObject(TaggedBase):
-    attrvalue = 66
-    def __init__(self, normalint):
-        self.normalint = normalint
-    def meth(self, x):
-        return self.normalint + x + 2
-
-class UnboxedObject(TaggedBase, UnboxedValue):
-    __slots__ = 'smallint'
-    def meth(self, x):
-        return self.smallint + x + 3
+            return ord(res)
+        return fn
 
+    def test_string_builder_over_allocation(self):
+        fn = self.runner("string_builder_over_allocation")
+        res = fn([])
+        assert res == ord('y')
 
 class GenericMovingGCTests(GenericGCTests):
     GC_CAN_MOVE = True
     GC_CANNOT_MALLOC_NONMOVABLE = True
 
-    def test_many_ids(self):
-        py.test.skip("fails for bad reasons in lltype.py :-(")
+    def define_many_ids(cls):
         class A(object):
             pass
         def f():
@@ -631,10 +695,30 @@
                     i += 1
                 j += 1
             lltype.free(idarray, flavor='raw')
-        run = self.runner(f)
+            return 0
+        return f
+    
+    def test_many_ids(self):
+        py.test.skip("fails for bad reasons in lltype.py :-(")
+        run = self.runner("many_ids")
         run([])
 
-    def test_do_malloc_operations(self):
+    @classmethod
+    def ensure_layoutbuilder(cls, translator):
+        jit2gc = getattr(translator, '_jit2gc', None)
+        if jit2gc:
+            return jit2gc['layoutbuilder']
+        GCClass = cls.gcpolicy.transformerclass.GCClass
+        lltype2vtable = translator.rtyper.lltype2vtable
+        layoutbuilder = framework.TransformerLayoutBuilder(GCClass,
+                                                               lltype2vtable)
+        layoutbuilder.delay_encoding()
+        translator._jit2gc = {
+            'layoutbuilder': layoutbuilder,
+        }
+        return layoutbuilder
+
+    def define_do_malloc_operations(cls):
         P = lltype.GcStruct('P', ('x', lltype.Signed))
         def g():
             r = lltype.malloc(P)
@@ -648,18 +732,13 @@
             while i < 40:
                 g()
                 i += 1
+            return 0
         def fix_graph_of_g(translator):
             from pypy.translator.translator import graphof
             from pypy.objspace.flow.model import Constant
             from pypy.rpython.lltypesystem import rffi
-            GCClass = self.gcpolicy.transformerclass.GCClass
-            lltype2vtable = translator.rtyper.lltype2vtable
-            layoutbuilder = framework.TransformerLayoutBuilder(GCClass,
-                                                               lltype2vtable)
-            layoutbuilder.delay_encoding()
-            translator._jit2gc = {
-                'layoutbuilder': layoutbuilder,
-                }
+            layoutbuilder = cls.ensure_layoutbuilder(translator)
+
             type_id = layoutbuilder.get_type_id(P)
             #
             # now fix the do_malloc_fixedsize_clear in the graph of g
@@ -674,10 +753,13 @@
                     break
             else:
                 assert 0, "oups, not found"
-        run = self.runner(f, mixlevelstuff=fix_graph_of_g)
+        return f, None, fix_graph_of_g
+            
+    def test_do_malloc_operations(self):
+        run = self.runner("do_malloc_operations")
         run([])
 
-    def test_do_malloc_operations_in_call(self):
+    def define_do_malloc_operations_in_call(cls):
         P = lltype.GcStruct('P', ('x', lltype.Signed))
         def g():
             llop.do_malloc_fixedsize_clear(llmemory.GCREF)  # placeholder
@@ -688,18 +770,12 @@
             while i < 40:
                 g()
                 i += q.x
+            return 0
         def fix_graph_of_g(translator):
             from pypy.translator.translator import graphof
             from pypy.objspace.flow.model import Constant
             from pypy.rpython.lltypesystem import rffi
-            GCClass = self.gcpolicy.transformerclass.GCClass
-            lltype2vtable = translator.rtyper.lltype2vtable
-            layoutbuilder = framework.TransformerLayoutBuilder(GCClass,
-                                                               lltype2vtable)
-            layoutbuilder.delay_encoding()
-            translator._jit2gc = {
-                'layoutbuilder': layoutbuilder,
-                }
+            layoutbuilder = cls.ensure_layoutbuilder(translator)            
             type_id = layoutbuilder.get_type_id(P)
             #
             # now fix the do_malloc_fixedsize_clear in the graph of g
@@ -714,9 +790,14 @@
                     break
             else:
                 assert 0, "oups, not found"
-        run = self.runner(f, mixlevelstuff=fix_graph_of_g)
+        return f, None, fix_graph_of_g
+        
+    def test_do_malloc_operations_in_call(self):
+        run = self.runner("do_malloc_operations_in_call")
         run([])
 
+# ________________________________________________________________
+
 class TestMarkSweepGC(GenericGCTests):
     gcname = "marksweep"
     class gcpolicy(gc.FrameworkGcPolicy):
@@ -725,7 +806,7 @@
             root_stack_depth = 200
 
 
-    def test_cloning(self):
+    def define_cloning(cls):
         B = lltype.GcStruct('B', ('x', lltype.Signed))
         A = lltype.GcStruct('A', ('b', lltype.Ptr(B)),
                                  ('unused', lltype.Ptr(B)))
@@ -755,11 +836,14 @@
             a2copy.b.x = 444
             return a1.b.x * 1000000 + a2.b.x * 1000 + a3.b.x
 
-        run = self.runner(func)
+        return func
+
+    def test_cloning(self):
+        run = self.runner("cloning")
         res = run([])
         assert res == 111222333
 
-    def test_cloning_varsize(self):
+    def define_cloning_varsize(cls):
         B = lltype.GcStruct('B', ('x', lltype.Signed))
         A = lltype.GcStruct('A', ('b', lltype.Ptr(B)),
                                  ('more', lltype.Array(lltype.Ptr(B))))
@@ -790,11 +874,14 @@
             a2copy.more[1].x = 441
             return a2.b.x * 1000000 + a2.more[0].x * 1000 + a2.more[1].x
 
-        run = self.runner(func)
+        return func
+
+    def test_cloning_varsize(self):
+        run = self.runner("cloning_varsize")
         res = run([])
         assert res == 22220221
 
-    def test_cloning_highlevel(self):
+    def define_cloning_highlevel(cls):
         class A:
             pass
         class B(A):
@@ -821,13 +908,16 @@
                 assert n > 5
             return 1
 
-        run = self.runner(func, nbargs=2)
+        return func
+
+    def test_cloning_highlevel(self):
+        run = self.runner("cloning_highlevel")
         res = run([3, 0])
         assert res == 1
         res = run([7, 0])
         assert res == 1
 
-    def test_cloning_highlevel_varsize(self):
+    def define_cloning_highlevel_varsize(cls):
         class A:
             pass
         def func(n, dummy):
@@ -849,11 +939,14 @@
                 n = n*10 + a.value
             return n
 
-        run = self.runner(func, nbargs=2)
+        return func
+
+    def test_cloning_highlevel_varsize(self):
+        run = self.runner("cloning_highlevel_varsize")
         res = run([3, 0])
         assert res == 456012789
 
-    def test_tree_cloning(self):
+    def define_tree_cloning(cls):
         import os
         # this makes a tree of calls.  Each leaf stores its path (a linked
         # list) in 'result'.  Paths are mutated in-place but the leaves don't
@@ -933,7 +1026,10 @@
                 check(result[i], i, 0, depth)
             os.write(2, 'ok\n')
             return 1
-        run = self.runner(func, nbargs=2)
+        return func
+
+    def test_tree_cloning(self):
+        run = self.runner("tree_cloning")
         res = run([3, 0])
         assert res == 1
 
@@ -959,6 +1055,9 @@
 class TestMarkCompactGC(GenericMovingGCTests):
     gcname = 'markcompact'
 
+    def setup_class(cls):
+        py.test.skip("Disabled for now, sorry")
+
     class gcpolicy(gc.FrameworkGcPolicy):
         class transformerclass(framework.FrameworkGCTransformer):
             from pypy.rpython.memory.gc.markcompact import MarkCompactGC as GCClass
@@ -976,7 +1075,7 @@
                          'nursery_size': 128}
             root_stack_depth = 200
 
-    def test_weakref_across_minor_collection(self):
+    def define_weakref_across_minor_collection(cls):
         import weakref
         class A:
             pass
@@ -994,11 +1093,14 @@
             llop.gc__collect(lltype.Void)
             assert ref() is a
             return a.foo + len(all)
-        run = self.runner(f)
+        return f
+
+    def test_weakref_across_minor_collection(self):
+        run = self.runner("weakref_across_minor_collection")
         res = run([])
         assert res == 20 + 20
 
-    def test_nongc_static_root_minor_collect(self):
+    def define_nongc_static_root_minor_collect(cls):
         T1 = lltype.GcStruct("C", ('x', lltype.Signed))
         T2 = lltype.Struct("C", ('p', lltype.Ptr(T1)))
         static = lltype.malloc(T2, immortal=True)
@@ -1015,12 +1117,17 @@
             i = static.p.x
             llop.gc__collect(lltype.Void)
             return static.p.x + i
-        run = self.runner(f, nbargs=0)
+        def cleanup():
+            static.p = lltype.nullptr(T1)        
+        return f, cleanup, None
+
+    def test_nongc_static_root_minor_collect(self):
+        run = self.runner("nongc_static_root_minor_collect")
         res = run([])
         assert res == 84
 
 
-    def test_static_root_minor_collect(self):
+    def define_static_root_minor_collect(cls):
         class A:
             pass
         class B:
@@ -1040,12 +1147,17 @@
             i = static.p.x
             llop.gc__collect(lltype.Void)
             return static.p.x + i
-        run = self.runner(f, nbargs=0)
+        def cleanup():
+            static.p = None
+        return f, cleanup, None
+
+    def test_static_root_minor_collect(self):
+        run = self.runner("static_root_minor_collect")
         res = run([])
         assert res == 84
 
 
-    def test_many_weakrefs(self):
+    def define_many_weakrefs(cls):
         # test for the case where allocating the weakref itself triggers
         # a collection
         import weakref
@@ -1058,10 +1170,15 @@
                 ref = weakref.ref(a)
                 assert ref() is a
                 i += 1
-        run = self.runner(f, nbargs=0)
+            return 0
+
+        return f
+        
+    def test_many_weakrefs(self):
+        run = self.runner("many_weakrefs")
         run([])
 
-    def test_immutable_to_old_promotion(self):
+    def define_immutable_to_old_promotion(cls):
         T_CHILD = lltype.Ptr(lltype.GcStruct('Child', ('field', lltype.Signed)))
         T_PARENT = lltype.Ptr(lltype.GcStruct('Parent', ('sub', T_CHILD)))
         child = lltype.malloc(T_CHILD.TO)
@@ -1083,7 +1200,10 @@
             #all[x] = lltype.nullptr(T_PARENT.TO)
             return res.sub.field
 
-        run, transformer = self.runner(f, nbargs=2, transformer=True)
+        return f
+
+    def test_immutable_to_old_promotion(self):
+        run, transformer = self.runner("immutable_to_old_promotion", transformer=True)
         run([1, 4])
         if not transformer.GCClass.prebuilt_gc_objects_are_static_roots:
             assert len(transformer.layoutbuilder.addresses_of_static_ptrs) == 0
@@ -1100,7 +1220,7 @@
         #  * the GcArray pointer from gc.wr_to_objects_with_id
         #  * the GcArray pointer from gc.object_id_dict.
 
-    def test_adr_of_nursery(self):
+    def define_adr_of_nursery(cls):
         class A(object):
             pass
         
@@ -1118,7 +1238,12 @@
             assert nf1 > nf0
             assert nt1 > nf1
             assert nt1 == nt0
-        run = self.runner(f, nbargs=0)
+            return 0
+        
+        return f
+    
+    def test_adr_of_nursery(self):
+        run = self.runner("adr_of_nursery")
         res = run([])        
 
 class TestGenerationalNoFullCollectGC(GCTest):
@@ -1139,11 +1264,15 @@
                 def semispace_collect(self, size_changing=False):
                     ll_assert(not self.__ready,
                               "no full collect should occur in this test")
+            def _teardown(self):
+                self.__ready = False # collecting here is expected
+                GenerationGC._teardown(self)
+                
             GC_PARAMS = {'space_size': 2048,
                          'nursery_size': 512}
             root_stack_depth = 200
 
-    def test_working_nursery(self):
+    def define_working_nursery(cls):
         def f():
             total = 0
             i = 0
@@ -1156,7 +1285,10 @@
                 total += len(lst)
                 i += 1
             return total
-        run = self.runner(f, nbargs=0)
+        return f
+
+    def test_working_nursery(self):
+        run = self.runner("working_nursery")
         res = run([])
         assert res == 40 * 5
 
@@ -1172,7 +1304,7 @@
                          'large_object': 32}
             root_stack_depth = 200
 
-    def test_ref_from_rawmalloced_to_regular(self):
+    def define_ref_from_rawmalloced_to_regular(cls):
         import gc
         S = lltype.GcStruct('S', ('x', lltype.Signed))
         A = lltype.GcStruct('A', ('p', lltype.Ptr(S)),
@@ -1190,11 +1322,14 @@
             lst = setup(j)
             gc.collect()
             return lst.p.x
-        run = self.runner(f, nbargs=2)
+        return f
+
+    def test_ref_from_rawmalloced_to_regular(self):
+        run = self.runner("ref_from_rawmalloced_to_regular")
         res = run([100, 100])
         assert res == 200
 
-    def test_assume_young_pointers(self):
+    def define_assume_young_pointers(cls):
         from pypy.rlib import rgc
         S = lltype.GcForwardReference()
         S.become(lltype.GcStruct('S',
@@ -1211,9 +1346,109 @@
             rgc.collect(0)
             return s0.next.x
 
-        run = self.runner(f, nbargs=0)
+        def cleanup():
+            s0.next = lltype.nullptr(S)
+
+        return f, cleanup, None
+
+    def test_assume_young_pointers(self):
+        run = self.runner("assume_young_pointers")
         res = run([])
         assert res == 42
 
     def test_malloc_nonmovable_fixsize(self):
         py.test.skip("not supported")
+
+# ________________________________________________________________
+# tagged pointers
+
+class TaggedPointerGCTests(GCTest):
+    taggedpointers = True
+
+    def define_tagged_simple(cls):
+        class Unrelated(object):
+            pass
+
+        u = Unrelated()
+        u.x = UnboxedObject(47)
+        def fn(n):
+            rgc.collect() # check that a prebuilt tagged pointer doesn't explode
+            if n > 0:
+                x = BoxedObject(n)
+            else:
+                x = UnboxedObject(n)
+            u.x = x # invoke write barrier
+            rgc.collect()
+            return x.meth(100)
+        def func():
+            return fn(1000) + fn(-1000)
+        assert func() == 205
+        return func
+
+    def test_tagged_simple(self):
+        func = self.runner("tagged_simple")
+        res = func([])
+        assert res == 205
+
+    def define_tagged_prebuilt(cls):
+
+        class F:
+            pass
+
+        f = F()
+        f.l = [UnboxedObject(10)]
+        def fn(n):
+            if n > 0:
+                x = BoxedObject(n)
+            else:
+                x = UnboxedObject(n)
+            f.l.append(x)
+            rgc.collect()
+            return f.l[-1].meth(100)
+        def func():
+            return fn(1000) ^ fn(-1000)
+        assert func() == -1999
+        return func
+
+    def test_tagged_prebuilt(self):
+        func = self.runner("tagged_prebuilt")
+        res = func([])
+        assert res == -1999
+
+from pypy.rlib.objectmodel import UnboxedValue
+
+class TaggedBase(object):
+    __slots__ = ()
+    def meth(self, x):
+        raise NotImplementedError
+
+class BoxedObject(TaggedBase):
+    attrvalue = 66
+    def __init__(self, normalint):
+        self.normalint = normalint
+    def meth(self, x):
+        return self.normalint + x + 2
+
+class UnboxedObject(TaggedBase, UnboxedValue):
+    __slots__ = 'smallint'
+    def meth(self, x):
+        return self.smallint + x + 3
+
+
+class TestMarkSweepTaggedPointerGC(TaggedPointerGCTests):
+    gcname = "marksweep"
+    class gcpolicy(gc.FrameworkGcPolicy):
+        class transformerclass(framework.FrameworkGCTransformer):
+            GC_PARAMS = {'start_heap_size': 4096 }
+            root_stack_depth = 200
+
+class TestHybridTaggedPointerGC(TaggedPointerGCTests):
+    gcname = "hybrid"
+
+    class gcpolicy(gc.FrameworkGcPolicy):
+        class transformerclass(framework.FrameworkGCTransformer):
+            from pypy.rpython.memory.gc.generation import GenerationGC as \
+                                                          GCClass
+            GC_PARAMS = {'space_size': 2048,
+                         'nursery_size': 128}
+            root_stack_depth = 200



More information about the Pypy-commit mailing list