[pypy-svn] r59039 - in pypy/dist/pypy/translator/backendopt: . test

arigo at codespeak.net arigo at codespeak.net
Sun Oct 12 18:33:59 CEST 2008


Author: arigo
Date: Sun Oct 12 18:33:57 2008
New Revision: 59039

Modified:
   pypy/dist/pypy/translator/backendopt/mallocv.py
   pypy/dist/pypy/translator/backendopt/test/test_mallocv.py
Log:
(pedronis, arigo)

Add a test.  Make the test fail in the right way, which took
several backtrackings.

We love our exception model!



Modified: pypy/dist/pypy/translator/backendopt/mallocv.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/mallocv.py	(original)
+++ pypy/dist/pypy/translator/backendopt/mallocv.py	Sun Oct 12 18:33:57 2008
@@ -2,6 +2,7 @@
 from pypy.objspace.flow.model import SpaceOperation, FunctionGraph, copygraph
 from pypy.objspace.flow.model import c_last_exception
 from pypy.translator.backendopt.support import log
+from pypy.translator.unsimplify import varoftype
 from pypy.rpython.typesystem import getfunctionptr
 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.lltypesystem.lloperation import llop
@@ -19,6 +20,7 @@
         self.check_no_destructor()
         self.names_and_types = []
         self.name2index = {}
+        self.name2subtype = {}
         self.initialize_type(MALLOCTYPE)
         #self.immutable_struct = MALLOCTYPE._hints.get('immutable')
 
@@ -42,6 +44,7 @@
             FIELDTYPE = TYPE._flds[name]
             self.name2index[name] = len(self.names_and_types)
             self.names_and_types.append((name, FIELDTYPE))
+            self.name2subtype[name] = TYPE
 
 
 class SpecNode(object):
@@ -206,6 +209,13 @@
         self.malloctypedescs = {}
         self.count_virtualized = 0
         self.verbose = verbose
+        self.EXCTYPE_to_vtable = self.build_obscure_mapping()
+
+    def build_obscure_mapping(self):
+        result = {}
+        for rinstance in self.rtyper.instance_reprs.values():
+            result[rinstance.lowleveltype.TO] = rinstance.rclass.getvtable()
+        return result
 
     def report_result(self):
         log.mallocv('removed %d mallocs so far' % (self.count_virtualized,))
@@ -383,15 +393,13 @@
         #
         if is_except(targetblock):
             v_expand_malloc = None
-            v_exc_type = renamings.get(nodelist[0])
             while currentframe.callerframe is not None:
                 currentframe = currentframe.callerframe
-                newlink = self.handle_catch(currentframe, v_exc_type,
-                                            renamings)
+                newlink = self.handle_catch(currentframe, nodelist, renamings)
                 if newlink:
                     return newlink
             else:
