[pypy-svn] r27519 - in pypy/dist/pypy: rpython/lltypesystem rpython/memory/test translator/stackless

arigo at codespeak.net arigo at codespeak.net
Sat May 20 22:04:53 CEST 2006


Author: arigo
Date: Sat May 20 22:04:51 2006
New Revision: 27519

Modified:
   pypy/dist/pypy/rpython/lltypesystem/lloperation.py
   pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py
   pypy/dist/pypy/translator/stackless/transform.py
Log:
(pedronis, arigo)

Yikes!  The problem was about the stackless transform.  It contained a hard-coded
list of operations that can possibly unwind the stack.  Moreover, even if it knew
about the new gc_x_*() operations, the exception transform would kill the
UnwindException branch without a canraise=... in LLOp().  So we added a flag
'canraisegc=True' that prevents both things from going wrong.

test_tree_cloning passes now!  Cloning seems to be working well enough that we
can try to expose it to RPython and see.



Modified: pypy/dist/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lloperation.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/lloperation.py	Sat May 20 22:04:51 2006
@@ -7,7 +7,8 @@
 
 class LLOp(object):
 
-    def __init__(self, sideeffects=True, canfold=False, canraise=(), pyobj=False):
+    def __init__(self, sideeffects=True, canfold=False, canraise=(),
+                 pyobj=False, canunwindgc=False):
         # self.opname = ... (set afterwards)
 
         if canfold:
@@ -28,6 +29,13 @@
         # The operation manipulates PyObjects
         self.pyobj = pyobj
 
+        # The operation can unwind the stack in a stackless gc build
+        self.canunwindgc = canunwindgc
+        if canunwindgc:
+            if (StackException not in self.canraise and
+                Exception not in self.canraise):
+                self.canraise += (StackException,)
+
     # __________ make the LLOp instances callable from LL helpers __________
 
     __name__ = property(lambda self: 'llop_'+self.opname)
@@ -254,8 +262,8 @@
 
     # __________ pointer operations __________
 
-    'malloc':               LLOp(canraise=(MemoryError,)),
-    'malloc_varsize':       LLOp(canraise=(MemoryError,)),
+    'malloc':               LLOp(canraise=(MemoryError,), canunwindgc=True),
+    'malloc_varsize':       LLOp(canraise=(MemoryError,), canunwindgc=True),
     'flavored_malloc':      LLOp(canraise=(MemoryError,)),
     'flavored_free':        LLOp(),
     'getfield':             LLOp(sideeffects=False),
@@ -307,7 +315,7 @@
 
     # __________ GC operations __________
 
-    'gc__collect':          LLOp(canraise=(Exception,)),
+    'gc__collect':          LLOp(canunwindgc=True),
     'gc_free':              LLOp(),
     'gc_fetch_exception':   LLOp(),
     'gc_restore_exception': LLOp(),
@@ -319,21 +327,21 @@
     'gc_reload_possibly_moved': LLOp(),
     # experimental operations in support of thread cloning, only
     # implemented by the Mark&Sweep GC
-    'gc_x_swap_pool':       LLOp(canraise=(Exception,)),
-    'gc_x_clone':           LLOp(canraise=(Exception,)),
+    'gc_x_swap_pool':       LLOp(canraise=(MemoryError,), canunwindgc=True),
+    'gc_x_clone':           LLOp(canraise=(MemoryError,), canunwindgc=True),
     'gc_x_size_header':     LLOp(),
     # this one is even more experimental; only implemented with the
     # Mark&Sweep GC, and likely only useful when combined with
     # stackless:
-    'gc_x_become':          LLOp(canraise=(Exception,)),
+    'gc_x_become':          LLOp(canraise=(RuntimeError,), canunwindgc=True),
 
-    # NOTE NOTE NOTE! don't forget *** canraise=StackException *** or
-    # possibly Exception for anything that can unwind the stack, in
-    # particular anything that mallocs!
+    # NOTE NOTE NOTE! don't forget *** canunwindgc=True *** for anything that
+    # can go through a stack unwind, in particular anything that mallocs!
 
     # __________ stackless operation(s) __________
 
     'yield_current_frame_to_caller': LLOp(canraise=(StackException,)),
+    #                               can always unwind, not just if stackless gc
 
     # __________ misc operations __________
 

Modified: pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py	(original)
+++ pypy/dist/pypy/rpython/memory/test/test_transformed_gc.py	Sat May 20 22:04:51 2006
@@ -327,42 +327,17 @@
         res = run([])
         assert res == 111222333
 
