PageRenderTime 42ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/memory/gctransform/test/test_transform.py

https://bitbucket.org/pypy/pypy/
Python | 294 lines | 247 code | 39 blank | 8 comment | 50 complexity | 0172fc3a29151764eadc31aa73eaa815 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from rpython.memory.gctransform.transform import BaseGCTransformer
  2. from rpython.flowspace.model import Variable
  3. from rpython.translator.backendopt.support import var_needsgc
  4. from rpython.translator.translator import TranslationContext, graphof
  5. from rpython.translator.exceptiontransform import ExceptionTransformer
  6. from rpython.rtyper.lltypesystem import lltype
  7. from rpython.conftest import option
  8. from rpython.rtyper.rtyper import llinterp_backend
  9. class LLInterpedTranformerTests:
  10. def llinterpreter_for_transformed_graph(self, f, args_s):
  11. from rpython.rtyper.llinterp import LLInterpreter
  12. from rpython.translator.c.genc import CStandaloneBuilder
  13. t = rtype(f, args_s)
  14. # XXX we shouldn't need an actual gcpolicy here.
  15. cbuild = CStandaloneBuilder(t, f, t.config, gcpolicy=self.gcpolicy)
  16. cbuild.make_entrypoint_wrapper = False
  17. cbuild.build_database()
  18. graph = cbuild.getentrypointptr()._obj.graph
  19. # arguments cannot be GC objects because nobody would put a
  20. # proper header on them
  21. for v in graph.getargs():
  22. if isinstance(v.concretetype, lltype.Ptr):
  23. assert v.concretetype.TO._gckind != 'gc', "fix the test!"
  24. llinterp = LLInterpreter(t.rtyper)
  25. if option.view:
  26. t.view()
  27. return llinterp, graph
  28. def test_simple(self):
  29. from rpython.annotator.model import SomeInteger
  30. class C:
  31. pass
  32. c = C()
  33. c.x = 1
  34. def g(x):
  35. if x:
  36. return c
  37. else:
  38. d = C()
  39. d.x = 2
  40. return d
  41. def f(x):
  42. return g(x).x
  43. llinterp, graph = self.llinterpreter_for_transformed_graph(f, [SomeInteger()])
  44. res = llinterp.eval_graph(graph, [0])
  45. assert res == f(0)
  46. res = llinterp.eval_graph(graph, [1])
  47. assert res == f(1)
  48. def test_simple_varsize(self):
  49. from rpython.annotator.model import SomeInteger
  50. def f(x):
  51. r = []
  52. for i in range(x):
  53. if i % 2:
  54. r.append(x)
  55. return len(r)
  56. llinterp, graph = self.llinterpreter_for_transformed_graph(f, [SomeInteger()])
  57. res = llinterp.eval_graph(graph, [0])
  58. assert res == f(0)
  59. res = llinterp.eval_graph(graph, [10])
  60. assert res == f(10)
  61. def test_str(self):
  62. from rpython.annotator.model import SomeBool
  63. def f(flag):
  64. if flag:
  65. x = 'a'
  66. else:
  67. x = 'brrrrrrr'
  68. return len(x + 'a')
  69. llinterp, graph = self.llinterpreter_for_transformed_graph(f, [SomeBool()])
  70. res = llinterp.eval_graph(graph, [True])
  71. assert res == f(True)
  72. res = llinterp.eval_graph(graph, [False])
  73. assert res == f(False)
  74. class _TestGCTransformer(BaseGCTransformer):
  75. def push_alive(self, var, llops):
  76. llops.genop("gc_push_alive", [var])
  77. def pop_alive(self, var, llops):
  78. llops.genop("gc_pop_alive", [var])
  79. def checkblock(block, is_borrowed, is_start_block):
  80. if block.operations == ():
  81. # a return/exception block -- don't want to think about them
  82. # (even though the test passes for somewhat accidental reasons)
  83. return
  84. if is_start_block:
  85. refs_in = 0
  86. else:
  87. refs_in = len([v for v in block.inputargs if isinstance(v, Variable)
  88. and var_needsgc(v)
  89. and not is_borrowed(v)])
  90. push_alives = len([op for op in block.operations
  91. if op.opname == 'gc_push_alive'])
  92. gc_returning_calls = len([op for op in block.operations
  93. if op.opname in ('direct_call', 'indirect_call')
  94. and var_needsgc(op.result)])
  95. pop_alives = len([op for op in block.operations
  96. if op.opname == 'gc_pop_alive'])
  97. if pop_alives == len(block.operations):
  98. # it's a block we inserted
  99. return
  100. assert not block.canraise
  101. for link in block.exits:
  102. refs_out = 0
  103. for v2 in link.target.inputargs:
  104. if var_needsgc(v2) and not is_borrowed(v2):
  105. refs_out += 1
  106. pushes = push_alives + gc_returning_calls
  107. assert refs_in + pushes == pop_alives + refs_out
  108. def rtype(func, inputtypes, specialize=True):
  109. t = TranslationContext()
  110. t.buildannotator().build_types(func, inputtypes)
  111. rtyper = t.buildrtyper()
  112. rtyper.backend = llinterp_backend
  113. if specialize:
  114. rtyper.specialize()
  115. if option.view:
  116. t.view()
  117. return t
  118. def rtype_and_transform(func, inputtypes, transformcls, specialize=True, check=True):
  119. t = rtype(func, inputtypes, specialize)
  120. transformer = transformcls(t)
  121. etrafo = ExceptionTransformer(t)
  122. etrafo.transform_completely()
  123. graphs_borrowed = {}
  124. for graph in t.graphs[:]:
  125. graphs_borrowed[graph] = transformer.transform_graph(graph)
  126. if option.view:
  127. t.view()
  128. t.checkgraphs()
  129. if check:
  130. for graph, is_borrowed in graphs_borrowed.iteritems():
  131. for block in graph.iterblocks():
  132. checkblock(block, is_borrowed, block is graph.startblock)
  133. return t, transformer
  134. def getops(graph):
  135. ops = {}
  136. for block in graph.iterblocks():
  137. for op in block.operations:
  138. ops.setdefault(op.opname, []).append(op)
  139. return ops
  140. def test_simple():
  141. def f():
  142. return 1
  143. rtype_and_transform(f, [], _TestGCTransformer)
  144. def test_fairly_simple():
  145. class C:
  146. pass
  147. def f():
  148. c = C()
  149. c.x = 1
  150. return c.x
  151. t, transformer = rtype_and_transform(f, [], _TestGCTransformer)
  152. def test_return_gcpointer():
  153. class C:
  154. pass
  155. def f():
  156. c = C()
  157. c.x = 1
  158. return c
  159. t, transformer = rtype_and_transform(f, [], _TestGCTransformer)
  160. def test_call_function():
  161. class C:
  162. pass
  163. def f():
  164. c = C()
  165. c.x = 1
  166. return c
  167. def g():
  168. return f().x
  169. t, transformer = rtype_and_transform(g, [], _TestGCTransformer)
  170. ggraph = graphof(t, g)
  171. for i, op in enumerate(ggraph.startblock.operations):
  172. if op.opname == "direct_call":
  173. break
  174. else:
  175. assert False, "direct_call not found!"
  176. assert ggraph.startblock.operations[i + 1].opname != 'gc_push_alive'
  177. def test_multiply_passed_var():
  178. S = lltype.GcStruct("S", ('x', lltype.Signed))
  179. def f(x):
  180. if x:
  181. a = lltype.malloc(S)
  182. a.x = 1
  183. b = a
  184. else:
  185. a = lltype.malloc(S)
  186. a.x = 1
  187. b = lltype.malloc(S)
  188. b.x = 2
  189. return a.x + b.x
  190. t, transformer = rtype_and_transform(f, [int], _TestGCTransformer)
  191. def test_pass_gc_pointer():
  192. S = lltype.GcStruct("S", ('x', lltype.Signed))
  193. def f(s):
  194. s.x = 1
  195. def g():
  196. s = lltype.malloc(S)
  197. f(s)
  198. return s.x
  199. t, transformer = rtype_and_transform(g, [], _TestGCTransformer)
  200. def test_except_block():
  201. S = lltype.GcStruct("S", ('x', lltype.Signed))
  202. def f(a, n):
  203. if n == 0:
  204. raise ValueError
  205. a.x = 1
  206. return a
  207. def g(n):
  208. a = lltype.malloc(S)
  209. try:
  210. return f(a, n).x
  211. except ValueError:
  212. return 0
  213. t, transformer = rtype_and_transform(g, [int], _TestGCTransformer)
  214. def test_except_block2():
  215. # the difference here is that f() returns Void, not a GcStruct
  216. S = lltype.GcStruct("S", ('x', lltype.Signed))
  217. def f(a, n):
  218. if n == 0:
  219. raise ValueError
  220. a.x = 1
  221. def g(n):
  222. a = lltype.malloc(S)
  223. try:
  224. f(a, n)
  225. return a.x
  226. except ValueError:
  227. return 0
  228. t, transformer = rtype_and_transform(g, [int], _TestGCTransformer)
  229. def test_no_livevars_with_exception():
  230. def g():
  231. raise TypeError
  232. def f():
  233. try:
  234. g()
  235. except TypeError:
  236. return 0
  237. return 1
  238. t, transformer = rtype_and_transform(f, [], _TestGCTransformer)
  239. def test_bare_setfield():
  240. from rpython.rtyper.lltypesystem.lloperation import llop
  241. class A:
  242. def __init__(self, obj):
  243. self.x = obj
  244. class B:
  245. def __init__(self, i):
  246. self.i = i
  247. def f(i):
  248. v = B(i)
  249. inst = A(v)
  250. llop.setfield(lltype.Void, inst, 'x', v)
  251. llop.bare_setfield(lltype.Void, inst, 'x', v)
  252. t, transformer = rtype_and_transform(f, [int], _TestGCTransformer,
  253. check=False)
  254. ops = getops(graphof(t, f))
  255. # xxx no checking done any more