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

/pypy/jit/backend/llsupport/test/test_gc.py

https://bitbucket.org/pypy/pypy/
Python | 462 lines | 392 code | 39 blank | 31 comment | 25 complexity | a43b74401a212d402a62c15f171f3b2c MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import random
  2. from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr
  3. from pypy.rpython.lltypesystem.lloperation import llop
  4. from pypy.rpython.annlowlevel import llhelper
  5. from pypy.jit.backend.llsupport.descr import *
  6. from pypy.jit.backend.llsupport.gc import *
  7. from pypy.jit.backend.llsupport import symbolic
  8. from pypy.jit.metainterp.gc import get_description
  9. from pypy.jit.metainterp.history import BoxPtr, BoxInt, ConstPtr
  10. from pypy.jit.metainterp.resoperation import get_deep_immutable_oplist
  11. from pypy.jit.tool.oparser import parse
  12. from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
  13. from pypy.jit.metainterp.optimizeopt.util import equaloplists
  14. def test_boehm():
  15. gc_ll_descr = GcLLDescr_boehm(None, None, None)
  16. #
  17. record = []
  18. prev_malloc_fn_ptr = gc_ll_descr.malloc_fn_ptr
  19. def my_malloc_fn_ptr(size):
  20. p = prev_malloc_fn_ptr(size)
  21. record.append((size, p))
  22. return p
  23. gc_ll_descr.malloc_fn_ptr = my_malloc_fn_ptr
  24. #
  25. # ---------- gc_malloc ----------
  26. S = lltype.GcStruct('S', ('x', lltype.Signed))
  27. sizedescr = get_size_descr(gc_ll_descr, S)
  28. p = gc_ll_descr.gc_malloc(sizedescr)
  29. assert record == [(sizedescr.size, p)]
  30. del record[:]
  31. # ---------- gc_malloc_array ----------
  32. A = lltype.GcArray(lltype.Signed)
  33. arraydescr = get_array_descr(gc_ll_descr, A)
  34. p = gc_ll_descr.gc_malloc_array(arraydescr, 10)
  35. assert record == [(arraydescr.basesize +
  36. 10 * arraydescr.itemsize, p)]
  37. del record[:]
  38. # ---------- gc_malloc_str ----------
  39. p = gc_ll_descr.gc_malloc_str(10)
  40. basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR, False)
  41. assert record == [(basesize + 10 * itemsize, p)]
  42. del record[:]
  43. # ---------- gc_malloc_unicode ----------
  44. p = gc_ll_descr.gc_malloc_unicode(10)
  45. basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE,
  46. False)
  47. assert record == [(basesize + 10 * itemsize, p)]
  48. del record[:]
  49. # ____________________________________________________________
  50. class TestGcRootMapAsmGcc:
  51. def test_make_shapes(self):
  52. def frame_pos(n):
  53. return -4*(4+n)
  54. gcrootmap = GcRootMap_asmgcc()
  55. num1 = frame_pos(-5)
  56. num1a = num1|2
  57. num2 = frame_pos(55)
  58. num2a = ((-num2|3) >> 7) | 128
  59. num2b = (-num2|3) & 127
  60. shape = gcrootmap.get_basic_shape()
  61. gcrootmap.add_frame_offset(shape, num1)
  62. gcrootmap.add_frame_offset(shape, num2)
  63. assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a])
  64. gcrootmap.add_callee_save_reg(shape, 1)
  65. assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a,
  66. 4])
  67. gcrootmap.add_callee_save_reg(shape, 2)
  68. assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a,
  69. 4, 8])
  70. gcrootmap.add_callee_save_reg(shape, 3)
  71. assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a,
  72. 4, 8, 12])
  73. gcrootmap.add_callee_save_reg(shape, 4)
  74. assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a,
  75. 4, 8, 12, 16])
  76. def test_compress_callshape(self):
  77. class FakeDataBlockWrapper:
  78. def malloc_aligned(self, size, alignment):
  79. assert alignment == 1 # here
  80. assert size == 4
  81. return rffi.cast(lltype.Signed, p)
  82. datablockwrapper = FakeDataBlockWrapper()
  83. p = lltype.malloc(rffi.CArray(lltype.Char), 4, immortal=True)
  84. gcrootmap = GcRootMap_asmgcc()
  85. shape = ['a', 'b', 'c', 'd']
  86. gcrootmap.compress_callshape(shape, datablockwrapper)
  87. assert p[0] == 'd'
  88. assert p[1] == 'c'
  89. assert p[2] == 'b'
  90. assert p[3] == 'a'
  91. def test_put_basic(self):
  92. gcrootmap = GcRootMap_asmgcc()
  93. retaddr = 1234567890
  94. shapeaddr = 51627384
  95. gcrootmap.put(retaddr, shapeaddr)
  96. assert gcrootmap._gcmap[0] == retaddr
  97. assert gcrootmap._gcmap[1] == shapeaddr
  98. p = rffi.cast(rffi.LONGP, gcrootmap.gcmapstart())
  99. assert p[0] == retaddr
  100. assert (gcrootmap.gcmapend() ==
  101. gcrootmap.gcmapstart() + rffi.sizeof(lltype.Signed) * 2)
  102. def test_put_resize(self):
  103. # the same as before, but enough times to trigger a few resizes
  104. gcrootmap = GcRootMap_asmgcc()
  105. for i in range(700):
  106. shapeaddr = i * 100 + 1
  107. retaddr = 123456789 + i
  108. gcrootmap.put(retaddr, shapeaddr)
  109. for i in range(700):
  110. assert gcrootmap._gcmap[i*2+0] == 123456789 + i
  111. assert gcrootmap._gcmap[i*2+1] == i * 100 + 1
  112. def test_remove_nulls(self):
  113. expected = []
  114. def check():
  115. assert gcrootmap._gcmap_curlength == len(expected) * 2
  116. for i, (a, b) in enumerate(expected):
  117. assert gcrootmap._gcmap[i*2] == a
  118. assert gcrootmap._gcmap[i*2+1] == b
  119. #
  120. gcrootmap = GcRootMap_asmgcc()
  121. for i in range(700):
  122. shapeaddr = i * 100 # 0 if i == 0
  123. retaddr = 123456789 + i
  124. gcrootmap.put(retaddr, shapeaddr)
  125. if shapeaddr != 0:
  126. expected.append((retaddr, shapeaddr))
  127. # at the first resize, the 0 should be removed
  128. check()
  129. for repeat in range(10):
  130. # now clear up half the entries
  131. assert len(expected) == 699
  132. for i in range(0, len(expected), 2):
  133. gcrootmap._gcmap[i*2+1] = 0
  134. gcrootmap._gcmap_deadentries += 1
  135. expected = expected[1::2]
  136. assert gcrootmap._gcmap_deadentries*6 > gcrootmap._gcmap_maxlength
  137. # check that we can again insert 350 entries without a resize
  138. oldgcmap = gcrootmap._gcmap
  139. for i in range(0, 699, 2):
  140. gcrootmap.put(515151 + i + repeat, 626262 + i)
  141. expected.append((515151 + i + repeat, 626262 + i))
  142. assert gcrootmap._gcmap == oldgcmap
  143. check()
  144. def test_freeing_block(self):
  145. from pypy.jit.backend.llsupport import gc
  146. class Asmgcroot:
  147. arrayitemsize = 2 * llmemory.sizeof(llmemory.Address)
  148. sort_count = 0
  149. def sort_gcmap(self, gcmapstart, gcmapend):
  150. self.sort_count += 1
  151. def binary_search(self, gcmapstart, gcmapend, startaddr):
  152. i = 0
  153. while (i < gcrootmap._gcmap_curlength//2 and
  154. gcrootmap._gcmap[i*2] < startaddr):
  155. i += 1
  156. if i > 0:
  157. i -= 1
  158. assert 0 <= i < gcrootmap._gcmap_curlength//2
  159. p = rffi.cast(rffi.CArrayPtr(llmemory.Address), gcmapstart)
  160. p = rffi.ptradd(p, 2*i)
  161. return llmemory.cast_ptr_to_adr(p)
  162. saved = gc.asmgcroot
  163. try:
  164. gc.asmgcroot = Asmgcroot()
  165. #
  166. gcrootmap = GcRootMap_asmgcc()
  167. gcrootmap._gcmap = lltype.malloc(gcrootmap.GCMAP_ARRAY,
  168. 1400, flavor='raw',
  169. immortal=True)
  170. for i in range(700):
  171. gcrootmap._gcmap[i*2] = 1200000 + i
  172. gcrootmap._gcmap[i*2+1] = i * 100 + 1
  173. assert gcrootmap._gcmap_deadentries == 0
  174. assert gc.asmgcroot.sort_count == 0
  175. gcrootmap._gcmap_maxlength = 1400
  176. gcrootmap._gcmap_curlength = 1400
  177. gcrootmap._gcmap_sorted = False
  178. #
  179. gcrootmap.freeing_block(1200000 - 100, 1200000)
  180. assert gcrootmap._gcmap_deadentries == 0
  181. assert gc.asmgcroot.sort_count == 1
  182. #
  183. gcrootmap.freeing_block(1200000 + 100, 1200000 + 200)
  184. assert gcrootmap._gcmap_deadentries == 100
  185. assert gc.asmgcroot.sort_count == 1
  186. for i in range(700):
  187. if 100 <= i < 200:
  188. expected = 0
  189. else:
  190. expected = i * 100 + 1
  191. assert gcrootmap._gcmap[i*2] == 1200000 + i
  192. assert gcrootmap._gcmap[i*2+1] == expected
  193. #
  194. gcrootmap.freeing_block(1200000 + 650, 1200000 + 750)
  195. assert gcrootmap._gcmap_deadentries == 150
  196. assert gc.asmgcroot.sort_count == 1
  197. for i in range(700):
  198. if 100 <= i < 200 or 650 <= i:
  199. expected = 0
  200. else:
  201. expected = i * 100 + 1
  202. assert gcrootmap._gcmap[i*2] == 1200000 + i
  203. assert gcrootmap._gcmap[i*2+1] == expected
  204. #
  205. finally:
  206. gc.asmgcroot = saved
  207. class TestGcRootMapShadowStack:
  208. class FakeGcDescr:
  209. force_index_ofs = 92
  210. def test_make_shapes(self):
  211. gcrootmap = GcRootMap_shadowstack(self.FakeGcDescr())
  212. shape = gcrootmap.get_basic_shape()
  213. gcrootmap.add_frame_offset(shape, 16)
  214. gcrootmap.add_frame_offset(shape, -24)
  215. assert shape == [16, -24]
  216. def test_compress_callshape(self):
  217. class FakeDataBlockWrapper:
  218. def malloc_aligned(self, size, alignment):
  219. assert alignment == 4 # even on 64-bits
  220. assert size == 12 # 4*3, even on 64-bits
  221. return rffi.cast(lltype.Signed, p)
  222. datablockwrapper = FakeDataBlockWrapper()
  223. p = lltype.malloc(rffi.CArray(rffi.INT), 3, immortal=True)
  224. gcrootmap = GcRootMap_shadowstack(self.FakeGcDescr())
  225. shape = [16, -24]
  226. gcrootmap.compress_callshape(shape, datablockwrapper)
  227. assert rffi.cast(lltype.Signed, p[0]) == 16
  228. assert rffi.cast(lltype.Signed, p[1]) == -24
  229. assert rffi.cast(lltype.Signed, p[2]) == 0
  230. class FakeLLOp(object):
  231. def __init__(self):
  232. self.record = []
  233. def _malloc(self, type_id, size):
  234. tid = llop.combine_ushort(lltype.Signed, type_id, 0)
  235. x = llmemory.raw_malloc(self.gcheaderbuilder.size_gc_header + size)
  236. x += self.gcheaderbuilder.size_gc_header
  237. return x, tid
  238. def do_malloc_fixedsize_clear(self, RESTYPE, type_id, size,
  239. has_finalizer, has_light_finalizer,
  240. contains_weakptr):
  241. assert not contains_weakptr
  242. assert not has_finalizer
  243. assert not has_light_finalizer
  244. p, tid = self._malloc(type_id, size)
  245. p = llmemory.cast_adr_to_ptr(p, RESTYPE)
  246. self.record.append(("fixedsize", repr(size), tid, p))
  247. return p
  248. def do_malloc_varsize_clear(self, RESTYPE, type_id, length, size,
  249. itemsize, offset_to_length):
  250. p, tid = self._malloc(type_id, size + itemsize * length)
  251. (p + offset_to_length).signed[0] = length
  252. p = llmemory.cast_adr_to_ptr(p, RESTYPE)
  253. self.record.append(("varsize", tid, length,
  254. repr(size), repr(itemsize),
  255. repr(offset_to_length), p))
  256. return p
  257. def _write_barrier_failing_case(self, adr_struct, adr_newptr):
  258. self.record.append(('barrier', adr_struct, adr_newptr))
  259. def get_write_barrier_failing_case(self, FPTRTYPE):
  260. return llhelper(FPTRTYPE, self._write_barrier_failing_case)
  261. _have_wb_from_array = False
  262. def _write_barrier_from_array_failing_case(self, adr_struct, v_index):
  263. self.record.append(('barrier_from_array', adr_struct, v_index))
  264. def get_write_barrier_from_array_failing_case(self, FPTRTYPE):
  265. if self._have_wb_from_array:
  266. return llhelper(FPTRTYPE,
  267. self._write_barrier_from_array_failing_case)
  268. else:
  269. return lltype.nullptr(FPTRTYPE.TO)
  270. class TestFramework(object):
  271. gc = 'hybrid'
  272. def setup_method(self, meth):
  273. class config_(object):
  274. class translation(object):
  275. gc = self.gc
  276. gcrootfinder = 'asmgcc'
  277. gctransformer = 'framework'
  278. gcremovetypeptr = False
  279. class FakeTranslator(object):
  280. config = config_
  281. class FakeCPU(object):
  282. def cast_adr_to_int(self, adr):
  283. if not adr:
  284. return 0
  285. try:
  286. ptr = llmemory.cast_adr_to_ptr(adr, gc_ll_descr.WB_FUNCPTR)
  287. assert ptr._obj._callable == \
  288. llop1._write_barrier_failing_case
  289. return 42
  290. except lltype.InvalidCast:
  291. ptr = llmemory.cast_adr_to_ptr(
  292. adr, gc_ll_descr.WB_ARRAY_FUNCPTR)
  293. assert ptr._obj._callable == \
  294. llop1._write_barrier_from_array_failing_case
  295. return 43
  296. gcdescr = get_description(config_)
  297. translator = FakeTranslator()
  298. llop1 = FakeLLOp()
  299. gc_ll_descr = GcLLDescr_framework(gcdescr, FakeTranslator(), None,
  300. llop1)
  301. gc_ll_descr.initialize()
  302. llop1.gcheaderbuilder = gc_ll_descr.gcheaderbuilder
  303. self.llop1 = llop1
  304. self.gc_ll_descr = gc_ll_descr
  305. self.fake_cpu = FakeCPU()
  306. ## def test_args_for_new(self):
  307. ## S = lltype.GcStruct('S', ('x', lltype.Signed))
  308. ## sizedescr = get_size_descr(self.gc_ll_descr, S)
  309. ## args = self.gc_ll_descr.args_for_new(sizedescr)
  310. ## for x in args:
  311. ## assert lltype.typeOf(x) == lltype.Signed
  312. ## A = lltype.GcArray(lltype.Signed)
  313. ## arraydescr = get_array_descr(self.gc_ll_descr, A)
  314. ## args = self.gc_ll_descr.args_for_new(sizedescr)
  315. ## for x in args:
  316. ## assert lltype.typeOf(x) == lltype.Signed
  317. def test_gc_malloc(self):
  318. S = lltype.GcStruct('S', ('x', lltype.Signed))
  319. sizedescr = get_size_descr(self.gc_ll_descr, S)
  320. p = self.gc_ll_descr.gc_malloc(sizedescr)
  321. assert lltype.typeOf(p) == llmemory.GCREF
  322. assert self.llop1.record == [("fixedsize", repr(sizedescr.size),
  323. sizedescr.tid, p)]
  324. def test_gc_malloc_array(self):
  325. A = lltype.GcArray(lltype.Signed)
  326. arraydescr = get_array_descr(self.gc_ll_descr, A)
  327. p = self.gc_ll_descr.gc_malloc_array(arraydescr, 10)
  328. assert self.llop1.record == [("varsize", arraydescr.tid, 10,
  329. repr(arraydescr.basesize),
  330. repr(arraydescr.itemsize),
  331. repr(arraydescr.lendescr.offset),
  332. p)]
  333. def test_gc_malloc_str(self):
  334. p = self.gc_ll_descr.gc_malloc_str(10)
  335. type_id = self.gc_ll_descr.layoutbuilder.get_type_id(rstr.STR)
  336. tid = llop.combine_ushort(lltype.Signed, type_id, 0)
  337. basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR,
  338. True)
  339. assert self.llop1.record == [("varsize", tid, 10,
  340. repr(basesize), repr(itemsize),
  341. repr(ofs_length), p)]
  342. def test_gc_malloc_unicode(self):
  343. p = self.gc_ll_descr.gc_malloc_unicode(10)
  344. type_id = self.gc_ll_descr.layoutbuilder.get_type_id(rstr.UNICODE)
  345. tid = llop.combine_ushort(lltype.Signed, type_id, 0)
  346. basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE,
  347. True)
  348. assert self.llop1.record == [("varsize", tid, 10,
  349. repr(basesize), repr(itemsize),
  350. repr(ofs_length), p)]
  351. def test_do_write_barrier(self):
  352. gc_ll_descr = self.gc_ll_descr
  353. R = lltype.GcStruct('R')
  354. S = lltype.GcStruct('S', ('r', lltype.Ptr(R)))
  355. s = lltype.malloc(S)
  356. r = lltype.malloc(R)
  357. s_hdr = gc_ll_descr.gcheaderbuilder.new_header(s)
  358. s_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
  359. r_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, r)
  360. s_adr = llmemory.cast_ptr_to_adr(s)
  361. r_adr = llmemory.cast_ptr_to_adr(r)
  362. #
  363. s_hdr.tid &= ~gc_ll_descr.GCClass.JIT_WB_IF_FLAG
  364. gc_ll_descr.do_write_barrier(s_gcref, r_gcref)
  365. assert self.llop1.record == [] # not called
  366. #
  367. s_hdr.tid |= gc_ll_descr.GCClass.JIT_WB_IF_FLAG
  368. gc_ll_descr.do_write_barrier(s_gcref, r_gcref)
  369. assert self.llop1.record == [('barrier', s_adr, r_adr)]
  370. def test_gen_write_barrier(self):
  371. gc_ll_descr = self.gc_ll_descr
  372. llop1 = self.llop1
  373. #
  374. rewriter = GcRewriterAssembler(gc_ll_descr, None)
  375. newops = rewriter.newops
  376. v_base = BoxPtr()
  377. v_value = BoxPtr()
  378. rewriter.gen_write_barrier(v_base, v_value)
  379. assert llop1.record == []
  380. assert len(newops) == 1
  381. assert newops[0].getopnum() == rop.COND_CALL_GC_WB
  382. assert newops[0].getarg(0) == v_base
  383. assert newops[0].getarg(1) == v_value
  384. assert newops[0].result is None
  385. wbdescr = newops[0].getdescr()
  386. assert isinstance(wbdescr.jit_wb_if_flag, int)
  387. assert isinstance(wbdescr.jit_wb_if_flag_byteofs, int)
  388. assert isinstance(wbdescr.jit_wb_if_flag_singlebyte, int)
  389. def test_get_rid_of_debug_merge_point(self):
  390. operations = [
  391. ResOperation(rop.DEBUG_MERGE_POINT, ['dummy', 2], None),
  392. ]
  393. gc_ll_descr = self.gc_ll_descr
  394. operations = gc_ll_descr.rewrite_assembler(None, operations, [])
  395. assert len(operations) == 0
  396. def test_record_constptrs(self):
  397. class MyFakeCPU(object):
  398. def cast_adr_to_int(self, adr):
  399. assert adr == "some fake address"
  400. return 43
  401. class MyFakeGCRefList(object):
  402. def get_address_of_gcref(self, s_gcref1):
  403. assert s_gcref1 == s_gcref
  404. return "some fake address"
  405. S = lltype.GcStruct('S')
  406. s = lltype.malloc(S)
  407. s_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
  408. v_random_box = BoxPtr()
  409. v_result = BoxInt()
  410. operations = [
  411. ResOperation(rop.PTR_EQ, [v_random_box, ConstPtr(s_gcref)],
  412. v_result),
  413. ]
  414. gc_ll_descr = self.gc_ll_descr
  415. gc_ll_descr.gcrefs = MyFakeGCRefList()
  416. gcrefs = []
  417. operations = get_deep_immutable_oplist(operations)
  418. operations2 = gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations,
  419. gcrefs)
  420. assert operations2 == operations
  421. assert gcrefs == [s_gcref]
  422. class TestFrameworkMiniMark(TestFramework):
  423. gc = 'minimark'