PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/rpython/translator/test/test_exceptiontransform.py

https://bitbucket.org/pypy/pypy/
Python | 268 lines | 236 code | 24 blank | 8 comment | 26 complexity | 85504aba11cc53179e2657cce895368b MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import py
  2. from rpython.translator.translator import TranslationContext, graphof
  3. from rpython.translator.simplify import join_blocks
  4. from rpython.translator import exceptiontransform
  5. from rpython.flowspace.model import summary
  6. from rpython.rtyper.test.test_llinterp import get_interpreter
  7. from rpython.translator.backendopt.all import backend_optimizations
  8. from rpython.conftest import option
  9. import sys
  10. def check_debug_build():
  11. # the 'not option.view' is because debug builds rarely
  12. # have pygame, so if you want to see the graphs pass --view and
  13. # don't be surprised when the test then passes when it shouldn't.
  14. if not hasattr(sys, 'gettotalrefcount') and not option.view:
  15. py.test.skip("test needs a debug build of Python")
  16. _already_transformed = {}
  17. def interpret(func, values):
  18. interp, graph = get_interpreter(func, values)
  19. t = interp.typer.annotator.translator
  20. if t not in _already_transformed:
  21. etrafo = exceptiontransform.ExceptionTransformer(t)
  22. etrafo.transform_completely()
  23. _already_transformed[t] = True
  24. return interp.eval_graph(graph, values)
  25. class TestExceptionTransform:
  26. def compile(self, fn, inputargs):
  27. from rpython.translator.c.test.test_genc import compile
  28. return compile(fn, inputargs)
  29. def transform_func(self, fn, inputtypes, backendopt=False):
  30. t = TranslationContext()
  31. t.buildannotator().build_types(fn, inputtypes)
  32. t.buildrtyper().specialize()
  33. if option.view:
  34. t.view()
  35. if backendopt:
  36. backend_optimizations(t)
  37. g = graphof(t, fn)
  38. etrafo = exceptiontransform.ExceptionTransformer(t)
  39. etrafo.create_exception_handling(g)
  40. join_blocks(g)
  41. if option.view:
  42. t.view()
  43. return t, g
  44. def test_simple(self):
  45. def one():
  46. return 1
  47. def foo():
  48. one()
  49. return one()
  50. t, g = self.transform_func(foo, [])
  51. assert len(list(g.iterblocks())) == 2 # graph does not change
  52. result = interpret(foo, [])
  53. assert result == 1
  54. f = self.compile(foo, [])
  55. assert f() == 1
  56. def test_passthrough(self):
  57. def one(x):
  58. if x:
  59. raise ValueError()
  60. def foo():
  61. one(0)
  62. one(1)
  63. t, g = self.transform_func(foo, [])
  64. f = self.compile(foo, [])
  65. f(expected_exception_name='ValueError')
  66. def test_catches(self):
  67. def one(x):
  68. if x == 1:
  69. raise ValueError()
  70. elif x == 2:
  71. raise TypeError()
  72. return x - 5
  73. def foo(x):
  74. x = one(x)
  75. try:
  76. x = one(x)
  77. except ValueError:
  78. return 1 + x
  79. except TypeError:
  80. return 2 + x
  81. except:
  82. return 3 + x
  83. return 4 + x
  84. t, g = self.transform_func(foo, [int])
  85. assert len(list(g.iterblocks())) == 10
  86. f = self.compile(foo, [int])
  87. result = interpret(foo, [6])
  88. assert result == 2
  89. result = f(6)
  90. assert result == 2
  91. result = interpret(foo, [7])
  92. assert result == 4
  93. result = f(7)
  94. assert result == 4
  95. result = interpret(foo, [8])
  96. assert result == 2
  97. result = f(8)
  98. assert result == 2
  99. def test_bare_except(self):
  100. def one(x):
  101. if x == 1:
  102. raise ValueError()
  103. elif x == 2:
  104. raise TypeError()
  105. return x - 5
  106. def foo(x):
  107. x = one(x)
  108. try:
  109. x = one(x)
  110. except:
  111. return 1 + x
  112. return 4 + x
  113. t, g = self.transform_func(foo, [int])
  114. assert len(list(g.iterblocks())) == 6
  115. f = self.compile(foo, [int])
  116. result = interpret(foo, [6])
  117. assert result == 2
  118. result = f(6)
  119. assert result == 2
  120. result = interpret(foo, [7])
  121. assert result == 3
  122. result = f(7)
  123. assert result == 3
  124. result = interpret(foo, [8])
  125. assert result == 2
  126. result = f(8)
  127. assert result == 2
  128. def test_raises(self):
  129. def foo(x):
  130. if x:
  131. raise ValueError()
  132. t, g = self.transform_func(foo, [int])
  133. assert len(list(g.iterblocks())) == 3
  134. f = self.compile(foo, [int])
  135. f(0)
  136. f(1, expected_exception_name='ValueError')
  137. def test_no_multiple_transform(self):
  138. def f(x):
  139. return x + 1
  140. t = TranslationContext()
  141. t.buildannotator().build_types(f, [int])
  142. t.buildrtyper().specialize()
  143. g = graphof(t, f)
  144. etrafo = exceptiontransform.ExceptionTransformer(t)
  145. etrafo.create_exception_handling(g)
  146. etrafo2 = exceptiontransform.ExceptionTransformer(t)
  147. py.test.raises(AssertionError, etrafo2.create_exception_handling, g)
  148. def test_preserve_can_raise(self):
  149. def f(x):
  150. raise ValueError
  151. t = TranslationContext()
  152. t.buildannotator().build_types(f, [int])
  153. t.buildrtyper().specialize()
  154. g = graphof(t, f)
  155. etrafo = exceptiontransform.ExceptionTransformer(t)
  156. etrafo.create_exception_handling(g)
  157. assert etrafo.raise_analyzer.analyze_direct_call(g)
  158. def test_reraise_is_not_raise(self):
  159. def one(x):
  160. if x == 1:
  161. raise ValueError()
  162. elif x == 2:
  163. raise TypeError()
  164. return x - 5
  165. def foo(x):
  166. try:
  167. return one(x)
  168. except ValueError:
  169. return -42
  170. t, g = self.transform_func(foo, [int])
  171. for block in g.iterblocks():
  172. for op in block.operations:
  173. # the operation 'debug_record_traceback' should only show up
  174. # in a normal raise, not in a reraise
  175. assert op.opname != 'debug_record_traceback'
  176. f = self.compile(foo, [int])
  177. result = interpret(foo, [7])
  178. assert result == 2
  179. result = f(7)
  180. assert result == 2
  181. result = interpret(foo, [1])
  182. assert result == -42
  183. result = f(1)
  184. assert result == -42
  185. def test_needs_keepalive(self):
  186. check_debug_build()
  187. from rpython.rtyper.lltypesystem import lltype
  188. X = lltype.GcStruct("X",
  189. ('y', lltype.Struct("Y", ('z', lltype.Signed))))
  190. def can_raise(n):
  191. if n:
  192. raise Exception
  193. else:
  194. return 1
  195. def foo(n):
  196. x = lltype.malloc(X)
  197. y = x.y
  198. y.z = 42
  199. r = can_raise(n)
  200. return r + y.z
  201. f = self.compile(foo, [int])
  202. res = f(0)
  203. assert res == 43
  204. def test_inserting_zeroing_op(self):
  205. from rpython.rtyper.lltypesystem import lltype
  206. S = lltype.GcStruct("S", ('x', lltype.Signed))
  207. def f(x):
  208. s = lltype.malloc(S)
  209. s.x = 0
  210. return s.x
  211. t = TranslationContext()
  212. t.buildannotator().build_types(f, [int])
  213. t.buildrtyper().specialize()
  214. g = graphof(t, f)
  215. etrafo = exceptiontransform.ExceptionTransformer(t)
  216. etrafo.create_exception_handling(g)
  217. ops = dict.fromkeys([o.opname for b, o in g.iterblockops()])
  218. assert 'zero_gc_pointers_inside' in ops
  219. def test_llexternal(self):
  220. from rpython.rtyper.lltypesystem.rffi import llexternal
  221. from rpython.rtyper.lltypesystem import lltype
  222. z = llexternal('z', [lltype.Signed], lltype.Signed)
  223. def f(x):
  224. y = -1
  225. if x > 0:
  226. y = z(x)
  227. return y + x
  228. t,g = self.transform_func(f, [int], True)
  229. # llexternals normally should not raise, the graph should have no exception
  230. # checking
  231. assert summary(g) == {'int_gt': 1, 'int_add': 1, 'direct_call': 1}
  232. def test_get_exception_addr(self):
  233. from rpython.rtyper.lltypesystem import lltype, llmemory
  234. from rpython.rtyper.lltypesystem.lloperation import llop
  235. def foo():
  236. # a bit hard to test, really
  237. a = llop.get_exception_addr(llmemory.Address)
  238. assert lltype.typeOf(a) is llmemory.Address
  239. a = llop.get_exc_value_addr(llmemory.Address)
  240. assert lltype.typeOf(a) is llmemory.Address
  241. return 42
  242. f = self.compile(foo, [])
  243. res = f()
  244. assert res == 42