PageRenderTime 103ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/translator/backendopt/test/test_writeanalyze.py

https://github.com/yasirs/pypy
Python | 406 lines | 339 code | 60 blank | 7 comment | 17 complexity | 4fad3ba2ff375660189b51ae4ee36b44 MD5 | raw file
  1. import py
  2. from pypy.rpython.lltypesystem import lltype
  3. from pypy.rpython.ootypesystem import ootype
  4. from pypy.translator.translator import TranslationContext, graphof
  5. from pypy.translator.simplify import get_funcobj
  6. from pypy.translator.backendopt.writeanalyze import WriteAnalyzer, top_set
  7. from pypy.translator.backendopt.writeanalyze import ReadWriteAnalyzer
  8. from pypy.translator.backendopt.all import backend_optimizations
  9. from pypy.conftest import option
  10. class BaseTest(object):
  11. type_system = None
  12. Analyzer = WriteAnalyzer
  13. def translate(self, func, sig):
  14. t = TranslationContext()
  15. t.buildannotator().build_types(func, sig)
  16. t.buildrtyper(type_system=self.type_system).specialize()
  17. if option.view:
  18. t.view()
  19. return t, self.Analyzer(t)
  20. class BaseTestWriteAnalyze(BaseTest):
  21. def test_writes_simple(self):
  22. def g(x):
  23. return True
  24. def f(x):
  25. return g(x - 1)
  26. t, wa = self.translate(f, [int])
  27. fgraph = graphof(t, f)
  28. result = wa.analyze(fgraph.startblock.operations[0])
  29. assert not result
  30. def test_writes_recursive(self):
  31. from pypy.translator.transform import insert_ll_stackcheck
  32. def g(x):
  33. return f(x)
  34. def f(x):
  35. if x:
  36. return g(x - 1)
  37. return 1
  38. t, wa = self.translate(f, [int])
  39. insert_ll_stackcheck(t)
  40. ggraph = graphof(t, g)
  41. result = wa.analyze(ggraph.startblock.operations[-1])
  42. assert not result
  43. def test_write_to_new_struct(self):
  44. class A(object):
  45. pass
  46. def f(x):
  47. a = A()
  48. a.baz = x # writes to a fresh new struct are ignored
  49. return a
  50. t, wa = self.translate(f, [int])
  51. fgraph = graphof(t, f)
  52. result = wa.analyze_direct_call(fgraph)
  53. assert not result
  54. def test_write_to_new_struct_2(self):
  55. class A(object):
  56. pass
  57. def f(x):
  58. a = A()
  59. # a few extra blocks
  60. i = 10
  61. while i > 0:
  62. i -= 1
  63. # done
  64. a.baz = x # writes to a fresh new struct are ignored
  65. return a
  66. t, wa = self.translate(f, [int])
  67. fgraph = graphof(t, f)
  68. result = wa.analyze_direct_call(fgraph)
  69. assert not result
  70. def test_write_to_new_struct_3(self):
  71. class A(object):
  72. pass
  73. prebuilt = A()
  74. def f(x):
  75. if x > 5:
  76. a = A()
  77. else:
  78. a = A()
  79. a.baz = x
  80. return a
  81. t, wa = self.translate(f, [int])
  82. fgraph = graphof(t, f)
  83. result = wa.analyze_direct_call(fgraph)
  84. assert not result
  85. def test_write_to_new_struct_4(self):
  86. class A(object):
  87. pass
  88. prebuilt = A()
  89. def f(x):
  90. if x > 5:
  91. a = A()
  92. else:
  93. a = prebuilt
  94. a.baz = x
  95. return a
  96. t, wa = self.translate(f, [int])
  97. fgraph = graphof(t, f)
  98. result = wa.analyze_direct_call(fgraph)
  99. assert len(result) == 1 and 'baz' in list(result)[0][-1]
  100. def test_write_to_new_struct_5(self):
  101. class A(object):
  102. baz = 123
  103. def f(x):
  104. if x:
  105. a = A()
  106. else:
  107. a = A()
  108. a.baz += 1
  109. t, wa = self.translate(f, [int])
  110. fgraph = graphof(t, f)
  111. result = wa.analyze_direct_call(fgraph)
  112. assert not result
  113. def test_method(self):
  114. class A(object):
  115. def f(self):
  116. self.x = 1
  117. return 1
  118. def m(self):
  119. raise ValueError
  120. class B(A):
  121. def f(self):
  122. return 2
  123. def m(self):
  124. return 3
  125. def f(a):
  126. return a.f()
  127. def m(a):
  128. return a.m()
  129. def h(flag):
  130. if flag:
  131. obj = A()
  132. else:
  133. obj = B()
  134. f(obj)
  135. m(obj)
  136. t, wa = self.translate(h, [int])
  137. hgraph = graphof(t, h)
  138. # fiiiish :-(
  139. block = hgraph.startblock.exits[0].target.exits[0].target
  140. op_call_f = block.operations[0]
  141. op_call_m = block.operations[1]
  142. # check that we fished the expected ops
  143. def check_call(op, fname):
  144. assert op.opname == "direct_call"
  145. assert get_funcobj(op.args[0].value)._name == fname
  146. check_call(op_call_f, "f")
  147. check_call(op_call_m, "m")
  148. result = wa.analyze(op_call_f)
  149. assert len(result) == 1
  150. (struct, T, name), = result
  151. assert struct == "struct"
  152. assert name.endswith("x")
  153. assert not wa.analyze(op_call_m)
  154. def test_instantiate(self):
  155. # instantiate is interesting, because it leads to one of the few cases of
  156. # an indirect call without a list of graphs
  157. from pypy.rlib.objectmodel import instantiate
  158. class A:
  159. pass
  160. class B(A):
  161. pass
  162. def g(x):
  163. if x:
  164. C = A
  165. else:
  166. C = B
  167. a = instantiate(C)
  168. def f(x):
  169. return g(x)
  170. t, wa = self.translate(f, [int])
  171. fgraph = graphof(t, f)
  172. result = wa.analyze(fgraph.startblock.operations[0])
  173. if self.type_system == 'lltype':
  174. assert result is top_set
  175. else:
  176. assert not result # ootype is more precise in this case
  177. def test_llexternal(self):
  178. from pypy.rpython.lltypesystem.rffi import llexternal
  179. from pypy.rpython.lltypesystem import lltype
  180. z = llexternal('z', [lltype.Signed], lltype.Signed)
  181. def f(x):
  182. return z(x)
  183. t, wa = self.translate(f, [int])
  184. fgraph = graphof(t, f)
  185. backend_optimizations(t)
  186. assert fgraph.startblock.operations[0].opname == 'direct_call'
  187. result = wa.analyze(fgraph.startblock.operations[0])
  188. assert not result
  189. def test_contains(self):
  190. def g(x, y, z):
  191. l = [x]
  192. return f(l, y, z)
  193. def f(x, y, z):
  194. return y in x
  195. t, wa = self.translate(g, [int, int, int])
  196. ggraph = graphof(t, g)
  197. assert ggraph.startblock.operations[-1].opname == 'direct_call'
  198. result = wa.analyze(ggraph.startblock.operations[-1])
  199. assert not result
  200. class TestLLtype(BaseTestWriteAnalyze):
  201. type_system = 'lltype'
  202. def test_list(self):
  203. def g(x, y, z):
  204. return f(x, y, z)
  205. def f(x, y, z):
  206. l = [0] * x
  207. l.append(y)
  208. return len(l) + z
  209. t, wa = self.translate(g, [int, int, int])
  210. ggraph = graphof(t, g)
  211. assert ggraph.startblock.operations[0].opname == 'direct_call'
  212. result = sorted(wa.analyze(ggraph.startblock.operations[0]))
  213. array, A = result[0]
  214. assert array == "array"
  215. assert A.TO.OF == lltype.Signed
  216. struct, S1, name = result[1]
  217. assert struct == "struct"
  218. assert S1.TO.items == A
  219. assert S1.TO.length == lltype.Signed
  220. assert name == "items"
  221. struct, S2, name = result[2]
  222. assert struct == "struct"
  223. assert name == "length"
  224. assert S1 is S2
  225. def test_llexternal_with_callback(self):
  226. from pypy.rpython.lltypesystem.rffi import llexternal
  227. from pypy.rpython.lltypesystem import lltype
  228. class Abc:
  229. pass
  230. abc = Abc()
  231. FUNC = lltype.FuncType([lltype.Signed], lltype.Signed)
  232. z = llexternal('z', [lltype.Ptr(FUNC)], lltype.Signed)
  233. def g(n):
  234. abc.foobar = n
  235. return n + 1
  236. def f(x):
  237. return z(g)
  238. t, wa = self.translate(f, [int])
  239. fgraph = graphof(t, f)
  240. backend_optimizations(t)
  241. assert fgraph.startblock.operations[0].opname == 'direct_call'
  242. result = wa.analyze(fgraph.startblock.operations[0])
  243. assert len(result) == 1
  244. (struct, T, name), = result
  245. assert struct == "struct"
  246. assert name.endswith("foobar")
  247. class TestOOtype(BaseTestWriteAnalyze):
  248. type_system = 'ootype'
  249. def test_array(self):
  250. def g(x, y, z):
  251. return f(x, y, z)
  252. def f(x, y, z):
  253. l = [0] * x
  254. l[1] = 42
  255. return len(l) + z
  256. t, wa = self.translate(g, [int, int, int])
  257. ggraph = graphof(t, g)
  258. assert ggraph.startblock.operations[0].opname == 'direct_call'
  259. result = sorted(wa.analyze(ggraph.startblock.operations[0]))
  260. assert len(result) == 1
  261. array, A = result[0]
  262. assert array == 'array'
  263. assert A.ITEM is ootype.Signed
  264. def test_list(self):
  265. def g(x, y, z):
  266. return f(x, y, z)
  267. def f(x, y, z):
  268. l = [0] * x
  269. l.append(z)
  270. return len(l) + z
  271. t, wa = self.translate(g, [int, int, int])
  272. ggraph = graphof(t, g)
  273. assert ggraph.startblock.operations[0].opname == 'direct_call'
  274. result = wa.analyze(ggraph.startblock.operations[0])
  275. assert result is top_set
  276. class TestLLtypeReadWriteAnalyze(BaseTest):
  277. Analyzer = ReadWriteAnalyzer
  278. type_system = 'lltype'
  279. def test_read_simple(self):
  280. def g(x):
  281. return True
  282. def f(x):
  283. return g(x - 1)
  284. t, wa = self.translate(f, [int])
  285. fgraph = graphof(t, f)
  286. result = wa.analyze(fgraph.startblock.operations[0])
  287. assert not result
  288. def test_read_really(self):
  289. class A(object):
  290. def __init__(self, y):
  291. self.y = y
  292. def f(self):
  293. self.x = 1
  294. return self.y
  295. def h(flag):
  296. obj = A(flag)
  297. return obj.f()
  298. t, wa = self.translate(h, [int])
  299. hgraph = graphof(t, h)
  300. op_call_f = hgraph.startblock.operations[-1]
  301. # check that we fished the expected ops
  302. assert op_call_f.opname == "direct_call"
  303. assert get_funcobj(op_call_f.args[0].value)._name == 'A.f'
  304. result = wa.analyze(op_call_f)
  305. assert len(result) == 2
  306. result = list(result)
  307. result.sort()
  308. [(struct1, T1, name1), (struct2, T2, name2)] = result
  309. assert struct1 == "readstruct"
  310. assert name1.endswith("y")
  311. assert struct2 == "struct"
  312. assert name2.endswith("x")
  313. assert T1 == T2
  314. def test_contains(self):
  315. def g(x, y, z):
  316. l = [x]
  317. return f(l, y, z)
  318. def f(x, y, z):
  319. return y in x
  320. t, wa = self.translate(g, [int, int, int])
  321. ggraph = graphof(t, g)
  322. assert ggraph.startblock.operations[-1].opname == 'direct_call'
  323. result = wa.analyze(ggraph.startblock.operations[-1])
  324. ARRAYPTR = list(result)[0][1]
  325. assert list(result) == [("readarray", ARRAYPTR)]
  326. assert isinstance(ARRAYPTR.TO, lltype.GcArray)
  327. def test_adt_method(self):
  328. def ll_callme(n):
  329. return n
  330. ll_callme = lltype.staticAdtMethod(ll_callme)
  331. S = lltype.GcStruct('S', ('x', lltype.Signed),
  332. adtmeths = {'yep': True,
  333. 'callme': ll_callme})
  334. def g(p, x, y, z):
  335. p.x = x
  336. if p.yep:
  337. z *= p.callme(y)
  338. return z
  339. def f(x, y, z):
  340. p = lltype.malloc(S)
  341. return g(p, x, y, z)
  342. t, wa = self.translate(f, [int, int, int])
  343. fgraph = graphof(t, f)
  344. assert fgraph.startblock.operations[-1].opname == 'direct_call'
  345. result = wa.analyze(fgraph.startblock.operations[-1])
  346. assert list(result) == [("struct", lltype.Ptr(S), "x")]