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

/rpython/memory/gctransform/test/test_framework.py

https://bitbucket.org/pypy/pypy/
Python | 396 lines | 385 code | 10 blank | 1 comment | 0 complexity | 863ce3d42a1b0ae5e21a3ad8776622c2 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from rpython.annotator.listdef import s_list_of_strings
  2. from rpython.annotator.model import SomeInteger
  3. from rpython.flowspace.model import Constant, SpaceOperation, mkentrymap
  4. from rpython.rtyper.lltypesystem import lltype, rffi
  5. from rpython.rtyper.lltypesystem.lloperation import llop
  6. from rpython.memory.gc.semispace import SemiSpaceGC
  7. from rpython.memory.gctransform.framework import (CollectAnalyzer,
  8. find_initializing_stores, find_clean_setarrayitems)
  9. from rpython.memory.gctransform.shadowstack import (
  10. ShadowStackFrameworkGCTransformer)
  11. from rpython.memory.gctransform.test.test_transform import rtype
  12. from rpython.memory.gctransform.transform import GcHighLevelOp
  13. from rpython.rtyper.rtyper import LowLevelOpList
  14. from rpython.translator.backendopt.all import backend_optimizations
  15. from rpython.translator.c.gc import BasicFrameworkGcPolicy
  16. from rpython.translator.exceptiontransform import ExceptionTransformer
  17. from rpython.translator.translator import TranslationContext, graphof
  18. from rpython.translator.unsimplify import varoftype
  19. import py
  20. class FrameworkGcPolicy2(BasicFrameworkGcPolicy):
  21. class transformerclass(ShadowStackFrameworkGCTransformer):
  22. root_stack_depth = 100
  23. def test_framework_simple():
  24. def g(x):
  25. return x + 1
  26. class A(object):
  27. pass
  28. def entrypoint(argv):
  29. a = A()
  30. a.b = g(1)
  31. return str(a.b)
  32. from rpython.rtyper.llinterp import LLInterpreter
  33. from rpython.translator.c.genc import CStandaloneBuilder
  34. t = rtype(entrypoint, [s_list_of_strings])
  35. t.config.translation.gc = "minimark"
  36. cbuild = CStandaloneBuilder(t, entrypoint, t.config,
  37. gcpolicy=FrameworkGcPolicy2)
  38. cbuild.make_entrypoint_wrapper = False
  39. db = cbuild.build_database()
  40. entrypointptr = cbuild.getentrypointptr()
  41. entrygraph = entrypointptr._obj.graph
  42. r_list_of_strings = t.rtyper.getrepr(s_list_of_strings)
  43. ll_argv = r_list_of_strings.convert_const([])
  44. llinterp = LLInterpreter(t.rtyper)
  45. # FIIIIISH
  46. setupgraph = db.gctransformer.frameworkgc_setup_ptr.value._obj.graph
  47. llinterp.eval_graph(setupgraph, [])
  48. res = llinterp.eval_graph(entrygraph, [ll_argv])
  49. assert ''.join(res.chars) == "2"
  50. def test_cancollect():
  51. S = lltype.GcStruct('S', ('x', lltype.Signed))
  52. def g():
  53. lltype.malloc(S, zero=True)
  54. t = rtype(g, [])
  55. gg = graphof(t, g)
  56. assert CollectAnalyzer(t).analyze_direct_call(gg)
  57. def g(x):
  58. return -x
  59. t = rtype(g, [int])
  60. gg = graphof(t, g)
  61. assert not CollectAnalyzer(t).analyze_direct_call(gg)
  62. def test_cancollect_external():
  63. fext1 = rffi.llexternal('fext1', [], lltype.Void, releasegil=False)
  64. def g():
  65. fext1()
  66. t = rtype(g, [])
  67. gg = graphof(t, g)
  68. assert not CollectAnalyzer(t).analyze_direct_call(gg)
  69. fext2 = rffi.llexternal('fext2', [], lltype.Void, releasegil=True)
  70. def g():
  71. fext2()
  72. t = rtype(g, [])
  73. gg = graphof(t, g)
  74. assert CollectAnalyzer(t).analyze_direct_call(gg)
  75. S = lltype.GcStruct('S', ('x', lltype.Signed))
  76. FUNC = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void))
  77. fext3 = rffi.llexternal('fext3', [FUNC], lltype.Void, releasegil=False)
  78. def h(x):
  79. lltype.malloc(S, zero=True)
  80. def g():
  81. fext3(h)
  82. t = rtype(g, [])
  83. gg = graphof(t, g)
  84. assert CollectAnalyzer(t).analyze_direct_call(gg)
  85. def test_no_collect():
  86. from rpython.rlib import rgc
  87. from rpython.translator.c.genc import CStandaloneBuilder
  88. @rgc.no_collect
  89. def g():
  90. return 1
  91. assert g._dont_inline_
  92. assert g._gc_no_collect_
  93. def entrypoint(argv):
  94. return g() + 2
  95. t = rtype(entrypoint, [s_list_of_strings])
  96. t.config.translation.gc = "minimark"
  97. cbuild = CStandaloneBuilder(t, entrypoint, t.config,
  98. gcpolicy=FrameworkGcPolicy2)
  99. cbuild.make_entrypoint_wrapper = False
  100. db = cbuild.build_database()
  101. def test_no_collect_detection():
  102. from rpython.rlib import rgc
  103. from rpython.translator.c.genc import CStandaloneBuilder
  104. class A(object):
  105. def __init__(self, x):
  106. self.x = x
  107. @rgc.no_collect
  108. def g():
  109. return A(1).x
  110. assert g._dont_inline_
  111. assert g._gc_no_collect_
  112. def entrypoint(argv):
  113. return g() + 2
  114. t = rtype(entrypoint, [s_list_of_strings])
  115. t.config.translation.gc = "minimark"
  116. cbuild = CStandaloneBuilder(t, entrypoint, t.config,
  117. gcpolicy=FrameworkGcPolicy2)
  118. cbuild.make_entrypoint_wrapper = False
  119. with py.test.raises(Exception) as f:
  120. cbuild.build_database()
  121. expected = "'no_collect' function can trigger collection: <function g at "
  122. assert str(f.value).startswith(expected)
  123. def test_custom_trace_function_no_collect():
  124. from rpython.rlib import rgc
  125. from rpython.translator.c.genc import CStandaloneBuilder
  126. S = lltype.GcStruct("MyStructure")
  127. class Glob:
  128. pass
  129. glob = Glob()
  130. def trace_func(gc, obj, callback, arg):
  131. glob.foo = (gc, obj)
  132. lambda_trace_func = lambda: trace_func
  133. def entrypoint(argv):
  134. lltype.malloc(S)
  135. rgc.register_custom_trace_hook(S, lambda_trace_func)
  136. return 0
  137. t = rtype(entrypoint, [s_list_of_strings])
  138. t.config.translation.gc = "minimark"
  139. cbuild = CStandaloneBuilder(t, entrypoint, t.config,
  140. gcpolicy=FrameworkGcPolicy2)
  141. cbuild.make_entrypoint_wrapper = False
  142. with py.test.raises(Exception) as f:
  143. cbuild.build_database()
  144. assert 'can cause the GC to be called' in str(f.value)
  145. assert 'trace_func' in str(f.value)
  146. assert 'MyStructure' in str(f.value)
  147. class WriteBarrierTransformer(ShadowStackFrameworkGCTransformer):
  148. clean_sets = {}
  149. GC_PARAMS = {}
  150. class GCClass(SemiSpaceGC):
  151. needs_write_barrier = True
  152. def writebarrier_before_copy(self, source, dest,
  153. source_start, dest_start, length):
  154. return True
  155. def write_barrier_check(spaceop, needs_write_barrier=True):
  156. t = TranslationContext()
  157. t.buildannotator().build_types(lambda x:x, [SomeInteger()])
  158. t.buildrtyper().specialize()
  159. transformer = WriteBarrierTransformer(t)
  160. llops = LowLevelOpList()
  161. hop = GcHighLevelOp(transformer, spaceop, 0, llops)
  162. hop.dispatch()
  163. found = False
  164. print spaceop, '======>'
  165. for op in llops:
  166. print '\t', op
  167. if op.opname == 'direct_call':
  168. found = True
  169. assert found == needs_write_barrier
  170. def test_write_barrier_support_setfield():
  171. PTR_TYPE2 = lltype.Ptr(lltype.GcStruct('T', ('y', lltype.Signed)))
  172. PTR_TYPE = lltype.Ptr(lltype.GcStruct('S', ('x', PTR_TYPE2)))
  173. write_barrier_check(SpaceOperation(
  174. "setfield",
  175. [varoftype(PTR_TYPE), Constant('x', lltype.Void),
  176. varoftype(PTR_TYPE2)],
  177. varoftype(lltype.Void)))
  178. def test_dont_add_write_barrier_for_constant_new_value():
  179. PTR_TYPE2 = lltype.Ptr(lltype.GcStruct('T', ('y', lltype.Signed)))
  180. PTR_TYPE = lltype.Ptr(lltype.GcStruct('S', ('x', PTR_TYPE2)))
  181. write_barrier_check(SpaceOperation(
  182. "setfield",
  183. [varoftype(PTR_TYPE), Constant('x', lltype.Void),
  184. Constant('foo', varoftype(PTR_TYPE2))],
  185. varoftype(lltype.Void)), needs_write_barrier=False)
  186. def test_write_barrier_support_setarrayitem():
  187. PTR_TYPE2 = lltype.Ptr(lltype.GcStruct('T', ('y', lltype.Signed)))
  188. ARRAYPTR = lltype.Ptr(lltype.GcArray(PTR_TYPE2))
  189. write_barrier_check(SpaceOperation(
  190. "setarrayitem",
  191. [varoftype(ARRAYPTR), varoftype(lltype.Signed),
  192. varoftype(PTR_TYPE2)],
  193. varoftype(lltype.Void)))
  194. def test_write_barrier_support_setinteriorfield():
  195. PTR_TYPE2 = lltype.Ptr(lltype.GcStruct('T', ('y', lltype.Signed)))
  196. ARRAYPTR2 = lltype.Ptr(lltype.GcArray(('a', lltype.Signed),
  197. ('b', PTR_TYPE2)))
  198. write_barrier_check(SpaceOperation(
  199. "setinteriorfield",
  200. [varoftype(ARRAYPTR2), varoftype(lltype.Signed),
  201. Constant('b', lltype.Void), varoftype(PTR_TYPE2)],
  202. varoftype(lltype.Void)))
  203. def test_remove_duplicate_write_barrier():
  204. from rpython.translator.c.genc import CStandaloneBuilder
  205. from rpython.flowspace.model import summary
  206. class A(object):
  207. pass
  208. glob_a_1 = A()
  209. glob_a_2 = A()
  210. def f(a, cond):
  211. a.x = a
  212. a.z = a
  213. if cond:
  214. a.y = a
  215. def g():
  216. f(glob_a_1, 5)
  217. f(glob_a_2, 0)
  218. t = rtype(g, [])
  219. t.config.translation.gc = "minimark"
  220. cbuild = CStandaloneBuilder(t, g, t.config,
  221. gcpolicy=FrameworkGcPolicy2)
  222. cbuild.make_entrypoint_wrapper = False
  223. db = cbuild.build_database()
  224. ff = graphof(t, f)
  225. #ff.show()
  226. assert summary(ff)['direct_call'] == 1 # only one remember_young_pointer
  227. def test_find_initializing_stores():
  228. class A(object):
  229. pass
  230. class B(object):
  231. pass
  232. def f():
  233. a = A()
  234. b = B()
  235. b.a = a
  236. b.b = 1
  237. t = rtype(f, [])
  238. etrafo = ExceptionTransformer(t)
  239. graphs = etrafo.transform_completely()
  240. collect_analyzer = CollectAnalyzer(t)
  241. init_stores = find_initializing_stores(collect_analyzer, t.graphs[0],
  242. mkentrymap(t.graphs[0]))
  243. assert len(init_stores) == 1
  244. def test_find_initializing_stores_across_blocks():
  245. class A(object):
  246. pass
  247. class B(object):
  248. pass
  249. def f(x):
  250. a1 = A()
  251. a2 = A()
  252. a = A()
  253. b = B()
  254. b.a = a
  255. if x:
  256. b.b = a1
  257. b.c = a2
  258. else:
  259. b.c = a1
  260. b.b = a2
  261. t = rtype(f, [int])
  262. etrafo = ExceptionTransformer(t)
  263. graphs = etrafo.transform_completely()
  264. collect_analyzer = CollectAnalyzer(t)
  265. init_stores = find_initializing_stores(collect_analyzer, t.graphs[0],
  266. mkentrymap(t.graphs[0]))
  267. assert len(init_stores) == 5
  268. def test_find_clean_setarrayitems():
  269. S = lltype.GcStruct('S')
  270. A = lltype.GcArray(lltype.Ptr(S))
  271. def f():
  272. l = lltype.malloc(A, 3)
  273. l[0] = lltype.malloc(S)
  274. l[1] = lltype.malloc(S)
  275. l[2] = lltype.malloc(S)
  276. x = l[1]
  277. l[0] = x
  278. return len(l)
  279. t = rtype(f, [])
  280. etrafo = ExceptionTransformer(t)
  281. graph = etrafo.transform_completely()
  282. collect_analyzer = CollectAnalyzer(t)
  283. clean_setarrayitems = find_clean_setarrayitems(collect_analyzer,
  284. t.graphs[0])
  285. assert len(clean_setarrayitems) == 1
  286. def test_find_clean_setarrayitems_2():
  287. S = lltype.GcStruct('S')
  288. A = lltype.GcArray(lltype.Ptr(S))
  289. def f():
  290. l = lltype.malloc(A, 3)
  291. l[0] = lltype.malloc(S)
  292. l[1] = lltype.malloc(S)
  293. l[2] = lltype.malloc(S)
  294. x = l[1]
  295. l[2] = lltype.malloc(S) # <- this can possibly collect
  296. l[0] = x
  297. return len(l)
  298. t = rtype(f, [])
  299. etrafo = ExceptionTransformer(t)
  300. graph = etrafo.transform_completely()
  301. collect_analyzer = CollectAnalyzer(t)
  302. clean_setarrayitems = find_clean_setarrayitems(collect_analyzer,
  303. t.graphs[0])
  304. assert len(clean_setarrayitems) == 0
  305. def test_find_clean_setarrayitems_3():
  306. S = lltype.GcStruct('S')
  307. A = lltype.GcArray(lltype.Ptr(S))
  308. def f():
  309. l = lltype.malloc(A, 3)
  310. l[0] = lltype.malloc(S)
  311. l[1] = lltype.malloc(S)
  312. l[2] = lltype.malloc(S)
  313. l2 = lltype.malloc(A, 4)
  314. x = l[1]
  315. l2[0] = x # <- different list
  316. return len(l)
  317. t = rtype(f, [])
  318. etrafo = ExceptionTransformer(t)
  319. graph = etrafo.transform_completely()
  320. collect_analyzer = CollectAnalyzer(t)
  321. clean_setarrayitems = find_clean_setarrayitems(collect_analyzer,
  322. t.graphs[0])
  323. assert len(clean_setarrayitems) == 0
  324. def test_list_operations():
  325. class A(object):
  326. pass
  327. def f():
  328. l = [A(), A()]
  329. l.append(A())
  330. l[1] = l[0]
  331. return len(l)
  332. t = rtype(f, [])
  333. backend_optimizations(t, clever_malloc_removal=False, storesink=True)
  334. etrafo = ExceptionTransformer(t)
  335. graph = etrafo.transform_completely()
  336. collect_analyzer = CollectAnalyzer(t)
  337. clean_setarrayitems = find_clean_setarrayitems(collect_analyzer,
  338. t.graphs[0])
  339. assert len(clean_setarrayitems) == 1