PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/jit/backend/x86/test/test_gc_integration.py

https://bitbucket.org/pypy/pypy/
Python | 259 lines | 236 code | 20 blank | 3 comment | 3 complexity | c016bf71c9482bcba81c23fa1545122c MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. """ Tests for register allocation for common constructs
  2. """
  3. import py
  4. from pypy.jit.metainterp.history import BoxInt, ConstInt,\
  5. BoxPtr, ConstPtr, TreeLoop, TargetToken
  6. from pypy.jit.metainterp.resoperation import rop, ResOperation
  7. from pypy.jit.codewriter import heaptracker
  8. from pypy.jit.codewriter.effectinfo import EffectInfo
  9. from pypy.jit.backend.llsupport.descr import GcCache, FieldDescr, FLAG_SIGNED
  10. from pypy.jit.backend.llsupport.gc import GcLLDescription
  11. from pypy.jit.backend.detect_cpu import getcpuclass
  12. from pypy.jit.backend.x86.regalloc import RegAlloc
  13. from pypy.jit.backend.x86.arch import WORD, FRAME_FIXED_SIZE
  14. from pypy.jit.tool.oparser import parse
  15. from pypy.rpython.lltypesystem import lltype, llmemory, rffi
  16. from pypy.rpython.annlowlevel import llhelper
  17. from pypy.rpython.lltypesystem import rclass, rstr
  18. from pypy.jit.backend.llsupport.gc import GcLLDescr_framework
  19. from pypy.jit.backend.x86.test.test_regalloc import MockAssembler
  20. from pypy.jit.backend.x86.test.test_regalloc import BaseTestRegalloc
  21. from pypy.jit.backend.x86.regalloc import X86RegisterManager, X86FrameManager,\
  22. X86XMMRegisterManager
  23. CPU = getcpuclass()
  24. class MockGcRootMap(object):
  25. is_shadow_stack = False
  26. def get_basic_shape(self, is_64_bit):
  27. return ['shape']
  28. def add_frame_offset(self, shape, offset):
  29. shape.append(offset)
  30. def add_callee_save_reg(self, shape, reg_index):
  31. index_to_name = { 1: 'ebx', 2: 'esi', 3: 'edi' }
  32. shape.append(index_to_name[reg_index])
  33. def compress_callshape(self, shape, datablockwrapper):
  34. assert datablockwrapper == 'fakedatablockwrapper'
  35. assert shape[0] == 'shape'
  36. return ['compressed'] + shape[1:]
  37. class MockGcDescr(GcCache):
  38. get_malloc_slowpath_addr = None
  39. write_barrier_descr = None
  40. moving_gc = True
  41. gcrootmap = MockGcRootMap()
  42. def initialize(self):
  43. pass
  44. _record_constptrs = GcLLDescr_framework._record_constptrs.im_func
  45. rewrite_assembler = GcLLDescr_framework.rewrite_assembler.im_func
  46. class TestRegallocDirectGcIntegration(object):
  47. def test_mark_gc_roots(self):
  48. cpu = CPU(None, None)
  49. cpu.setup_once()
  50. regalloc = RegAlloc(MockAssembler(cpu, MockGcDescr(False)))
  51. regalloc.assembler.datablockwrapper = 'fakedatablockwrapper'
  52. boxes = [BoxPtr() for i in range(len(X86RegisterManager.all_regs))]
  53. longevity = {}
  54. for box in boxes:
  55. longevity[box] = (0, 1)
  56. regalloc.fm = X86FrameManager()
  57. regalloc.rm = X86RegisterManager(longevity, regalloc.fm,
  58. assembler=regalloc.assembler)
  59. regalloc.xrm = X86XMMRegisterManager(longevity, regalloc.fm,
  60. assembler=regalloc.assembler)
  61. cpu = regalloc.assembler.cpu
  62. for box in boxes:
  63. regalloc.rm.try_allocate_reg(box)
  64. TP = lltype.FuncType([], lltype.Signed)
  65. calldescr = cpu.calldescrof(TP, TP.ARGS, TP.RESULT,
  66. EffectInfo.MOST_GENERAL)
  67. regalloc.rm._check_invariants()
  68. box = boxes[0]
  69. regalloc.position = 0
  70. regalloc.consider_call(ResOperation(rop.CALL, [box], BoxInt(),
  71. calldescr))
  72. assert len(regalloc.assembler.movs) == 3
  73. #
  74. mark = regalloc.get_mark_gc_roots(cpu.gc_ll_descr.gcrootmap)
  75. assert mark[0] == 'compressed'
  76. base = -WORD * FRAME_FIXED_SIZE
  77. expected = ['ebx', 'esi', 'edi', base, base-WORD, base-WORD*2]
  78. assert dict.fromkeys(mark[1:]) == dict.fromkeys(expected)
  79. class TestRegallocGcIntegration(BaseTestRegalloc):
  80. cpu = CPU(None, None)
  81. cpu.gc_ll_descr = MockGcDescr(False)
  82. cpu.setup_once()
  83. S = lltype.GcForwardReference()
  84. S.become(lltype.GcStruct('S', ('field', lltype.Ptr(S)),
  85. ('int', lltype.Signed)))
  86. fielddescr = cpu.fielddescrof(S, 'field')
  87. struct_ptr = lltype.malloc(S)
  88. struct_ref = lltype.cast_opaque_ptr(llmemory.GCREF, struct_ptr)
  89. child_ptr = lltype.nullptr(S)
  90. struct_ptr.field = child_ptr
  91. descr0 = cpu.fielddescrof(S, 'int')
  92. ptr0 = struct_ref
  93. targettoken = TargetToken()
  94. namespace = locals().copy()
  95. def test_basic(self):
  96. ops = '''
  97. [p0]
  98. p1 = getfield_gc(p0, descr=fielddescr)
  99. finish(p1)
  100. '''
  101. self.interpret(ops, [self.struct_ptr])
  102. assert not self.getptr(0, lltype.Ptr(self.S))
  103. def test_rewrite_constptr(self):
  104. ops = '''
  105. []
  106. p1 = getfield_gc(ConstPtr(struct_ref), descr=fielddescr)
  107. finish(p1)
  108. '''
  109. self.interpret(ops, [])
  110. assert not self.getptr(0, lltype.Ptr(self.S))
  111. def test_bug_0(self):
  112. ops = '''
  113. [i0, i1, i2, i3, i4, i5, i6, i7, i8]
  114. label(i0, i1, i2, i3, i4, i5, i6, i7, i8, descr=targettoken)
  115. guard_value(i2, 1) [i2, i3, i4, i5, i6, i7, i0, i1, i8]
  116. guard_class(i4, 138998336) [i4, i5, i6, i7, i0, i1, i8]
  117. i11 = getfield_gc(i4, descr=descr0)
  118. guard_nonnull(i11) [i4, i5, i6, i7, i0, i1, i11, i8]
  119. i13 = getfield_gc(i11, descr=descr0)
  120. guard_isnull(i13) [i4, i5, i6, i7, i0, i1, i11, i8]
  121. i15 = getfield_gc(i4, descr=descr0)
  122. i17 = int_lt(i15, 0)
  123. guard_false(i17) [i4, i5, i6, i7, i0, i1, i11, i15, i8]
  124. i18 = getfield_gc(i11, descr=descr0)
  125. i19 = int_ge(i15, i18)
  126. guard_false(i19) [i4, i5, i6, i7, i0, i1, i11, i15, i8]
  127. i20 = int_lt(i15, 0)
  128. guard_false(i20) [i4, i5, i6, i7, i0, i1, i11, i15, i8]
  129. i21 = getfield_gc(i11, descr=descr0)
  130. i22 = getfield_gc(i11, descr=descr0)
  131. i23 = int_mul(i15, i22)
  132. i24 = int_add(i21, i23)
  133. i25 = getfield_gc(i4, descr=descr0)
  134. i27 = int_add(i25, 1)
  135. setfield_gc(i4, i27, descr=descr0)
  136. i29 = getfield_raw(144839744, descr=descr0)
  137. i31 = int_and(i29, -2141192192)
  138. i32 = int_is_true(i31)
  139. guard_false(i32) [i4, i6, i7, i0, i1, i24]
  140. i33 = getfield_gc(i0, descr=descr0)
  141. guard_value(i33, ConstPtr(ptr0)) [i4, i6, i7, i0, i1, i33, i24]
  142. jump(i0, i1, 1, 17, i4, ConstPtr(ptr0), i6, i7, i24, descr=targettoken)
  143. '''
  144. self.interpret(ops, [0, 0, 0, 0, 0, 0, 0, 0, 0], run=False)
  145. NOT_INITIALIZED = chr(0xdd)
  146. class GCDescrFastpathMalloc(GcLLDescription):
  147. gcrootmap = None
  148. write_barrier_descr = None
  149. def __init__(self):
  150. GcLLDescription.__init__(self, None)
  151. # create a nursery
  152. NTP = rffi.CArray(lltype.Char)
  153. self.nursery = lltype.malloc(NTP, 64, flavor='raw')
  154. for i in range(64):
  155. self.nursery[i] = NOT_INITIALIZED
  156. self.addrs = lltype.malloc(rffi.CArray(lltype.Signed), 2,
  157. flavor='raw')
  158. self.addrs[0] = rffi.cast(lltype.Signed, self.nursery)
  159. self.addrs[1] = self.addrs[0] + 64
  160. self.calls = []
  161. def malloc_slowpath(size):
  162. self.calls.append(size)
  163. # reset the nursery
  164. nadr = rffi.cast(lltype.Signed, self.nursery)
  165. self.addrs[0] = nadr + size
  166. return nadr
  167. self.generate_function('malloc_nursery', malloc_slowpath,
  168. [lltype.Signed], lltype.Signed)
  169. def get_nursery_free_addr(self):
  170. return rffi.cast(lltype.Signed, self.addrs)
  171. def get_nursery_top_addr(self):
  172. return rffi.cast(lltype.Signed, self.addrs) + WORD
  173. def get_malloc_slowpath_addr(self):
  174. return self.get_malloc_fn_addr('malloc_nursery')
  175. def check_nothing_in_nursery(self):
  176. # CALL_MALLOC_NURSERY should not write anything in the nursery
  177. for i in range(64):
  178. assert self.nursery[i] == NOT_INITIALIZED
  179. class TestMallocFastpath(BaseTestRegalloc):
  180. def setup_method(self, method):
  181. cpu = CPU(None, None)
  182. cpu.gc_ll_descr = GCDescrFastpathMalloc()
  183. cpu.setup_once()
  184. self.cpu = cpu
  185. def test_malloc_fastpath(self):
  186. ops = '''
  187. []
  188. p0 = call_malloc_nursery(16)
  189. p1 = call_malloc_nursery(32)
  190. p2 = call_malloc_nursery(16)
  191. finish(p0, p1, p2)
  192. '''
  193. self.interpret(ops, [])
  194. # check the returned pointers
  195. gc_ll_descr = self.cpu.gc_ll_descr
  196. nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
  197. ref = self.cpu.get_latest_value_ref
  198. assert rffi.cast(lltype.Signed, ref(0)) == nurs_adr + 0
  199. assert rffi.cast(lltype.Signed, ref(1)) == nurs_adr + 16
  200. assert rffi.cast(lltype.Signed, ref(2)) == nurs_adr + 48
  201. # check the nursery content and state
  202. gc_ll_descr.check_nothing_in_nursery()
  203. assert gc_ll_descr.addrs[0] == nurs_adr + 64
  204. # slowpath never called
  205. assert gc_ll_descr.calls == []
  206. def test_malloc_slowpath(self):
  207. ops = '''
  208. []
  209. p0 = call_malloc_nursery(16)
  210. p1 = call_malloc_nursery(32)
  211. p2 = call_malloc_nursery(24) # overflow
  212. finish(p0, p1, p2)
  213. '''
  214. self.interpret(ops, [])
  215. # check the returned pointers
  216. gc_ll_descr = self.cpu.gc_ll_descr
  217. nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
  218. ref = self.cpu.get_latest_value_ref
  219. assert rffi.cast(lltype.Signed, ref(0)) == nurs_adr + 0
  220. assert rffi.cast(lltype.Signed, ref(1)) == nurs_adr + 16
  221. assert rffi.cast(lltype.Signed, ref(2)) == nurs_adr + 0
  222. # check the nursery content and state
  223. gc_ll_descr.check_nothing_in_nursery()
  224. assert gc_ll_descr.addrs[0] == nurs_adr + 24
  225. # this should call slow path once
  226. assert gc_ll_descr.calls == [24]