PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/translator/backendopt/test/test_canraise.py

https://bitbucket.org/pypy/pypy/
Python | 255 lines | 216 code | 26 blank | 13 comment | 15 complexity | be4d6d870312971b0cd9e4b2d408ea2c MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from rpython.translator.translator import TranslationContext, graphof
  2. from rpython.translator.backendopt.canraise import RaiseAnalyzer
  3. from rpython.translator.backendopt.all import backend_optimizations
  4. from rpython.conftest import option
  5. class TestCanRaise(object):
  6. def translate(self, func, sig):
  7. t = TranslationContext()
  8. t.buildannotator().build_types(func, sig)
  9. t.buildrtyper().specialize()
  10. if option.view:
  11. t.view()
  12. return t, RaiseAnalyzer(t)
  13. def test_can_raise_simple(self):
  14. def g(x):
  15. return True
  16. def f(x):
  17. return g(x - 1)
  18. t, ra = self.translate(f, [int])
  19. fgraph = graphof(t, f)
  20. result = ra.can_raise(fgraph.startblock.operations[0])
  21. assert not result
  22. def test_can_raise_recursive(self):
  23. from rpython.translator.transform import insert_ll_stackcheck
  24. def g(x):
  25. return f(x)
  26. def f(x):
  27. if x:
  28. return g(x - 1)
  29. return 1
  30. t, ra = self.translate(f, [int])
  31. insert_ll_stackcheck(t)
  32. ggraph = graphof(t, g)
  33. result = ra.can_raise(ggraph.startblock.operations[-1])
  34. assert result # due to stack check every recursive function can raise
  35. def test_bug_graphanalyze_recursive(self):
  36. # intentionally don't insert stack checks. the test shows a problem
  37. # with using the graph analyzer on recursive functions that is indepent
  38. # of the fact that recursive functions always happen to raise
  39. def g(x):
  40. return f(x)
  41. def f(x):
  42. if x:
  43. if x % 2:
  44. return x
  45. raise ValueError
  46. return g(x - 1)
  47. t, ra = self.translate(f, [int])
  48. ggraph = graphof(t, g)
  49. fgraph = graphof(t, f)
  50. result = ra.can_raise(ggraph.startblock.operations[-1]) # the call to f
  51. assert result
  52. result = ra.can_raise(fgraph.startblock.exits[0].target.operations[-1]) # the call to g
  53. assert result
  54. def test_recursive_cannot_raise(self):
  55. # intentionally don't insert stack checks. The goal is to verify
  56. # the graph analyzer, which should return "no" on such a recursion.
  57. def g(x):
  58. return f(x)
  59. def f(x):
  60. if x:
  61. if x % 2:
  62. return x
  63. return 42
  64. return g(x - 1)
  65. t, ra = self.translate(f, [int])
  66. ggraph = graphof(t, g)
  67. fgraph = graphof(t, f)
  68. result = ra.can_raise(ggraph.startblock.operations[-1]) # the call to f
  69. assert not result
  70. result = ra.can_raise(fgraph.startblock.exits[0].target.operations[-1]) # the call to g
  71. assert not result
  72. def test_can_raise_exception(self):
  73. def g():
  74. raise ValueError
  75. def f():
  76. return g()
  77. t, ra = self.translate(f, [])
  78. fgraph = graphof(t, f)
  79. result = ra.can_raise(fgraph.startblock.operations[0])
  80. assert result
  81. def test_indirect_call(self):
  82. def g1():
  83. raise ValueError
  84. def g2():
  85. return 2
  86. def f(x):
  87. if x:
  88. g = g1
  89. else:
  90. g = g2
  91. return g()
  92. def h(x):
  93. return f(x)
  94. t, ra = self.translate(h, [int])
  95. hgraph = graphof(t, h)
  96. result = ra.can_raise(hgraph.startblock.operations[0])
  97. assert result
  98. def test_method(self):
  99. class A(object):
  100. def f(self):
  101. return 1
  102. def m(self):
  103. raise ValueError
  104. class B(A):
  105. def f(self):
  106. return 2
  107. def m(self):
  108. return 3
  109. def f(a):
  110. return a.f()
  111. def m(a):
  112. return a.m()
  113. def h(flag):
  114. if flag:
  115. obj = A()
  116. else:
  117. obj = B()
  118. f(obj)
  119. m(obj)
  120. t, ra = self.translate(h, [int])
  121. hgraph = graphof(t, h)
  122. # fiiiish :-(
  123. block = hgraph.startblock.exits[0].target.exits[0].target
  124. op_call_f = block.operations[0]
  125. op_call_m = block.operations[1]
  126. # check that we fished the expected ops
  127. def check_call(op, fname):
  128. assert op.opname == "direct_call"
  129. assert op.args[0].value._obj._name == fname
  130. check_call(op_call_f, "f")
  131. check_call(op_call_m, "m")
  132. assert not ra.can_raise(op_call_f)
  133. assert ra.can_raise(op_call_m)
  134. def test_method_recursive(self):
  135. class A:
  136. def m(self, x):
  137. if x > 0:
  138. return self.m(x-1)
  139. else:
  140. return 42
  141. def m(a):
  142. return a.m(2)
  143. def h():
  144. obj = A()
  145. m(obj)
  146. t, ra = self.translate(h, [])
  147. hgraph = graphof(t, h)
  148. # fiiiish :-(
  149. block = hgraph.startblock
  150. op_call_m = block.operations[-1]
  151. assert op_call_m.opname == "direct_call"
  152. assert not ra.can_raise(op_call_m)
  153. def test_instantiate(self):
  154. # instantiate is interesting, because it leads to one of the few cases of
  155. # an indirect call without a list of graphs
  156. from rpython.rlib.objectmodel import instantiate
  157. class A:
  158. pass
  159. class B(A):
  160. pass
  161. def g(x):
  162. if x:
  163. C = A
  164. else:
  165. C = B
  166. a = instantiate(C)
  167. def f(x):
  168. return g(x)
  169. t, ra = self.translate(f, [int])
  170. fgraph = graphof(t, f)
  171. result = ra.can_raise(fgraph.startblock.operations[0])
  172. assert result
  173. def test_llexternal(self):
  174. from rpython.rtyper.lltypesystem.rffi import llexternal
  175. from rpython.rtyper.lltypesystem import lltype
  176. z = llexternal('z', [lltype.Signed], lltype.Signed)
  177. def f(x):
  178. return z(x)
  179. t, ra = self.translate(f, [int])
  180. fgraph = graphof(t, f)
  181. backend_optimizations(t)
  182. assert fgraph.startblock.operations[0].opname == 'direct_call'
  183. result = ra.can_raise(fgraph.startblock.operations[0])
  184. assert not result
  185. z = llexternal('z', [lltype.Signed], lltype.Signed)
  186. def g(x):
  187. return z(x)
  188. t, ra = self.translate(g, [int])
  189. ggraph = graphof(t, g)
  190. assert ggraph.startblock.operations[0].opname == 'direct_call'
  191. result = ra.can_raise(ggraph.startblock.operations[0])
  192. assert result
  193. def test_ll_arraycopy(self):
  194. from rpython.rtyper.lltypesystem import rffi
  195. from rpython.rlib.rgc import ll_arraycopy
  196. def f(a, b, c, d, e):
  197. ll_arraycopy(a, b, c, d, e)
  198. t, ra = self.translate(f, [rffi.CCHARP, rffi.CCHARP, int, int, int])
  199. fgraph = graphof(t, f)
  200. result = ra.can_raise(fgraph.startblock.operations[0])
  201. assert not result
  202. def test_memoryerror(self):
  203. def f(x):
  204. return [x, 42]
  205. t, ra = self.translate(f, [int])
  206. result = ra.analyze_direct_call(graphof(t, f))
  207. assert result
  208. #
  209. ra = RaiseAnalyzer(t)
  210. ra.do_ignore_memory_error()
  211. result = ra.analyze_direct_call(graphof(t, f))
  212. assert not result
  213. #
  214. def g(x):
  215. try:
  216. return f(x)
  217. except:
  218. raise
  219. t, ra = self.translate(g, [int])
  220. ra.do_ignore_memory_error()
  221. result = ra.analyze_direct_call(graphof(t, g))
  222. assert not result
  223. #
  224. def h(x):
  225. return {5:6}[x]
  226. t, ra = self.translate(h, [int])
  227. ra.do_ignore_memory_error() # but it's potentially a KeyError
  228. result = ra.analyze_direct_call(graphof(t, h))
  229. assert result