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

arigo at codespeak.net arigo at codespeak.net
Sun Oct 12 11:25:59 CEST 2008


Author: arigo
Date: Sun Oct 12 11:25:57 2008
New Revision: 59013

Modified:
   pypy/dist/pypy/translator/backendopt/mallocv.py
   pypy/dist/pypy/translator/backendopt/test/test_mallocv.py
Log:
Start tests and work on exceptions.


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 11:25:57 2008
@@ -1,5 +1,6 @@
 from pypy.objspace.flow.model import Variable, Constant, Block, Link
 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.rpython.typesystem import getfunctionptr
 from pypy.rpython.lltypesystem import lltype
@@ -458,10 +459,21 @@
         block = currentframe.sourceblock
         self.specblock.exitswitch = self.rename_nonvirtual(block.exitswitch,
                                                            'exitswitch')
+        catch_exc = self.specblock.exitswitch == c_last_exception
         newlinks = []
         for link in block.exits:
-            targetnodes = {}
+            is_exc_link = catch_exc and link.exitcase is not None
+            if is_exc_link:
+                extravars = []
+                for attr in ['last_exception', 'last_exc_value']:
+                    v = getattr(link, attr)
+                    if isinstance(v, Variable):
+                        rtnode = RuntimeSpecNode(v, v.concretetype)
+                        self.setnode(v, rtnode)
+                        self.renamings[rtnode] = v = rtnode.newvar()
+                    extravars.append(v)
 
+            targetnodes = {}
             rtnodes = []
             for v1, v2 in zip(link.args, link.target.inputargs):
                 node = self.getnode(v1)
@@ -494,7 +506,10 @@
             linkargs = [self.renamings[rtnode] for rtnode in rtnodes]
             newlink = Link(linkargs, specblock)
             newlink.exitcase = link.exitcase
-            newlink.llexitcase = link.llexitcase
+            if hasattr(link, 'llexitcase'):
+                newlink.llexitcase = link.llexitcase
+            if is_exc_link:
+                newlink.extravars(*extravars)
             newlinks.append(newlink)
         self.specblock.closeblock(*newlinks)
 
@@ -675,6 +690,10 @@
     # don't include the variables produced by the current or future operations
     for op in block.operations[index:]:
         seen[op.result] = True
+    # don't include the extra vars produced by exception-catching links
+    for link in block.exits:
+        for v in link.getextravars():
+            seen[v] = True
     # but include the variables consumed by the current or any future operation
     for op in block.operations[index:]:
         for v in op.args:

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 11:25:57 2008
@@ -1,4 +1,5 @@
 import py
+import sys
 from pypy.translator.backendopt.mallocv import MallocVirtualizer
 from pypy.translator.backendopt.inline import inline_function
 from pypy.translator.backendopt.all import backend_optimizations
@@ -6,12 +7,20 @@
 from pypy.translator import simplify
 from pypy.objspace.flow.model import checkgraph, flatten, Block, mkentrymap
 from pypy.objspace.flow.model import summary
-from pypy.rpython.llinterp import LLInterpreter
+from pypy.rpython.llinterp import LLInterpreter, LLException
 from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.rpython.ootypesystem import ootype
 from pypy.rlib import objectmodel
+from pypy.rlib.rarithmetic import ovfcheck
 from pypy.conftest import option
 
+DONT_CHECK_RESULT = object()
+class CHECK_RAISES:
+    def __init__(self, excname):
+        assert isinstance(excname, str)
+        self.excname = excname
+
+
 class BaseMallocRemovalTest(object):
     type_system = None
     MallocRemover = None
@@ -52,10 +61,15 @@
             if progress and option.view:
                 t.view()
             t.checkgraphs()
-            if expected_result is not Ellipsis:
+            if expected_result is not DONT_CHECK_RESULT:
                 interp = LLInterpreter(t.rtyper)
-                res = interp.eval_graph(graph, args)
-                assert res == expected_result
+                if not isinstance(expected_result, CHECK_RAISES):
+                    res = interp.eval_graph(graph, args)
+                    assert res == expected_result
+                else:
+                    excinfo = py.test.raises(LLException,
+                                             interp.eval_graph, graph, args)
+                    assert expected_result.excname in str(excinfo.value)
             if not progress:
                 break
             maxiter -= 1
@@ -165,6 +179,110 @@
         graph = self.check(f, [int], [19], 42,
                            expected_calls=0)     # inlined
 
+    def test_catch_simple(self):
+        class A:
+            pass
+        class E(Exception):
+            def __init__(self, n):
+                self.n = n
+        def g(n):
+            if n < 0:
+                raise E(n)
+        def f(n):
+            a = A()
+            a.n = 10
+            try:
+                g(n)
+            except E, e:
+                a.n = e.n
+            return a.n
+        self.check(f, [int], [15], 10, expected_calls=1)
+        self.check(f, [int], [-15], -15, expected_calls=1)
+
+    def test_raise_catch(self):
+        class A:
+            pass
+        class E(Exception):
+            def __init__(self, n):
+                self.n = n
+        def f(n):
+            a = A()
+            e1 = E(n)
+            try:
+                raise e1
+            except E, e:
+                a.n = e.n
+            return a.n
+        self.check(f, [int], [15], 15)
+
+    def test_raising_op(self):
+        class A:
+            pass
+        def f(n):
+            a = A()
+            a.n = n
+            try:
+                a.n = ovfcheck(a.n + 1)
+            except OverflowError:
+                return -42
+            return a.n
+        self.check(f, [int], [19], 20)
+        self.check(f, [int], [sys.maxint], -42)
+
+    def test_raises_through_spec_graph(self):
+        class A:
+            pass
+        def g(a):
+            if a.n < 0:
+                raise ValueError
+        def f(n):
+            a = A()
+            a.n = n
+            g(a)
+            return a.n
+        self.check(f, [int], [19], 19,
+                   expected_calls=1)
+        self.check(f, [int], [-19], CHECK_RAISES("ValueError"),
+                   expected_calls=1)
+
+    def test_raises_through_inlining(self):
+        py.test.skip("in-progress")
+        class A:
+            pass
+        def g(a):
+            a.n -= 1
+            if a.n < 0:
+                raise ValueError
+        def f(n):
+            a = A()
+            a.n = n
+            g(a)
+            return a.n
+        self.check(f, [int], [19], 18)
+        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):
+            a.n -= 1
+            if a.n <= 0:
+                raise StopIteration
+            return a.n * 10
+        def f(n):
+            a = A()
+            a.n = n
+            total = 0
+            try:
+                while True:
+                    total += g(a)
+            except StopIteration:
+                pass
+            return total
+        graph = self.check(f, [int], [11], 550,
+                           expected_calls=0)     # inlined
+
     def test_fn2(self):
         class T:
             pass
@@ -445,7 +563,7 @@
             x.u1.a = 3
             x.u2.b = 6
             return x.u1.b * x.u2.a
-        self.check(fn, [], [], Ellipsis)
+        self.check(fn, [], [], DONT_CHECK_RESULT)
 
     def test_keep_all_keepalives(self):
         py.test.skip("redo me")



More information about the Pypy-commit mailing list