-                targetblock = self.exception_escapes(nodelist)
+                targetblock = self.exception_escapes(nodelist, renamings)
                 assert len(nodelist) == len(targetblock.inputargs)
 
         if (currentframe.callerframe is None and
@@ -424,16 +432,22 @@
                 callerframe.nodelist[i] = retnode
         return callerframe
 
-    def handle_catch(self, catchingframe, v_exc_type, renamings):
+    def handle_catch(self, catchingframe, nodelist, renamings):
         if not self.has_exception_catching(catchingframe):
             return None
-        if not isinstance(v_exc_type, Constant):
+        [exc_node, exc_value_node] = nodelist
+        v_exc_type = renamings.get(exc_node)
+        if isinstance(v_exc_type, Constant):
+            exc_type = v_exc_type.value
+        elif isinstance(exc_value_node, VirtualSpecNode):
+            EXCTYPE = exc_value_node.typedesc.MALLOCTYPE
+            exc_type = self.mallocv.EXCTYPE_to_vtable[EXCTYPE]
+        else:
             raise CannotVirtualize("raising non-constant exc type")
         excdata = self.mallocv.excdata
         assert catchingframe.sourceblock.exits[0].exitcase is None
         for catchlink in catchingframe.sourceblock.exits[1:]:
-            if excdata.fn_exception_match(v_exc_type.value,
-                                          catchlink.llexitcase):
+            if excdata.fn_exception_match(exc_type, catchlink.llexitcase):
                 # Match found.  Follow this link.
                 mynodes = catchingframe.get_nodes_in_use()
                 # XXX Constants
@@ -453,17 +467,79 @@
             assert 1 <= catchingframe.nextopindex <= len(operations)
             return catchingframe.nextopindex == len(operations)
 
-    def exception_escapes(self, nodelist):
+    def exception_escapes(self, nodelist, renamings):
         # the exception escapes
         if not is_trivial_nodelist(nodelist):
+            # start of hacks to help handle_catch()
+            [exc_node, exc_value_node] = nodelist
+            v_exc_type = renamings.get(exc_node)
+            if isinstance(v_exc_type, Constant):
+                # cannot improve: handle_catch() would already be happy
+                # by seeing the exc_type as a constant
+                pass
+            elif isinstance(exc_value_node, VirtualSpecNode):
+                # can improve with a strange hack: we pretend that
+                # the source code jumps to a block that itself allocates
+                # the exception, sets all fields, and raises it by
+                # passing a constant type.
+                typedesc = exc_value_node.typedesc
+                return self.get_exc_reconstruction_block(typedesc)
+            else:
+                # cannot improve: handle_catch() will have no clue about
+                # the exception type
+                pass
             raise CannotVirtualize("except block")
-            # ^^^ this could also be a ForcedInline, to try to match the
-            # exception raising and catching globally.  But it looks
-            # overkill for now.
         targetblock = self.graph.exceptblock
         self.mallocv.fixup_except_block(targetblock)
         return targetblock
 
+    def get_exc_reconstruction_block(self, typedesc):
+        exceptblock = self.graph.exceptblock
+        self.mallocv.fixup_except_block(exceptblock)
+        TEXC = exceptblock.inputargs[0].concretetype
+        TVAL = exceptblock.inputargs[1].concretetype
+        #
+        v_ignored_type = varoftype(TEXC)
+        v_incoming_value = varoftype(TVAL)
+        block = Block([v_ignored_type, v_incoming_value])
+        #
+        c_EXCTYPE = Constant(typedesc.MALLOCTYPE, lltype.Void)
+        v = varoftype(lltype.Ptr(typedesc.MALLOCTYPE))
+        c_flavor = Constant({'flavor': 'gc'}, lltype.Void)
+        op = SpaceOperation('malloc', [c_EXCTYPE, c_flavor], v)
+        block.operations.append(op)
+        #
+        for name, FIELDTYPE in typedesc.names_and_types:
+            EXACTPTR = lltype.Ptr(typedesc.name2subtype[name])
+            c_name = Constant(name)
+            c_name.concretetype = lltype.Void
+            #
+            v_in = varoftype(EXACTPTR)
+            op = SpaceOperation('cast_pointer', [v_incoming_value], v_in)
+            block.operations.append(op)
+            #
+            v_field = varoftype(FIELDTYPE)
+            op = SpaceOperation('getfield', [v_in, c_name], v_field)
+            block.operations.append(op)
+            #
+            v_out = varoftype(EXACTPTR)
+            op = SpaceOperation('cast_pointer', [v], v_out)
+            block.operations.append(op)
+            #
+            v0 = Variable()
+            v0.concretetype = lltype.Void
+            op = SpaceOperation('setfield', [v_out, c_name, v_field], v0)
+            block.operations.append(op)
+        #
+        v_exc_value = varoftype(TVAL)
+        op = SpaceOperation('cast_pointer', [v], v_exc_value)
+        block.operations.append(op)
+        #
+        exc_type = self.mallocv.EXCTYPE_to_vtable[typedesc.MALLOCTYPE]
+        c_exc_type = Constant(exc_type, TEXC)
+        block.closeblock(Link([c_exc_type, v_exc_value], exceptblock))
+        return block
+
     def get_specialized_block(self, virtualframe, v_expand_malloc=None):
         key = virtualframe.getfrozenkey()
         specblock = self.specialized_blocks.get(key)

Modified: pypy/dist/pypy/translator/backendopt/test/test_mallocv.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/test/test_mallocv.py	(original)
+++ pypy/dist/pypy/translator/backendopt/test/test_mallocv.py	Sun Oct 12 18:33:57 2008
@@ -273,7 +273,6 @@
         self.check(f, [int], [-19], CHECK_RAISES("ValueError"))
 
     def test_call_raise_catch(self):
-        #py.test.skip("in-progress")
         class A:
             pass
         def g(a):
@@ -294,6 +293,28 @@
         graph = self.check(f, [int], [11], 550,
                            expected_calls=0)     # inlined
 
+    def test_call_raise_catch_inspect(self):
+        py.test.skip("in-progress")
+        class A:
+            pass
+        class E(Exception):
+            def __init__(self, n):
+                self.n = n
+        def g(a):
+            a.n -= 1
+            if a.n < 0:
+                raise E(a.n * 10)
+        def f(n):
+            a = A()
+            a.n = n
+            try:
+                g(a)       # this call should be inlined
+            except E, e:
+                a.n = e.n
+            return a.n
+        self.check(f, [int], [15], 14, expected_calls=0)
+        self.check(f, [int], [-15], -160, expected_calls=0)
+
     def test_fn2(self):
         class T:
             pass



More information about the Pypy-commit mailing list