PageRenderTime 47ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/pypy/jit/backend/llsupport/gc.py

http://github.com/pypy/pypy
Python | 890 lines | 741 code | 52 blank | 97 comment | 46 complexity | e799a419657065ecebb8377be33aa4fc MD5 | raw file
  1. import os
  2. from pypy.rlib import rgc
  3. from pypy.rlib.objectmodel import we_are_translated, specialize
  4. from pypy.rlib.rarithmetic import ovfcheck
  5. from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass, rstr
  6. from pypy.rpython.lltypesystem import llgroup
  7. from pypy.rpython.lltypesystem.lloperation import llop
  8. from pypy.rpython.annlowlevel import llhelper
  9. from pypy.translator.tool.cbuild import ExternalCompilationInfo
  10. from pypy.jit.codewriter import heaptracker
  11. from pypy.jit.metainterp.history import ConstPtr, AbstractDescr
  12. from pypy.jit.metainterp.resoperation import ResOperation, rop
  13. from pypy.jit.backend.llsupport import symbolic
  14. from pypy.jit.backend.llsupport.symbolic import WORD
  15. from pypy.jit.backend.llsupport.descr import SizeDescr, ArrayDescr
  16. from pypy.jit.backend.llsupport.descr import GcCache, get_field_descr
  17. from pypy.jit.backend.llsupport.descr import get_array_descr
  18. from pypy.jit.backend.llsupport.descr import get_call_descr
  19. from pypy.jit.backend.llsupport.rewrite import GcRewriterAssembler
  20. from pypy.rpython.memory.gctransform import asmgcroot
  21. # ____________________________________________________________
  22. class GcLLDescription(GcCache):
  23. def __init__(self, gcdescr, translator=None, rtyper=None):
  24. GcCache.__init__(self, translator is not None, rtyper)
  25. self.gcdescr = gcdescr
  26. if translator and translator.config.translation.gcremovetypeptr:
  27. self.fielddescr_vtable = None
  28. else:
  29. self.fielddescr_vtable = get_field_descr(self, rclass.OBJECT,
  30. 'typeptr')
  31. self._generated_functions = []
  32. def _setup_str(self):
  33. self.str_descr = get_array_descr(self, rstr.STR)
  34. self.unicode_descr = get_array_descr(self, rstr.UNICODE)
  35. def generate_function(self, funcname, func, ARGS, RESULT=llmemory.GCREF):
  36. """Generates a variant of malloc with the given name and the given
  37. arguments. It should return NULL if out of memory. If it raises
  38. anything, it must be an optional MemoryError.
  39. """
  40. FUNCPTR = lltype.Ptr(lltype.FuncType(ARGS, RESULT))
  41. descr = get_call_descr(self, ARGS, RESULT)
  42. setattr(self, funcname, func)
  43. setattr(self, funcname + '_FUNCPTR', FUNCPTR)
  44. setattr(self, funcname + '_descr', descr)
  45. self._generated_functions.append(funcname)
  46. @specialize.arg(1)
  47. def get_malloc_fn(self, funcname):
  48. func = getattr(self, funcname)
  49. FUNC = getattr(self, funcname + '_FUNCPTR')
  50. return llhelper(FUNC, func)
  51. @specialize.arg(1)
  52. def get_malloc_fn_addr(self, funcname):
  53. ll_func = self.get_malloc_fn(funcname)
  54. return heaptracker.adr2int(llmemory.cast_ptr_to_adr(ll_func))
  55. def _freeze_(self):
  56. return True
  57. def initialize(self):
  58. pass
  59. def do_write_barrier(self, gcref_struct, gcref_newptr):
  60. pass
  61. def can_use_nursery_malloc(self, size):
  62. return False
  63. def has_write_barrier_class(self):
  64. return None
  65. def freeing_block(self, start, stop):
  66. pass
  67. def get_nursery_free_addr(self):
  68. raise NotImplementedError
  69. def get_nursery_top_addr(self):
  70. raise NotImplementedError
  71. def gc_malloc(self, sizedescr):
  72. """Blackhole: do a 'bh_new'. Also used for 'bh_new_with_vtable',
  73. with the vtable pointer set manually afterwards."""
  74. assert isinstance(sizedescr, SizeDescr)
  75. return self._bh_malloc(sizedescr)
  76. def gc_malloc_array(self, arraydescr, num_elem):
  77. assert isinstance(arraydescr, ArrayDescr)
  78. return self._bh_malloc_array(arraydescr, num_elem)
  79. def gc_malloc_str(self, num_elem):
  80. return self._bh_malloc_array(self.str_descr, num_elem)
  81. def gc_malloc_unicode(self, num_elem):
  82. return self._bh_malloc_array(self.unicode_descr, num_elem)
  83. def _record_constptrs(self, op, gcrefs_output_list):
  84. for i in range(op.numargs()):
  85. v = op.getarg(i)
  86. if isinstance(v, ConstPtr) and bool(v.value):
  87. p = v.value
  88. rgc._make_sure_does_not_move(p)
  89. gcrefs_output_list.append(p)
  90. def rewrite_assembler(self, cpu, operations, gcrefs_output_list):
  91. rewriter = GcRewriterAssembler(self, cpu)
  92. newops = rewriter.rewrite(operations)
  93. # record all GCREFs, because the GC (or Boehm) cannot see them and
  94. # keep them alive if they end up as constants in the assembler
  95. for op in newops:
  96. self._record_constptrs(op, gcrefs_output_list)
  97. return newops
  98. # ____________________________________________________________
  99. class GcLLDescr_boehm(GcLLDescription):
  100. kind = 'boehm'
  101. moving_gc = False
  102. round_up = False
  103. gcrootmap = None
  104. write_barrier_descr = None
  105. fielddescr_tid = None
  106. str_type_id = 0
  107. unicode_type_id = 0
  108. get_malloc_slowpath_addr = None
  109. @classmethod
  110. def configure_boehm_once(cls):
  111. """ Configure boehm only once, since we don't cache failures
  112. """
  113. if hasattr(cls, 'malloc_fn_ptr'):
  114. return cls.malloc_fn_ptr
  115. from pypy.rpython.tool import rffi_platform
  116. compilation_info = rffi_platform.configure_boehm()
  117. # on some platform GC_init is required before any other
  118. # GC_* functions, call it here for the benefit of tests
  119. # XXX move this to tests
  120. init_fn_ptr = rffi.llexternal("GC_init",
  121. [], lltype.Void,
  122. compilation_info=compilation_info,
  123. sandboxsafe=True,
  124. _nowrapper=True)
  125. init_fn_ptr()
  126. # Versions 6.x of libgc needs to use GC_local_malloc().
  127. # Versions 7.x of libgc removed this function; GC_malloc() has
  128. # the same behavior if libgc was compiled with
  129. # THREAD_LOCAL_ALLOC.
  130. class CConfig:
  131. _compilation_info_ = compilation_info
  132. HAS_LOCAL_MALLOC = rffi_platform.Has("GC_local_malloc")
  133. config = rffi_platform.configure(CConfig)
  134. if config['HAS_LOCAL_MALLOC']:
  135. GC_MALLOC = "GC_local_malloc"
  136. else:
  137. GC_MALLOC = "GC_malloc"
  138. malloc_fn_ptr = rffi.llexternal(GC_MALLOC,
  139. [lltype.Signed], # size_t, but good enough
  140. llmemory.GCREF,
  141. compilation_info=compilation_info,
  142. sandboxsafe=True,
  143. _nowrapper=True)
  144. cls.malloc_fn_ptr = malloc_fn_ptr
  145. return malloc_fn_ptr
  146. def __init__(self, gcdescr, translator, rtyper):
  147. GcLLDescription.__init__(self, gcdescr, translator, rtyper)
  148. # grab a pointer to the Boehm 'malloc' function
  149. self.malloc_fn_ptr = self.configure_boehm_once()
  150. self._setup_str()
  151. self._make_functions()
  152. def _make_functions(self):
  153. def malloc_fixedsize(size):
  154. return self.malloc_fn_ptr(size)
  155. self.generate_function('malloc_fixedsize', malloc_fixedsize,
  156. [lltype.Signed])
  157. def malloc_array(basesize, num_elem, itemsize, ofs_length):
  158. try:
  159. totalsize = ovfcheck(basesize + ovfcheck(itemsize * num_elem))
  160. except OverflowError:
  161. return lltype.nullptr(llmemory.GCREF.TO)
  162. res = self.malloc_fn_ptr(totalsize)
  163. if res:
  164. arrayptr = rffi.cast(rffi.CArrayPtr(lltype.Signed), res)
  165. arrayptr[ofs_length/WORD] = num_elem
  166. return res
  167. self.generate_function('malloc_array', malloc_array,
  168. [lltype.Signed] * 4)
  169. def _bh_malloc(self, sizedescr):
  170. return self.malloc_fixedsize(sizedescr.size)
  171. def _bh_malloc_array(self, arraydescr, num_elem):
  172. return self.malloc_array(arraydescr.basesize, num_elem,
  173. arraydescr.itemsize,
  174. arraydescr.lendescr.offset)
  175. # ____________________________________________________________
  176. # All code below is for the hybrid or minimark GC
  177. class GcRootMap_asmgcc(object):
  178. """Handles locating the stack roots in the assembler.
  179. This is the class supporting --gcrootfinder=asmgcc.
  180. """
  181. is_shadow_stack = False
  182. is_64_bit = (WORD == 8)
  183. LOC_REG = 0
  184. LOC_ESP_PLUS = 1
  185. LOC_EBP_PLUS = 2
  186. LOC_EBP_MINUS = 3
  187. GCMAP_ARRAY = rffi.CArray(lltype.Signed)
  188. CALLSHAPE_ARRAY_PTR = rffi.CArrayPtr(rffi.UCHAR)
  189. def __init__(self, gcdescr=None):
  190. # '_gcmap' is an array of length '_gcmap_maxlength' of addresses.
  191. # '_gcmap_curlength' tells how full the array really is.
  192. # The addresses are actually grouped in pairs:
  193. # (addr-after-the-CALL-in-assembler, addr-of-the-call-shape).
  194. # '_gcmap_deadentries' counts pairs marked dead (2nd item is NULL).
  195. # '_gcmap_sorted' is True only if we know the array is sorted.
  196. self._gcmap = lltype.nullptr(self.GCMAP_ARRAY)
  197. self._gcmap_curlength = 0
  198. self._gcmap_maxlength = 0
  199. self._gcmap_deadentries = 0
  200. self._gcmap_sorted = True
  201. def add_jit2gc_hooks(self, jit2gc):
  202. jit2gc.update({
  203. 'gcmapstart': lambda: self.gcmapstart(),
  204. 'gcmapend': lambda: self.gcmapend(),
  205. 'gcmarksorted': lambda: self.gcmarksorted(),
  206. })
  207. def initialize(self):
  208. # hack hack hack. Remove these lines and see MissingRTypeAttribute
  209. # when the rtyper tries to annotate these methods only when GC-ing...
  210. self.gcmapstart()
  211. self.gcmapend()
  212. self.gcmarksorted()
  213. def gcmapstart(self):
  214. return rffi.cast(llmemory.Address, self._gcmap)
  215. def gcmapend(self):
  216. addr = self.gcmapstart()
  217. if self._gcmap_curlength:
  218. addr += rffi.sizeof(lltype.Signed) * self._gcmap_curlength
  219. if not we_are_translated() and type(addr) is long:
  220. from pypy.rpython.lltypesystem import ll2ctypes
  221. addr = ll2ctypes._lladdress(addr) # XXX workaround
  222. return addr
  223. def gcmarksorted(self):
  224. # Called by the GC when it is about to sort [gcmapstart():gcmapend()].
  225. # Returns the previous sortedness flag -- i.e. returns True if it
  226. # is already sorted, False if sorting is needed.
  227. sorted = self._gcmap_sorted
  228. self._gcmap_sorted = True
  229. return sorted
  230. def put(self, retaddr, callshapeaddr):
  231. """'retaddr' is the address just after the CALL.
  232. 'callshapeaddr' is the address of the raw 'shape' marker.
  233. Both addresses are actually integers here."""
  234. index = self._gcmap_curlength
  235. if index + 2 > self._gcmap_maxlength:
  236. index = self._enlarge_gcmap()
  237. self._gcmap[index] = retaddr
  238. self._gcmap[index+1] = callshapeaddr
  239. self._gcmap_curlength = index + 2
  240. self._gcmap_sorted = False
  241. @rgc.no_collect
  242. def _enlarge_gcmap(self):
  243. oldgcmap = self._gcmap
  244. if self._gcmap_deadentries * 3 * 2 > self._gcmap_maxlength:
  245. # More than 1/3rd of the entries are dead. Don't actually
  246. # enlarge the gcmap table, but just clean up the dead entries.
  247. newgcmap = oldgcmap
  248. else:
  249. # Normal path: enlarge the array.
  250. newlength = 250 + (self._gcmap_maxlength // 3) * 4
  251. newgcmap = lltype.malloc(self.GCMAP_ARRAY, newlength, flavor='raw',
  252. track_allocation=False)
  253. self._gcmap_maxlength = newlength
  254. #
  255. j = 0
  256. i = 0
  257. end = self._gcmap_curlength
  258. while i < end:
  259. if oldgcmap[i + 1]:
  260. newgcmap[j] = oldgcmap[i]
  261. newgcmap[j + 1] = oldgcmap[i + 1]
  262. j += 2
  263. i += 2
  264. self._gcmap_curlength = j
  265. self._gcmap_deadentries = 0
  266. if oldgcmap != newgcmap:
  267. self._gcmap = newgcmap
  268. if oldgcmap:
  269. lltype.free(oldgcmap, flavor='raw', track_allocation=False)
  270. return j
  271. @rgc.no_collect
  272. def freeing_block(self, start, stop):
  273. # if [start:stop] is a raw block of assembler, then look up the
  274. # corresponding gcroot markers, and mark them as freed now in
  275. # self._gcmap by setting the 2nd address of every entry to NULL.
  276. gcmapstart = self.gcmapstart()
  277. gcmapend = self.gcmapend()
  278. if gcmapstart == gcmapend:
  279. return
  280. if not self.gcmarksorted():
  281. asmgcroot.sort_gcmap(gcmapstart, gcmapend)
  282. # A note about gcmarksorted(): the deletion we do here keeps the
  283. # array sorted. This avoids needing too many sort_gcmap()s.
  284. # Indeed, freeing_block() is typically called many times in a row,
  285. # so it will call sort_gcmap() at most the first time.
  286. startaddr = rffi.cast(llmemory.Address, start)
  287. stopaddr = rffi.cast(llmemory.Address, stop)
  288. item = asmgcroot.binary_search(gcmapstart, gcmapend, startaddr)
  289. # 'item' points to one of the entries. Because the whole array
  290. # is sorted, we know that it points either to the first entry we
  291. # want to kill, or to the previous entry.
  292. if item.address[0] < startaddr:
  293. item += asmgcroot.arrayitemsize # go forward one entry
  294. assert item == gcmapend or item.address[0] >= startaddr
  295. while item != gcmapend and item.address[0] < stopaddr:
  296. item.address[1] = llmemory.NULL
  297. self._gcmap_deadentries += 1
  298. item += asmgcroot.arrayitemsize
  299. def get_basic_shape(self):
  300. # XXX: Should this code even really know about stack frame layout of
  301. # the JIT?
  302. if self.is_64_bit:
  303. return [chr(self.LOC_EBP_PLUS | 4), # return addr: at 8(%rbp)
  304. chr(self.LOC_EBP_MINUS | 4), # saved %rbx: at -8(%rbp)
  305. chr(self.LOC_EBP_MINUS | 8), # saved %r12: at -16(%rbp)
  306. chr(self.LOC_EBP_MINUS | 12), # saved %r13: at -24(%rbp)
  307. chr(self.LOC_EBP_MINUS | 16), # saved %r14: at -32(%rbp)
  308. chr(self.LOC_EBP_MINUS | 20), # saved %r15: at -40(%rbp)
  309. chr(self.LOC_EBP_PLUS | 0), # saved %rbp: at (%rbp)
  310. chr(0)]
  311. else:
  312. return [chr(self.LOC_EBP_PLUS | 4), # return addr: at 4(%ebp)
  313. chr(self.LOC_EBP_MINUS | 4), # saved %ebx: at -4(%ebp)
  314. chr(self.LOC_EBP_MINUS | 8), # saved %esi: at -8(%ebp)
  315. chr(self.LOC_EBP_MINUS | 12), # saved %edi: at -12(%ebp)
  316. chr(self.LOC_EBP_PLUS | 0), # saved %ebp: at (%ebp)
  317. chr(0)]
  318. def _encode_num(self, shape, number):
  319. assert number >= 0
  320. flag = 0
  321. while number >= 0x80:
  322. shape.append(chr((number & 0x7F) | flag))
  323. flag = 0x80
  324. number >>= 7
  325. shape.append(chr(number | flag))
  326. def add_frame_offset(self, shape, offset):
  327. if self.is_64_bit:
  328. assert (offset & 7) == 0
  329. offset >>= 1
  330. else:
  331. assert (offset & 3) == 0
  332. if offset >= 0:
  333. num = self.LOC_EBP_PLUS | offset
  334. else:
  335. num = self.LOC_EBP_MINUS | (-offset)
  336. self._encode_num(shape, num)
  337. def add_callee_save_reg(self, shape, reg_index):
  338. assert reg_index > 0
  339. shape.append(chr(self.LOC_REG | (reg_index << 2)))
  340. def compress_callshape(self, shape, datablockwrapper):
  341. # Similar to compress_callshape() in trackgcroot.py.
  342. # Returns an address to raw memory (as an integer).
  343. length = len(shape)
  344. rawaddr = datablockwrapper.malloc_aligned(length, 1)
  345. p = rffi.cast(self.CALLSHAPE_ARRAY_PTR, rawaddr)
  346. for i in range(length):
  347. p[length-1-i] = rffi.cast(rffi.UCHAR, shape[i])
  348. return rawaddr
  349. class GcRootMap_shadowstack(object):
  350. """Handles locating the stack roots in the assembler.
  351. This is the class supporting --gcrootfinder=shadowstack.
  352. """
  353. is_shadow_stack = True
  354. MARKER_FRAME = 8 # this marker now *follows* the frame addr
  355. # The "shadowstack" is a portable way in which the GC finds the
  356. # roots that live in the stack. Normally it is just a list of
  357. # pointers to GC objects. The pointers may be moved around by a GC
  358. # collection. But with the JIT, an entry can also be MARKER_FRAME,
  359. # in which case the previous entry points to an assembler stack frame.
  360. # During a residual CALL from the assembler (which may indirectly
  361. # call the GC), we use the force_index stored in the assembler
  362. # stack frame to identify the call: we can go from the force_index
  363. # to a list of where the GC pointers are in the frame (this is the
  364. # purpose of the present class).
  365. #
  366. # Note that across CALL_MAY_FORCE or CALL_ASSEMBLER, we can also go
  367. # from the force_index to a ResumeGuardForcedDescr instance, which
  368. # is used if the virtualizable or the virtualrefs need to be forced
  369. # (see pypy.jit.backend.model). The force_index number in the stack
  370. # frame is initially set to a non-negative value x, but it is
  371. # occasionally turned into (~x) in case of forcing.
  372. INTARRAYPTR = rffi.CArrayPtr(rffi.INT)
  373. CALLSHAPES_ARRAY = rffi.CArray(INTARRAYPTR)
  374. def __init__(self, gcdescr):
  375. self._callshapes = lltype.nullptr(self.CALLSHAPES_ARRAY)
  376. self._callshapes_maxlength = 0
  377. self.force_index_ofs = gcdescr.force_index_ofs
  378. def add_jit2gc_hooks(self, jit2gc):
  379. #
  380. # ---------------
  381. # This is used to enumerate the shadowstack in the presence
  382. # of the JIT. It is also used by the stacklet support in
  383. # rlib/_stacklet_shadowstack. That's why it is written as
  384. # an iterator that can also be used with a custom_trace.
  385. #
  386. class RootIterator:
  387. _alloc_flavor_ = "raw"
  388. def setcontext(iself, context):
  389. iself.context = context
  390. def nextleft(iself, gc, range_lowest, prev):
  391. # Return the next valid GC object's address, in right-to-left
  392. # order from the shadowstack array. This usually means just
  393. # returning "prev - sizeofaddr", until we reach "range_lowest",
  394. # except that we are skipping NULLs. If "prev - sizeofaddr"
  395. # contains a MARKER_FRAME instead, then we go into
  396. # JIT-frame-lookup mode.
  397. #
  398. while True:
  399. #
  400. # If we are not iterating right now in a JIT frame
  401. if iself.frame_addr == 0:
  402. #
  403. # Look for the next shadowstack address that
  404. # contains a valid pointer
  405. while prev != range_lowest:
  406. prev -= llmemory.sizeof(llmemory.Address)
  407. if prev.signed[0] == self.MARKER_FRAME:
  408. break
  409. if gc.points_to_valid_gc_object(prev):
  410. return prev
  411. else:
  412. return llmemory.NULL # done
  413. #
  414. # It's a JIT frame. Save away 'prev' for later, and
  415. # go into JIT-frame-exploring mode.
  416. prev -= llmemory.sizeof(llmemory.Address)
  417. frame_addr = prev.signed[0]
  418. iself.saved_prev = prev
  419. iself.frame_addr = frame_addr
  420. addr = llmemory.cast_int_to_adr(frame_addr +
  421. self.force_index_ofs)
  422. addr = iself.translateptr(iself.context, addr)
  423. force_index = addr.signed[0]
  424. if force_index < 0:
  425. force_index = ~force_index
  426. # NB: the next line reads a still-alive _callshapes,
  427. # because we ensure that just before we called this
  428. # piece of assembler, we put on the (same) stack a
  429. # pointer to a loop_token that keeps the force_index
  430. # alive.
  431. callshape = self._callshapes[force_index]
  432. else:
  433. # Continuing to explore this JIT frame
  434. callshape = iself.callshape
  435. #
  436. # 'callshape' points to the next INT of the callshape.
  437. # If it's zero we are done with the JIT frame.
  438. while rffi.cast(lltype.Signed, callshape[0]) != 0:
  439. #
  440. # Non-zero: it's an offset inside the JIT frame.
  441. # Read it and increment 'callshape'.
  442. offset = rffi.cast(lltype.Signed, callshape[0])
  443. callshape = lltype.direct_ptradd(callshape, 1)
  444. addr = llmemory.cast_int_to_adr(iself.frame_addr +
  445. offset)
  446. addr = iself.translateptr(iself.context, addr)
  447. if gc.points_to_valid_gc_object(addr):
  448. #
  449. # The JIT frame contains a valid GC pointer at
  450. # this address (as opposed to NULL). Save
  451. # 'callshape' for the next call, and return the
  452. # address.
  453. iself.callshape = callshape
  454. return addr
  455. #
  456. # Restore 'prev' and loop back to the start.
  457. iself.frame_addr = 0
  458. prev = iself.saved_prev
  459. # ---------------
  460. #
  461. root_iterator = RootIterator()
  462. root_iterator.frame_addr = 0
  463. root_iterator.context = llmemory.NULL
  464. root_iterator.translateptr = lambda context, addr: addr
  465. jit2gc.update({
  466. 'root_iterator': root_iterator,
  467. })
  468. def initialize(self):
  469. pass
  470. def get_basic_shape(self):
  471. return []
  472. def add_frame_offset(self, shape, offset):
  473. assert offset != 0
  474. shape.append(offset)
  475. def add_callee_save_reg(self, shape, register):
  476. msg = "GC pointer in %s was not spilled" % register
  477. os.write(2, '[llsupport/gc] %s\n' % msg)
  478. raise AssertionError(msg)
  479. def compress_callshape(self, shape, datablockwrapper):
  480. length = len(shape)
  481. SZINT = rffi.sizeof(rffi.INT)
  482. rawaddr = datablockwrapper.malloc_aligned((length + 1) * SZINT, SZINT)
  483. p = rffi.cast(self.INTARRAYPTR, rawaddr)
  484. for i in range(length):
  485. p[i] = rffi.cast(rffi.INT, shape[i])
  486. p[length] = rffi.cast(rffi.INT, 0)
  487. return p
  488. def write_callshape(self, p, force_index):
  489. if force_index >= self._callshapes_maxlength:
  490. self._enlarge_callshape_list(force_index + 1)
  491. self._callshapes[force_index] = p
  492. def _enlarge_callshape_list(self, minsize):
  493. newlength = 250 + (self._callshapes_maxlength // 3) * 4
  494. if newlength < minsize:
  495. newlength = minsize
  496. newarray = lltype.malloc(self.CALLSHAPES_ARRAY, newlength,
  497. flavor='raw', track_allocation=False)
  498. if self._callshapes:
  499. i = self._callshapes_maxlength - 1
  500. while i >= 0:
  501. newarray[i] = self._callshapes[i]
  502. i -= 1
  503. lltype.free(self._callshapes, flavor='raw', track_allocation=False)
  504. self._callshapes = newarray
  505. self._callshapes_maxlength = newlength
  506. def freeing_block(self, start, stop):
  507. pass # nothing needed here
  508. def get_root_stack_top_addr(self):
  509. rst_addr = llop.gc_adr_of_root_stack_top(llmemory.Address)
  510. return rffi.cast(lltype.Signed, rst_addr)
  511. class WriteBarrierDescr(AbstractDescr):
  512. def __init__(self, gc_ll_descr):
  513. self.llop1 = gc_ll_descr.llop1
  514. self.WB_FUNCPTR = gc_ll_descr.WB_FUNCPTR
  515. self.WB_ARRAY_FUNCPTR = gc_ll_descr.WB_ARRAY_FUNCPTR
  516. self.fielddescr_tid = gc_ll_descr.fielddescr_tid
  517. #
  518. GCClass = gc_ll_descr.GCClass
  519. if GCClass is None: # for tests
  520. return
  521. self.jit_wb_if_flag = GCClass.JIT_WB_IF_FLAG
  522. self.jit_wb_if_flag_byteofs, self.jit_wb_if_flag_singlebyte = (
  523. self.extract_flag_byte(self.jit_wb_if_flag))
  524. #
  525. if hasattr(GCClass, 'JIT_WB_CARDS_SET'):
  526. self.jit_wb_cards_set = GCClass.JIT_WB_CARDS_SET
  527. self.jit_wb_card_page_shift = GCClass.JIT_WB_CARD_PAGE_SHIFT
  528. self.jit_wb_cards_set_byteofs, self.jit_wb_cards_set_singlebyte = (
  529. self.extract_flag_byte(self.jit_wb_cards_set))
  530. else:
  531. self.jit_wb_cards_set = 0
  532. def extract_flag_byte(self, flag_word):
  533. # if convenient for the backend, we compute the info about
  534. # the flag as (byte-offset, single-byte-flag).
  535. import struct
  536. value = struct.pack(lltype.SignedFmt, flag_word)
  537. assert value.count('\x00') == len(value) - 1 # only one byte is != 0
  538. i = 0
  539. while value[i] == '\x00': i += 1
  540. return (i, struct.unpack('b', value[i])[0])
  541. def get_write_barrier_fn(self, cpu):
  542. llop1 = self.llop1
  543. funcptr = llop1.get_write_barrier_failing_case(self.WB_FUNCPTR)
  544. funcaddr = llmemory.cast_ptr_to_adr(funcptr)
  545. return cpu.cast_adr_to_int(funcaddr)
  546. def get_write_barrier_from_array_fn(self, cpu):
  547. # returns a function with arguments [array, index, newvalue]
  548. llop1 = self.llop1
  549. funcptr = llop1.get_write_barrier_from_array_failing_case(
  550. self.WB_ARRAY_FUNCPTR)
  551. funcaddr = llmemory.cast_ptr_to_adr(funcptr)
  552. return cpu.cast_adr_to_int(funcaddr) # this may return 0
  553. def has_write_barrier_from_array(self, cpu):
  554. return self.get_write_barrier_from_array_fn(cpu) != 0
  555. class GcLLDescr_framework(GcLLDescription):
  556. DEBUG = False # forced to True by x86/test/test_zrpy_gc.py
  557. kind = 'framework'
  558. round_up = True
  559. def __init__(self, gcdescr, translator, rtyper, llop1=llop,
  560. really_not_translated=False):
  561. GcLLDescription.__init__(self, gcdescr, translator, rtyper)
  562. self.translator = translator
  563. self.llop1 = llop1
  564. if really_not_translated:
  565. assert not self.translate_support_code # but half does not work
  566. self._initialize_for_tests()
  567. else:
  568. assert self.translate_support_code,"required with the framework GC"
  569. self._check_valid_gc()
  570. self._make_gcrootmap()
  571. self._make_layoutbuilder()
  572. self._setup_gcclass()
  573. self._setup_tid()
  574. self._setup_write_barrier()
  575. self._setup_str()
  576. self._make_functions(really_not_translated)
  577. def _initialize_for_tests(self):
  578. self.layoutbuilder = None
  579. self.fielddescr_tid = AbstractDescr()
  580. self.max_size_of_young_obj = 1000
  581. self.GCClass = None
  582. def _check_valid_gc(self):
  583. # we need the hybrid or minimark GC for rgc._make_sure_does_not_move()
  584. # to work
  585. if self.gcdescr.config.translation.gc not in ('hybrid', 'minimark'):
  586. raise NotImplementedError("--gc=%s not implemented with the JIT" %
  587. (gcdescr.config.translation.gc,))
  588. def _make_gcrootmap(self):
  589. # to find roots in the assembler, make a GcRootMap
  590. name = self.gcdescr.config.translation.gcrootfinder
  591. try:
  592. cls = globals()['GcRootMap_' + name]
  593. except KeyError:
  594. raise NotImplementedError("--gcrootfinder=%s not implemented"
  595. " with the JIT" % (name,))
  596. gcrootmap = cls(self.gcdescr)
  597. self.gcrootmap = gcrootmap
  598. def _make_layoutbuilder(self):
  599. # make a TransformerLayoutBuilder and save it on the translator
  600. # where it can be fished and reused by the FrameworkGCTransformer
  601. from pypy.rpython.memory.gctransform import framework
  602. translator = self.translator
  603. self.layoutbuilder = framework.TransformerLayoutBuilder(translator)
  604. self.layoutbuilder.delay_encoding()
  605. translator._jit2gc = {'layoutbuilder': self.layoutbuilder}
  606. self.gcrootmap.add_jit2gc_hooks(translator._jit2gc)
  607. def _setup_gcclass(self):
  608. from pypy.rpython.memory.gcheader import GCHeaderBuilder
  609. self.GCClass = self.layoutbuilder.GCClass
  610. self.moving_gc = self.GCClass.moving_gc
  611. self.HDRPTR = lltype.Ptr(self.GCClass.HDR)
  612. self.gcheaderbuilder = GCHeaderBuilder(self.HDRPTR.TO)
  613. self.max_size_of_young_obj = self.GCClass.JIT_max_size_of_young_obj()
  614. self.minimal_size_in_nursery=self.GCClass.JIT_minimal_size_in_nursery()
  615. # for the fast path of mallocs, the following must be true, at least
  616. assert self.GCClass.inline_simple_malloc
  617. assert self.GCClass.inline_simple_malloc_varsize
  618. def _setup_tid(self):
  619. self.fielddescr_tid = get_field_descr(self, self.GCClass.HDR, 'tid')
  620. def _setup_write_barrier(self):
  621. self.WB_FUNCPTR = lltype.Ptr(lltype.FuncType(
  622. [llmemory.Address, llmemory.Address], lltype.Void))
  623. self.WB_ARRAY_FUNCPTR = lltype.Ptr(lltype.FuncType(
  624. [llmemory.Address, lltype.Signed, llmemory.Address], lltype.Void))
  625. self.write_barrier_descr = WriteBarrierDescr(self)
  626. def _make_functions(self, really_not_translated):
  627. from pypy.rpython.memory.gctypelayout import check_typeid
  628. llop1 = self.llop1
  629. (self.standard_array_basesize, _, self.standard_array_length_ofs) = \
  630. symbolic.get_array_token(lltype.GcArray(lltype.Signed),
  631. not really_not_translated)
  632. def malloc_nursery_slowpath(size):
  633. """Allocate 'size' null bytes out of the nursery.
  634. Note that the fast path is typically inlined by the backend."""
  635. if self.DEBUG:
  636. self._random_usage_of_xmm_registers()
  637. type_id = rffi.cast(llgroup.HALFWORD, 0) # missing here
  638. return llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
  639. type_id, size,
  640. False, False, False)
  641. self.generate_function('malloc_nursery', malloc_nursery_slowpath,
  642. [lltype.Signed])
  643. def malloc_array(itemsize, tid, num_elem):
  644. """Allocate an array with a variable-size num_elem.
  645. Only works for standard arrays."""
  646. type_id = llop.extract_ushort(llgroup.HALFWORD, tid)
  647. check_typeid(type_id)
  648. return llop1.do_malloc_varsize_clear(
  649. llmemory.GCREF,
  650. type_id, num_elem, self.standard_array_basesize, itemsize,
  651. self.standard_array_length_ofs)
  652. self.generate_function('malloc_array', malloc_array,
  653. [lltype.Signed] * 3)
  654. def malloc_array_nonstandard(basesize, itemsize, lengthofs, tid,
  655. num_elem):
  656. """For the rare case of non-standard arrays, i.e. arrays where
  657. self.standard_array_{basesize,length_ofs} is wrong. It can
  658. occur e.g. with arrays of floats on Win32."""
  659. type_id = llop.extract_ushort(llgroup.HALFWORD, tid)
  660. check_typeid(type_id)
  661. return llop1.do_malloc_varsize_clear(
  662. llmemory.GCREF,
  663. type_id, num_elem, basesize, itemsize, lengthofs)
  664. self.generate_function('malloc_array_nonstandard',
  665. malloc_array_nonstandard,
  666. [lltype.Signed] * 5)
  667. str_type_id = self.str_descr.tid
  668. str_basesize = self.str_descr.basesize
  669. str_itemsize = self.str_descr.itemsize
  670. str_ofs_length = self.str_descr.lendescr.offset
  671. unicode_type_id = self.unicode_descr.tid
  672. unicode_basesize = self.unicode_descr.basesize
  673. unicode_itemsize = self.unicode_descr.itemsize
  674. unicode_ofs_length = self.unicode_descr.lendescr.offset
  675. def malloc_str(length):
  676. return llop1.do_malloc_varsize_clear(
  677. llmemory.GCREF,
  678. str_type_id, length, str_basesize, str_itemsize,
  679. str_ofs_length)
  680. self.generate_function('malloc_str', malloc_str,
  681. [lltype.Signed])
  682. def malloc_unicode(length):
  683. return llop1.do_malloc_varsize_clear(
  684. llmemory.GCREF,
  685. unicode_type_id, length, unicode_basesize, unicode_itemsize,
  686. unicode_ofs_length)
  687. self.generate_function('malloc_unicode', malloc_unicode,
  688. [lltype.Signed])
  689. # Never called as far as I can tell, but there for completeness:
  690. # allocate a fixed-size object, but not in the nursery, because
  691. # it is too big.
  692. def malloc_big_fixedsize(size, tid):
  693. if self.DEBUG:
  694. self._random_usage_of_xmm_registers()
  695. type_id = llop.extract_ushort(llgroup.HALFWORD, tid)
  696. check_typeid(type_id)
  697. return llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
  698. type_id, size,
  699. False, False, False)
  700. self.generate_function('malloc_big_fixedsize', malloc_big_fixedsize,
  701. [lltype.Signed] * 2)
  702. def _bh_malloc(self, sizedescr):
  703. from pypy.rpython.memory.gctypelayout import check_typeid
  704. llop1 = self.llop1
  705. type_id = llop.extract_ushort(llgroup.HALFWORD, sizedescr.tid)
  706. check_typeid(type_id)
  707. return llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
  708. type_id, sizedescr.size,
  709. False, False, False)
  710. def _bh_malloc_array(self, arraydescr, num_elem):
  711. from pypy.rpython.memory.gctypelayout import check_typeid
  712. llop1 = self.llop1
  713. type_id = llop.extract_ushort(llgroup.HALFWORD, arraydescr.tid)
  714. check_typeid(type_id)
  715. return llop1.do_malloc_varsize_clear(llmemory.GCREF,
  716. type_id, num_elem,
  717. arraydescr.basesize,
  718. arraydescr.itemsize,
  719. arraydescr.lendescr.offset)
  720. class ForTestOnly:
  721. pass
  722. for_test_only = ForTestOnly()
  723. for_test_only.x = 1.23
  724. def _random_usage_of_xmm_registers(self):
  725. x0 = self.for_test_only.x
  726. x1 = x0 * 0.1
  727. x2 = x0 * 0.2
  728. x3 = x0 * 0.3
  729. self.for_test_only.x = x0 + x1 + x2 + x3
  730. def get_nursery_free_addr(self):
  731. nurs_addr = llop.gc_adr_of_nursery_free(llmemory.Address)
  732. return rffi.cast(lltype.Signed, nurs_addr)
  733. def get_nursery_top_addr(self):
  734. nurs_top_addr = llop.gc_adr_of_nursery_top(llmemory.Address)
  735. return rffi.cast(lltype.Signed, nurs_top_addr)
  736. def initialize(self):
  737. self.gcrootmap.initialize()
  738. def init_size_descr(self, S, descr):
  739. if self.layoutbuilder is not None:
  740. type_id = self.layoutbuilder.get_type_id(S)
  741. assert not self.layoutbuilder.is_weakref_type(S)
  742. assert not self.layoutbuilder.has_finalizer(S)
  743. descr.tid = llop.combine_ushort(lltype.Signed, type_id, 0)
  744. def init_array_descr(self, A, descr):
  745. if self.layoutbuilder is not None:
  746. type_id = self.layoutbuilder.get_type_id(A)
  747. descr.tid = llop.combine_ushort(lltype.Signed, type_id, 0)
  748. def _set_tid(self, gcptr, tid):
  749. hdr_addr = llmemory.cast_ptr_to_adr(gcptr)
  750. hdr_addr -= self.gcheaderbuilder.size_gc_header
  751. hdr = llmemory.cast_adr_to_ptr(hdr_addr, self.HDRPTR)
  752. hdr.tid = tid
  753. def do_write_barrier(self, gcref_struct, gcref_newptr):
  754. hdr_addr = llmemory.cast_ptr_to_adr(gcref_struct)
  755. hdr_addr -= self.gcheaderbuilder.size_gc_header
  756. hdr = llmemory.cast_adr_to_ptr(hdr_addr, self.HDRPTR)
  757. if hdr.tid & self.GCClass.JIT_WB_IF_FLAG:
  758. # get a pointer to the 'remember_young_pointer' function from
  759. # the GC, and call it immediately
  760. llop1 = self.llop1
  761. funcptr = llop1.get_write_barrier_failing_case(self.WB_FUNCPTR)
  762. funcptr(llmemory.cast_ptr_to_adr(gcref_struct),
  763. llmemory.cast_ptr_to_adr(gcref_newptr))
  764. def can_use_nursery_malloc(self, size):
  765. return size < self.max_size_of_young_obj
  766. def has_write_barrier_class(self):
  767. return WriteBarrierDescr
  768. def freeing_block(self, start, stop):
  769. self.gcrootmap.freeing_block(start, stop)
  770. def get_malloc_slowpath_addr(self):
  771. return self.get_malloc_fn_addr('malloc_nursery')
  772. # ____________________________________________________________
  773. def get_ll_description(gcdescr, translator=None, rtyper=None):
  774. # translator is None if translate_support_code is False.
  775. if gcdescr is not None:
  776. name = gcdescr.config.translation.gctransformer
  777. else:
  778. name = "boehm"
  779. try:
  780. cls = globals()['GcLLDescr_' + name]
  781. except KeyError:
  782. raise NotImplementedError("GC transformer %r not supported by "
  783. "the JIT backend" % (name,))
  784. return cls(gcdescr, translator, rtyper)