-
-class TestStacklessMarkSweepGC(TestMarkSweepGC):
-
-    class gcpolicy(gc.StacklessFrameworkGcPolicy):
-        class transformerclass(gctransform.StacklessFrameworkGCTransformer):
-            GC_PARAMS = {'start_heap_size': 4096 }
-
-    def test_x_become(self):
-        py.test.skip('fails mysteriously')
-        S = lltype.GcStruct("S", ('x', lltype.Signed))
-        def f():
-            x = lltype.malloc(S)
-            x.x = 10
-            y = lltype.malloc(S)
-            y.x = 20
-            z = x
-            #llop.gc__collect(lltype.Void)
-            llop.gc_x_become(lltype.Void,
-                             llmemory.cast_ptr_to_adr(x),
-                             llmemory.cast_ptr_to_adr(y))
-            return z.x
-        run = self.runner(f)
-        res = run([])
-        # not implemented yet!
-        assert res == 20 
-
     def test_tree_cloning(self):
-        py.test.skip("aaaaaaaaaaaaaaaaaaaaaaargh later")
         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
         # see each other's mutations because of x_clone.
+        STUFF = lltype.FixedSizeArray(lltype.Signed, 21)
         NODE = lltype.GcForwardReference()
         NODE.become(lltype.GcStruct('node', ('index', lltype.Signed),
                                             ('counter', lltype.Signed),
-                                            ('next', lltype.Ptr(NODE))))
+                                            ('next', lltype.Ptr(NODE)),
+                                            ('use_some_space', STUFF)))
         PATHARRAY = lltype.GcArray(lltype.Ptr(NODE))
         clonedata = lltype.malloc(X_CLONE)
 
@@ -390,22 +365,23 @@
             # The above should have the same effect as:
             #    path = clone(path)
 
-            # bump all the path's counters by one
+            # bump all the path node counters by one
             p = path
             while p:
                 p.counter += 1
                 p = p.next
 
             if remaining_depth == 0:
+                llop.debug_print(lltype.Void, "setting", index, "with", path)
                 result[index] = path   # leaf
             else:
                 node = lltype.malloc(NODE)
                 node.index = index * 2
                 node.counter = 0
                 node.next = path
-                do_call(result, node, node.index, remaining_depth - 1)
+                do_call(result, node, index * 2, remaining_depth - 1)
                 node.index += 1    # mutation!
-                do_call(result, node, node.index, remaining_depth - 1)
+                do_call(result, node, index * 2 + 1, remaining_depth - 1)
 
             # restore the parent pool
             llop.gc_x_swap_pool(X_POOL_PTR, parentpool)
@@ -424,14 +400,43 @@
             os.write(2, 'building tree... ')
             do_call(result, lltype.nullptr(NODE), 0, depth)
             os.write(2, 'checking tree... ')
+            #from pypy.rpython.lltypesystem.lloperation import llop
+            #llop.debug_view(lltype.Void, result,
+            #                llop.gc_x_size_header(lltype.Signed))
             for i in range(1 << depth):
                 check(result[i], i, 0, depth)
             os.write(2, 'ok\n')
             return 1
         run = self.runner(func, nbargs=2)
-        res = run([5, 0])
+        res = run([3, 0])
         assert res == 1
 
+
+class TestStacklessMarkSweepGC(TestMarkSweepGC):
+
+    class gcpolicy(gc.StacklessFrameworkGcPolicy):
+        class transformerclass(gctransform.StacklessFrameworkGCTransformer):
+            GC_PARAMS = {'start_heap_size': 4096 }
+
+    def test_x_become(self):
+        py.test.skip('fails less mysteriously')
+        S = lltype.GcStruct("S", ('x', lltype.Signed))
+        def f():
+            x = lltype.malloc(S)
+            x.x = 10
+            y = lltype.malloc(S)
+            y.x = 20
+            z = x
+            #llop.gc__collect(lltype.Void)
+            llop.gc_x_become(lltype.Void,
+                             llmemory.cast_ptr_to_adr(x),
+                             llmemory.cast_ptr_to_adr(y))
+            return z.x
+        run = self.runner(f)
+        res = run([])
+        # not implemented yet!
+        assert res == 20 
+
 class TestSemiSpaceGC(TestMarkSweepGC):
 
     def setup_class(cls):

Modified: pypy/dist/pypy/translator/stackless/transform.py
==============================================================================
--- pypy/dist/pypy/translator/stackless/transform.py	(original)
+++ pypy/dist/pypy/translator/stackless/transform.py	Sat May 20 22:04:51 2006
@@ -1,4 +1,5 @@
 from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.lltypesystem.lloperation import LL_OPERATIONS
 from pypy.rpython import rarithmetic, rclass, rmodel
 from pypy.translator.backendopt import support
 from pypy.objspace.flow import model
@@ -97,9 +98,9 @@
         self.stackless_gc = stackless_gc
 
     def operation_is_true(self, op):
-        return (op.opname == 'yield_current_frame_to_caller' or
-                self.stackless_gc and (op.opname.startswith('malloc')
-                                       or op.opname == 'gc__collect'))
+        if op.opname == 'yield_current_frame_to_caller':
+            return True
+        return self.stackless_gc and LL_OPERATIONS[op.opname].canunwindgc
 
     def analyze_external_call(self, op):
         callable = op.args[0].value._obj._callable



More information about the Pypy-commit mailing list