PageRenderTime 50ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/rpython/jit/backend/llsupport/gc.py

https://bitbucket.org/pypy/pypy/
Python | 667 lines | 638 code | 17 blank | 12 comment | 6 complexity | 6b931234e58c6be996d7b83922e849b4 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import os
  2. from rpython.rlib import rgc
  3. from rpython.rlib.objectmodel import we_are_translated, specialize
  4. from rpython.rlib.rarithmetic import ovfcheck
  5. from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, rstr
  6. from rpython.rtyper import rclass
  7. from rpython.rtyper.lltypesystem import llgroup
  8. from rpython.rtyper.lltypesystem.lloperation import llop
  9. from rpython.rtyper.annlowlevel import llhelper, cast_instance_to_gcref
  10. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  11. from rpython.jit.codewriter import heaptracker
  12. from rpython.jit.metainterp.history import ConstPtr, AbstractDescr, ConstInt
  13. from rpython.jit.metainterp.resoperation import rop, ResOperation
  14. from rpython.jit.backend.llsupport import symbolic, jitframe
  15. from rpython.jit.backend.llsupport.symbolic import WORD
  16. from rpython.jit.backend.llsupport.descr import SizeDescr, ArrayDescr, FieldDescr
  17. from rpython.jit.backend.llsupport.descr import GcCache, get_field_descr
  18. from rpython.jit.backend.llsupport.descr import get_array_descr
  19. from rpython.jit.backend.llsupport.descr import get_call_descr
  20. from rpython.jit.backend.llsupport.descr import unpack_arraydescr
  21. from rpython.jit.backend.llsupport.rewrite import GcRewriterAssembler
  22. from rpython.memory.gctransform import asmgcroot
  23. from rpython.jit.codewriter.effectinfo import EffectInfo
  24. # ____________________________________________________________
  25. class GcLLDescription(GcCache):
  26. def __init__(self, gcdescr, translator=None, rtyper=None):
  27. GcCache.__init__(self, translator is not None, rtyper)
  28. self.gcdescr = gcdescr
  29. if translator and translator.config.translation.gcremovetypeptr:
  30. self.fielddescr_vtable = None
  31. else:
  32. self.fielddescr_vtable = get_field_descr(self, rclass.OBJECT,
  33. 'typeptr')
  34. self._generated_functions = []
  35. def _setup_str(self):
  36. self.str_descr = get_array_descr(self, rstr.STR)
  37. self.unicode_descr = get_array_descr(self, rstr.UNICODE)
  38. self.str_hash_descr = get_field_descr(self, rstr.STR, 'hash')
  39. self.unicode_hash_descr = get_field_descr(self, rstr.UNICODE, 'hash')
  40. def generate_function(self, funcname, func, ARGS, RESULT=llmemory.GCREF):
  41. """Generates a variant of malloc with the given name and the given
  42. arguments. It should return NULL if out of memory. If it raises
  43. anything, it must be an optional MemoryError.
  44. """
  45. FUNCPTR = lltype.Ptr(lltype.FuncType(ARGS, RESULT))
  46. # Note: the call may invoke the GC, which may run finalizers.
  47. # Finalizers are constrained in what they can do, but we can't
  48. # really express that in a useful way here.
  49. descr = get_call_descr(self, ARGS, RESULT, EffectInfo.MOST_GENERAL)
  50. setattr(self, funcname, func)
  51. setattr(self, funcname + '_FUNCPTR', FUNCPTR)
  52. setattr(self, funcname + '_descr', descr)
  53. self._generated_functions.append(funcname)
  54. @specialize.arg(1)
  55. def get_malloc_fn(self, funcname):
  56. func = getattr(self, funcname)
  57. FUNC = getattr(self, funcname + '_FUNCPTR')
  58. return llhelper(FUNC, func)
  59. @specialize.arg(1)
  60. def get_malloc_fn_addr(self, funcname):
  61. ll_func = self.get_malloc_fn(funcname)
  62. return heaptracker.adr2int(llmemory.cast_ptr_to_adr(ll_func))
  63. def _freeze_(self):
  64. return True
  65. def initialize(self):
  66. pass
  67. def can_use_nursery_malloc(self, size):
  68. return False
  69. def has_write_barrier_class(self):
  70. return None
  71. def get_nursery_free_addr(self):
  72. raise NotImplementedError
  73. def get_nursery_top_addr(self):
  74. raise NotImplementedError
  75. def freeing_block(self, rawstart, rawstop):
  76. pass
  77. def gc_malloc(self, sizedescr):
  78. """Blackhole: do a 'bh_new'. Also used for 'bh_new_with_vtable',
  79. with the vtable pointer set manually afterwards."""
  80. assert isinstance(sizedescr, SizeDescr)
  81. return self._bh_malloc(sizedescr)
  82. def gc_malloc_array(self, num_elem, arraydescr):
  83. assert isinstance(arraydescr, ArrayDescr)
  84. return self._bh_malloc_array(num_elem, arraydescr)
  85. def gc_malloc_str(self, num_elem):
  86. return self._bh_malloc_array(num_elem, self.str_descr)
  87. def gc_malloc_unicode(self, num_elem):
  88. return self._bh_malloc_array(num_elem, self.unicode_descr)
  89. def rewrite_assembler(self, cpu, operations, gcrefs_output_list):
  90. rewriter = GcRewriterAssembler(self, cpu)
  91. newops = rewriter.rewrite(operations, gcrefs_output_list)
  92. return newops
  93. @specialize.memo()
  94. def getframedescrs(self, cpu):
  95. descrs = JitFrameDescrs()
  96. descrs.arraydescr = cpu.arraydescrof(jitframe.JITFRAME)
  97. for name in ['jf_descr', 'jf_guard_exc', 'jf_force_descr',
  98. 'jf_frame_info', 'jf_gcmap', 'jf_extra_stack_depth',
  99. 'jf_savedata', 'jf_forward']:
  100. setattr(descrs, name, cpu.fielddescrof(jitframe.JITFRAME, name))
  101. descrs.jfi_frame_size = cpu.fielddescrof(jitframe.JITFRAMEINFO,
  102. 'jfi_frame_size')
  103. descrs.jfi_frame_depth = cpu.fielddescrof(jitframe.JITFRAMEINFO,
  104. 'jfi_frame_depth')
  105. return descrs
  106. def getarraydescr_for_frame(self, type):
  107. """ This functions retuns an arraydescr of type for the JITFRAME"""
  108. raise NotImplementedError
  109. def malloc_jitframe(self, frame_info):
  110. """ Allocate a new frame, overwritten by tests
  111. """
  112. return jitframe.JITFRAME.allocate(frame_info)
  113. def make_gcref_tracer(self, array_base_addr, gcrefs):
  114. # for tests, or for Boehm. Overridden for framework GCs
  115. from rpython.jit.backend.llsupport import gcreftracer
  116. return gcreftracer.make_boehm_tracer(array_base_addr, gcrefs)
  117. def clear_gcref_tracer(self, tracer):
  118. pass # nothing needed unless overridden
  119. class JitFrameDescrs:
  120. def _freeze_(self):
  121. return True
  122. # ____________________________________________________________
  123. class GcLLDescr_boehm(GcLLDescription):
  124. kind = 'boehm'
  125. malloc_zero_filled = True
  126. moving_gc = False
  127. round_up = False
  128. write_barrier_descr = None
  129. fielddescr_tid = None
  130. gcrootmap = None
  131. str_type_id = 0
  132. unicode_type_id = 0
  133. get_malloc_slowpath_addr = None
  134. supports_guard_gc_type = False
  135. def is_shadow_stack(self):
  136. return False
  137. @classmethod
  138. def configure_boehm_once(cls):
  139. """ Configure boehm only once, since we don't cache failures
  140. """
  141. if hasattr(cls, 'malloc_fn_ptr'):
  142. return cls.malloc_fn_ptr
  143. from rpython.rtyper.tool import rffi_platform
  144. compilation_info = rffi_platform.configure_boehm()
  145. # on some platform GC_init is required before any other
  146. # GC_* functions, call it here for the benefit of tests
  147. # XXX move this to tests
  148. init_fn_ptr = rffi.llexternal("GC_init",
  149. [], lltype.Void,
  150. compilation_info=compilation_info,
  151. sandboxsafe=True,
  152. _nowrapper=True)
  153. init_fn_ptr()
  154. # Versions 6.x of libgc needs to use GC_local_malloc().
  155. # Versions 7.x of libgc removed this function; GC_malloc() has
  156. # the same behavior if libgc was compiled with
  157. # THREAD_LOCAL_ALLOC.
  158. class CConfig:
  159. _compilation_info_ = compilation_info
  160. HAS_LOCAL_MALLOC = rffi_platform.Has("GC_local_malloc")
  161. config = rffi_platform.configure(CConfig)
  162. if config['HAS_LOCAL_MALLOC']:
  163. GC_MALLOC = "GC_local_malloc"
  164. else:
  165. GC_MALLOC = "GC_malloc"
  166. malloc_fn_ptr = rffi.llexternal(GC_MALLOC,
  167. [lltype.Signed], # size_t, but good enough
  168. llmemory.GCREF,
  169. compilation_info=compilation_info,
  170. sandboxsafe=True,
  171. _nowrapper=True)
  172. cls.malloc_fn_ptr = malloc_fn_ptr
  173. return malloc_fn_ptr
  174. def __init__(self, gcdescr, translator, rtyper):
  175. GcLLDescription.__init__(self, gcdescr, translator, rtyper)
  176. # grab a pointer to the Boehm 'malloc' function
  177. self.malloc_fn_ptr = self.configure_boehm_once()
  178. self._setup_str()
  179. self._make_functions()
  180. self.memory = 0
  181. def _make_functions(self):
  182. def malloc_fixedsize(size):
  183. return self.malloc_fn_ptr(size)
  184. self.generate_function('malloc_fixedsize', malloc_fixedsize,
  185. [lltype.Signed])
  186. def malloc_array(basesize, num_elem, itemsize, ofs_length):
  187. try:
  188. totalsize = ovfcheck(basesize + ovfcheck(itemsize * num_elem))
  189. except OverflowError:
  190. return lltype.nullptr(llmemory.GCREF.TO)
  191. res = self.malloc_fn_ptr(totalsize)
  192. if res:
  193. arrayptr = rffi.cast(rffi.CArrayPtr(lltype.Signed), res)
  194. arrayptr[ofs_length/WORD] = num_elem
  195. return res
  196. self.generate_function('malloc_array', malloc_array,
  197. [lltype.Signed] * 4)
  198. def _bh_malloc(self, sizedescr):
  199. return self.malloc_fixedsize(sizedescr.size)
  200. def _bh_malloc_array(self, num_elem, arraydescr):
  201. return self.malloc_array(arraydescr.basesize, num_elem,
  202. arraydescr.itemsize,
  203. arraydescr.lendescr.offset)
  204. # ____________________________________________________________
  205. # All code below is for the hybrid or minimark GC
  206. class GcRootMap_asmgcc(object):
  207. is_shadow_stack = False
  208. def __init__(self, gcdescr):
  209. pass
  210. def register_asm_addr(self, start, mark):
  211. pass
  212. class GcRootMap_shadowstack(object):
  213. is_shadow_stack = True
  214. def __init__(self, gcdescr):
  215. pass
  216. def register_asm_addr(self, start, mark):
  217. pass
  218. def get_root_stack_top_addr(self):
  219. rst_addr = llop.gc_adr_of_root_stack_top(llmemory.Address)
  220. return rffi.cast(lltype.Signed, rst_addr)
  221. class WriteBarrierDescr(AbstractDescr):
  222. def __init__(self, gc_ll_descr):
  223. self.llop1 = gc_ll_descr.llop1
  224. self.WB_FUNCPTR = gc_ll_descr.WB_FUNCPTR
  225. self.fielddescr_tid = gc_ll_descr.fielddescr_tid
  226. #
  227. GCClass = gc_ll_descr.GCClass
  228. if GCClass is None: # for tests
  229. return
  230. self.jit_wb_if_flag = GCClass.JIT_WB_IF_FLAG
  231. self.jit_wb_if_flag_byteofs, self.jit_wb_if_flag_singlebyte = (
  232. self.extract_flag_byte(self.jit_wb_if_flag))
  233. #
  234. if hasattr(GCClass, 'JIT_WB_CARDS_SET'):
  235. self.jit_wb_cards_set = GCClass.JIT_WB_CARDS_SET
  236. self.jit_wb_card_page_shift = GCClass.JIT_WB_CARD_PAGE_SHIFT
  237. self.jit_wb_cards_set_byteofs, self.jit_wb_cards_set_singlebyte = (
  238. self.extract_flag_byte(self.jit_wb_cards_set))
  239. #
  240. # the x86 backend uses the following "accidental" facts to
  241. # avoid one instruction:
  242. assert self.jit_wb_cards_set_byteofs == self.jit_wb_if_flag_byteofs
  243. assert self.jit_wb_cards_set_singlebyte == -0x80
  244. else:
  245. self.jit_wb_cards_set = 0
  246. def extract_flag_byte(self, flag_word):
  247. # if convenient for the backend, we compute the info about
  248. # the flag as (byte-offset, single-byte-flag).
  249. import struct
  250. value = struct.pack(lltype.SignedFmt, flag_word)
  251. assert value.count('\x00') == len(value) - 1 # only one byte is != 0
  252. i = 0
  253. while value[i] == '\x00': i += 1
  254. return (i, struct.unpack('b', value[i])[0])
  255. def get_write_barrier_fn(self, cpu):
  256. llop1 = self.llop1
  257. funcptr = llop1.get_write_barrier_failing_case(self.WB_FUNCPTR)
  258. funcaddr = llmemory.cast_ptr_to_adr(funcptr)
  259. return cpu.cast_adr_to_int(funcaddr)
  260. def get_write_barrier_from_array_fn(self, cpu):
  261. # returns a function with arguments [array, index, newvalue]
  262. llop1 = self.llop1
  263. funcptr = llop1.get_write_barrier_from_array_failing_case(
  264. self.WB_FUNCPTR)
  265. funcaddr = llmemory.cast_ptr_to_adr(funcptr)
  266. return cpu.cast_adr_to_int(funcaddr) # this may return 0
  267. def has_write_barrier_from_array(self, cpu):
  268. return self.get_write_barrier_from_array_fn(cpu) != 0
  269. class GcLLDescr_framework(GcLLDescription):
  270. DEBUG = False # forced to True by x86/test/test_zrpy_gc.py
  271. kind = 'framework'
  272. round_up = True
  273. layoutbuilder = None
  274. supports_guard_gc_type = True
  275. def is_shadow_stack(self):
  276. return self.gcrootmap.is_shadow_stack
  277. def __init__(self, gcdescr, translator, rtyper, llop1=llop,
  278. really_not_translated=False):
  279. GcLLDescription.__init__(self, gcdescr, translator, rtyper)
  280. self.translator = translator
  281. self.llop1 = llop1
  282. if really_not_translated:
  283. assert not self.translate_support_code # but half does not work
  284. self._initialize_for_tests()
  285. else:
  286. assert self.translate_support_code,"required with the framework GC"
  287. self._check_valid_gc()
  288. self._make_layoutbuilder()
  289. self._make_gcrootmap()
  290. self._setup_gcclass()
  291. self._setup_tid()
  292. self._setup_guard_is_object()
  293. self._setup_write_barrier()
  294. self._setup_str()
  295. self._make_functions(really_not_translated)
  296. def _make_gcrootmap(self):
  297. # to find roots in the assembler, make a GcRootMap
  298. name = self.gcdescr.config.translation.gcrootfinder
  299. try:
  300. cls = globals()['GcRootMap_' + name]
  301. except KeyError:
  302. raise NotImplementedError("--gcrootfinder=%s not implemented"
  303. " with the JIT" % (name,))
  304. gcrootmap = cls(self.gcdescr)
  305. self.gcrootmap = gcrootmap
  306. def _initialize_for_tests(self):
  307. self.layoutbuilder = None
  308. self.fielddescr_tid = FieldDescr("test_tid",0,8,0)
  309. self.max_size_of_young_obj = 1000
  310. self.GCClass = None
  311. def _check_valid_gc(self):
  312. # we need the hybrid or minimark GC for rgc._make_sure_does_not_move()
  313. # to work. 'hybrid' could work but isn't tested with the JIT.
  314. if self.gcdescr.config.translation.gc not in ('minimark',
  315. 'incminimark'):
  316. raise NotImplementedError("--gc=%s not implemented with the JIT" %
  317. (self.gcdescr.config.translation.gc,))
  318. def _make_layoutbuilder(self):
  319. # make a TransformerLayoutBuilder and save it on the translator
  320. # where it can be fished and reused by the FrameworkGCTransformer
  321. from rpython.memory.gctransform import framework
  322. translator = self.translator
  323. self.layoutbuilder = framework.TransformerLayoutBuilder(translator)
  324. self.layoutbuilder.delay_encoding()
  325. if not hasattr(translator, '_jit2gc'):
  326. translator._jit2gc = {}
  327. translator._jit2gc['layoutbuilder'] = self.layoutbuilder
  328. def _setup_gcclass(self):
  329. from rpython.memory.gcheader import GCHeaderBuilder
  330. self.GCClass = self.layoutbuilder.GCClass
  331. self.moving_gc = self.GCClass.moving_gc
  332. self.malloc_zero_filled = self.GCClass.malloc_zero_filled
  333. self.HDRPTR = lltype.Ptr(self.GCClass.HDR)
  334. self.gcheaderbuilder = GCHeaderBuilder(self.HDRPTR.TO)
  335. self.max_size_of_young_obj = self.GCClass.JIT_max_size_of_young_obj()
  336. self.minimal_size_in_nursery=self.GCClass.JIT_minimal_size_in_nursery()
  337. # for the fast path of mallocs, the following must be true, at least
  338. assert self.GCClass.inline_simple_malloc
  339. assert self.GCClass.inline_simple_malloc_varsize
  340. def _setup_tid(self):
  341. self.fielddescr_tid = get_field_descr(self, self.GCClass.HDR, 'tid')
  342. frame_tid = self.layoutbuilder.get_type_id(jitframe.JITFRAME)
  343. self.translator._jit2gc['frame_tid'] = frame_tid
  344. def _setup_write_barrier(self):
  345. self.WB_FUNCPTR = lltype.Ptr(lltype.FuncType(
  346. [llmemory.Address], lltype.Void))
  347. self.write_barrier_descr = WriteBarrierDescr(self)
  348. def _make_functions(self, really_not_translated):
  349. from rpython.memory.gctypelayout import check_typeid
  350. llop1 = self.llop1
  351. (self.standard_array_basesize, _, self.standard_array_length_ofs) = \
  352. symbolic.get_array_token(lltype.GcArray(lltype.Signed),
  353. not really_not_translated)
  354. def malloc_nursery_slowpath(size):
  355. """Allocate 'size' null bytes out of the nursery.
  356. Note that the fast path is typically inlined by the backend."""
  357. assert size >= self.minimal_size_in_nursery
  358. if self.DEBUG:
  359. self._random_usage_of_xmm_registers()
  360. type_id = rffi.cast(llgroup.HALFWORD, 0) # missing here
  361. return llop1.do_malloc_fixedsize(llmemory.GCREF,
  362. type_id, size,
  363. False, False, False)
  364. self.generate_function('malloc_nursery', malloc_nursery_slowpath,
  365. [lltype.Signed])
  366. def malloc_array(itemsize, tid, num_elem):
  367. """Allocate an array with a variable-size num_elem.
  368. Only works for standard arrays."""
  369. assert num_elem >= 0, 'num_elem should be >= 0'
  370. type_id = llop.extract_ushort(llgroup.HALFWORD, tid)
  371. check_typeid(type_id)
  372. return llop1.do_malloc_varsize_clear(
  373. llmemory.GCREF,
  374. type_id, num_elem, self.standard_array_basesize, itemsize,
  375. self.standard_array_length_ofs)
  376. self.generate_function('malloc_array', malloc_array,
  377. [lltype.Signed] * 3)
  378. def malloc_array_nonstandard(basesize, itemsize, lengthofs, tid,
  379. num_elem):
  380. """For the rare case of non-standard arrays, i.e. arrays where
  381. self.standard_array_{basesize,length_ofs} is wrong. It can
  382. occur e.g. with arrays of floats on Win32."""
  383. type_id = llop.extract_ushort(llgroup.HALFWORD, tid)
  384. check_typeid(type_id)
  385. return llop1.do_malloc_varsize_clear(
  386. llmemory.GCREF,
  387. type_id, num_elem, basesize, itemsize, lengthofs)
  388. self.generate_function('malloc_array_nonstandard',
  389. malloc_array_nonstandard,
  390. [lltype.Signed] * 5)
  391. str_type_id = self.str_descr.tid
  392. str_basesize = self.str_descr.basesize
  393. str_itemsize = self.str_descr.itemsize
  394. str_ofs_length = self.str_descr.lendescr.offset
  395. unicode_type_id = self.unicode_descr.tid
  396. unicode_basesize = self.unicode_descr.basesize
  397. unicode_itemsize = self.unicode_descr.itemsize
  398. unicode_ofs_length = self.unicode_descr.lendescr.offset
  399. def malloc_str(length):
  400. type_id = llop.extract_ushort(llgroup.HALFWORD, str_type_id)
  401. return llop1.do_malloc_varsize(
  402. llmemory.GCREF,
  403. type_id, length, str_basesize, str_itemsize,
  404. str_ofs_length)
  405. self.generate_function('malloc_str', malloc_str,
  406. [lltype.Signed])
  407. def malloc_unicode(length):
  408. type_id = llop.extract_ushort(llgroup.HALFWORD, unicode_type_id)
  409. return llop1.do_malloc_varsize(
  410. llmemory.GCREF,
  411. type_id, length, unicode_basesize, unicode_itemsize,
  412. unicode_ofs_length)
  413. self.generate_function('malloc_unicode', malloc_unicode,
  414. [lltype.Signed])
  415. # Never called as far as I can tell, but there for completeness:
  416. # allocate a fixed-size object, but not in the nursery, because
  417. # it is too big.
  418. def malloc_big_fixedsize(size, tid):
  419. if self.DEBUG:
  420. self._random_usage_of_xmm_registers()
  421. type_id = llop.extract_ushort(llgroup.HALFWORD, tid)
  422. check_typeid(type_id)
  423. return llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
  424. type_id, size,
  425. False, False, False)
  426. self.generate_function('malloc_big_fixedsize', malloc_big_fixedsize,
  427. [lltype.Signed] * 2)
  428. def _bh_malloc(self, sizedescr):
  429. from rpython.memory.gctypelayout import check_typeid
  430. llop1 = self.llop1
  431. type_id = llop.extract_ushort(llgroup.HALFWORD, sizedescr.tid)
  432. check_typeid(type_id)
  433. return llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
  434. type_id, sizedescr.size,
  435. False, False, False)
  436. def _bh_malloc_array(self, num_elem, arraydescr):
  437. from rpython.memory.gctypelayout import check_typeid
  438. llop1 = self.llop1
  439. type_id = llop.extract_ushort(llgroup.HALFWORD, arraydescr.tid)
  440. check_typeid(type_id)
  441. return llop1.do_malloc_varsize_clear(llmemory.GCREF,
  442. type_id, num_elem,
  443. arraydescr.basesize,
  444. arraydescr.itemsize,
  445. arraydescr.lendescr.offset)
  446. class ForTestOnly:
  447. pass
  448. for_test_only = ForTestOnly()
  449. for_test_only.x = 1.23
  450. def _random_usage_of_xmm_registers(self):
  451. x0 = self.for_test_only.x
  452. x1 = x0 * 0.1
  453. x2 = x0 * 0.2
  454. x3 = x0 * 0.3
  455. self.for_test_only.x = x0 + x1 + x2 + x3
  456. def get_nursery_free_addr(self):
  457. nurs_addr = llop.gc_adr_of_nursery_free(llmemory.Address)
  458. return rffi.cast(lltype.Signed, nurs_addr)
  459. def get_nursery_top_addr(self):
  460. nurs_top_addr = llop.gc_adr_of_nursery_top(llmemory.Address)
  461. return rffi.cast(lltype.Signed, nurs_top_addr)
  462. def initialize(self):
  463. pass
  464. #self.gcrootmap.initialize()
  465. def init_size_descr(self, S, descr):
  466. if not isinstance(S, lltype.GcStruct):
  467. return
  468. if self.layoutbuilder is not None:
  469. type_id = self.layoutbuilder.get_type_id(S)
  470. descr.tid = llop.combine_ushort(lltype.Signed, type_id, 0)
  471. def init_array_descr(self, A, descr):
  472. if not isinstance(A, (lltype.GcArray, lltype.GcStruct)):
  473. return
  474. if self.layoutbuilder is not None:
  475. type_id = self.layoutbuilder.get_type_id(A)
  476. descr.tid = llop.combine_ushort(lltype.Signed, type_id, 0)
  477. def can_use_nursery_malloc(self, size):
  478. return size < self.max_size_of_young_obj
  479. def has_write_barrier_class(self):
  480. return WriteBarrierDescr
  481. def get_malloc_slowpath_addr(self):
  482. return self.get_malloc_fn_addr('malloc_nursery')
  483. def get_malloc_slowpath_array_addr(self):
  484. return self.get_malloc_fn_addr('malloc_array')
  485. def get_typeid_from_classptr_if_gcremovetypeptr(self, classptr):
  486. """Returns the typeid corresponding from a vtable pointer 'classptr'.
  487. This function only works if cpu.vtable_offset is None, i.e. in
  488. a translation with --gcremovetypeptr.
  489. """
  490. from rpython.memory.gctypelayout import GCData
  491. assert self.gcdescr.config.translation.gcremovetypeptr
  492. # hard-coded assumption: to go from an object to its class
  493. # we would use the following algorithm:
  494. # - read the typeid from mem(locs[0]), i.e. at offset 0;
  495. # this is a complete word (N=4 bytes on 32-bit, N=8 on
  496. # 64-bits)
  497. # - keep the lower half of what is read there (i.e.
  498. # truncate to an unsigned 'N / 2' bytes value)
  499. # - multiply by 4 (on 32-bits only) and use it as an
  500. # offset in type_info_group
  501. # - add 16/32 bytes, to go past the TYPE_INFO structure
  502. # here, we have to go back from 'classptr' back to the typeid,
  503. # so we do (part of) these computations in reverse.
  504. sizeof_ti = rffi.sizeof(GCData.TYPE_INFO)
  505. type_info_group = llop.gc_get_type_info_group(llmemory.Address)
  506. type_info_group = rffi.cast(lltype.Signed, type_info_group)
  507. expected_typeid = classptr - sizeof_ti - type_info_group
  508. if WORD == 4:
  509. expected_typeid >>= 2
  510. return expected_typeid
  511. def get_translated_info_for_typeinfo(self):
  512. from rpython.memory.gctypelayout import GCData
  513. type_info_group = llop.gc_get_type_info_group(llmemory.Address)
  514. type_info_group = rffi.cast(lltype.Signed, type_info_group)
  515. if WORD == 4:
  516. shift_by = 2
  517. elif WORD == 8:
  518. shift_by = 0
  519. sizeof_ti = rffi.sizeof(GCData.TYPE_INFO)
  520. return (type_info_group, shift_by, sizeof_ti)
  521. def _setup_guard_is_object(self):
  522. from rpython.memory.gctypelayout import GCData, T_IS_RPYTHON_INSTANCE
  523. import struct
  524. infobits_offset, _ = symbolic.get_field_token(GCData.TYPE_INFO,
  525. 'infobits', True)
  526. # compute the offset to the actual *byte*, and the byte mask
  527. mask = struct.pack("l", T_IS_RPYTHON_INSTANCE)
  528. assert mask.count('\x00') == len(mask) - 1
  529. infobits_offset_plus = 0
  530. while mask.startswith('\x00'):
  531. infobits_offset_plus += 1
  532. mask = mask[1:]
  533. self._infobits_offset = infobits_offset
  534. self._infobits_offset_plus = infobits_offset_plus
  535. self._T_IS_RPYTHON_INSTANCE_BYTE = ord(mask[0])
  536. def get_translated_info_for_guard_is_object(self):
  537. infobits_offset = rffi.cast(lltype.Signed, self._infobits_offset)
  538. infobits_offset += self._infobits_offset_plus
  539. return (infobits_offset, self._T_IS_RPYTHON_INSTANCE_BYTE)
  540. def get_actual_typeid(self, gcptr):
  541. # Read the whole GC header word. Return the typeid from the
  542. # lower half-word.
  543. hdr = rffi.cast(self.HDRPTR, gcptr)
  544. type_id = llop.extract_ushort(llgroup.HALFWORD, hdr.tid)
  545. return llop.combine_ushort(lltype.Signed, type_id, 0)
  546. def check_is_object(self, gcptr):
  547. # read the typeid, fetch one byte of the field 'infobits' from
  548. # the big typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'.
  549. typeid = self.get_actual_typeid(gcptr)
  550. #
  551. base_type_info, shift_by, sizeof_ti = (
  552. self.get_translated_info_for_typeinfo())
  553. infobits_offset, IS_OBJECT_FLAG = (
  554. self.get_translated_info_for_guard_is_object())
  555. p = base_type_info + (typeid << shift_by) + infobits_offset
  556. p = rffi.cast(rffi.CCHARP, p)
  557. return (ord(p[0]) & IS_OBJECT_FLAG) != 0
  558. def make_gcref_tracer(self, array_base_addr, gcrefs):
  559. from rpython.jit.backend.llsupport import gcreftracer
  560. return gcreftracer.make_framework_tracer(array_base_addr, gcrefs)
  561. def clear_gcref_tracer(self, tracer):
  562. tracer.array_length = 0
  563. # ____________________________________________________________
  564. def get_ll_description(gcdescr, translator=None, rtyper=None):
  565. # translator is None if translate_support_code is False.
  566. if gcdescr is not None:
  567. name = gcdescr.config.translation.gctransformer
  568. else:
  569. name = "boehm"
  570. try:
  571. cls = globals()['GcLLDescr_' + name]
  572. except KeyError:
  573. raise NotImplementedError("GC transformer %r not supported by "
  574. "the JIT backend" % (name,))
  575. return cls(gcdescr, translator, rtyper)