PageRenderTime 31ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/pypy/rpython/memory/gctransform/framework.py

https://bitbucket.org/pypy/pypy/
Python | 1386 lines | 1238 code | 89 blank | 59 comment | 135 complexity | 3ad508ff071bb02f6de7cc39cb3a0bda MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. from pypy.rpython.memory.gctransform.transform import GCTransformer
  2. from pypy.rpython.memory.gctransform.support import find_gc_ptrs_in_type, \
  3. get_rtti, ll_call_destructor, type_contains_pyobjs, var_ispyobj
  4. from pypy.rpython.lltypesystem import lltype, llmemory, rffi, llgroup
  5. from pypy.rpython import rmodel
  6. from pypy.rpython.memory import gctypelayout
  7. from pypy.rpython.memory.gc import marksweep
  8. from pypy.rpython.memory.gcheader import GCHeaderBuilder
  9. from pypy.rlib.rarithmetic import ovfcheck
  10. from pypy.rlib import rgc
  11. from pypy.rlib.debug import ll_assert
  12. from pypy.rlib.objectmodel import we_are_translated
  13. from pypy.translator.backendopt import graphanalyze
  14. from pypy.translator.backendopt.support import var_needsgc
  15. from pypy.translator.backendopt.finalizer import FinalizerAnalyzer
  16. from pypy.annotation import model as annmodel
  17. from pypy.rpython import annlowlevel
  18. from pypy.rpython.rbuiltin import gen_cast
  19. from pypy.rpython.memory.gctypelayout import ll_weakref_deref, WEAKREF
  20. from pypy.rpython.memory.gctypelayout import convert_weakref_to, WEAKREFPTR
  21. from pypy.rpython.memory.gctransform.log import log
  22. from pypy.tool.sourcetools import func_with_new_name
  23. from pypy.rpython.lltypesystem.lloperation import llop, LL_OPERATIONS
  24. import sys, types
  25. TYPE_ID = llgroup.HALFWORD
  26. class CollectAnalyzer(graphanalyze.BoolGraphAnalyzer):
  27. def analyze_direct_call(self, graph, seen=None):
  28. try:
  29. func = graph.func
  30. except AttributeError:
  31. pass
  32. else:
  33. if getattr(func, '_gctransformer_hint_cannot_collect_', False):
  34. return False
  35. if getattr(func, '_gctransformer_hint_close_stack_', False):
  36. return True
  37. return graphanalyze.GraphAnalyzer.analyze_direct_call(self, graph,
  38. seen)
  39. def analyze_external_call(self, op, seen=None):
  40. funcobj = op.args[0].value._obj
  41. if getattr(funcobj, 'random_effects_on_gcobjs', False):
  42. return True
  43. return graphanalyze.GraphAnalyzer.analyze_external_call(self, op,
  44. seen)
  45. def analyze_simple_operation(self, op, graphinfo):
  46. if op.opname in ('malloc', 'malloc_varsize'):
  47. flags = op.args[1].value
  48. return flags['flavor'] == 'gc'
  49. else:
  50. return (op.opname in LL_OPERATIONS and
  51. LL_OPERATIONS[op.opname].canmallocgc)
  52. def find_initializing_stores(collect_analyzer, graph):
  53. from pypy.objspace.flow.model import mkentrymap
  54. entrymap = mkentrymap(graph)
  55. # a bit of a hackish analysis: if a block contains a malloc and check that
  56. # the result is not zero, then the block following the True link will
  57. # usually initialize the newly allocated object
  58. result = set()
  59. def find_in_block(block, mallocvars):
  60. for i, op in enumerate(block.operations):
  61. if op.opname in ("cast_pointer", "same_as"):
  62. if op.args[0] in mallocvars:
  63. mallocvars[op.result] = True
  64. elif op.opname in ("setfield", "setarrayitem", "setinteriorfield"):
  65. TYPE = op.args[-1].concretetype
  66. if (op.args[0] in mallocvars and
  67. isinstance(TYPE, lltype.Ptr) and
  68. TYPE.TO._gckind == "gc"):
  69. result.add(op)
  70. else:
  71. if collect_analyzer.analyze(op):
  72. return
  73. for exit in block.exits:
  74. if len(entrymap[exit.target]) != 1:
  75. continue
  76. newmallocvars = {}
  77. for i, var in enumerate(exit.args):
  78. if var in mallocvars:
  79. newmallocvars[exit.target.inputargs[i]] = True
  80. if newmallocvars:
  81. find_in_block(exit.target, newmallocvars)
  82. mallocnum = 0
  83. blockset = set(graph.iterblocks())
  84. while blockset:
  85. block = blockset.pop()
  86. if len(block.operations) < 2:
  87. continue
  88. mallocop = block.operations[-2]
  89. checkop = block.operations[-1]
  90. if not (mallocop.opname == "malloc" and
  91. checkop.opname == "ptr_nonzero" and
  92. mallocop.result is checkop.args[0] and
  93. block.exitswitch is checkop.result):
  94. continue
  95. rtti = get_rtti(mallocop.args[0].value)
  96. if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'):
  97. continue
  98. exits = [exit for exit in block.exits if exit.llexitcase]
  99. if len(exits) != 1:
  100. continue
  101. exit = exits[0]
  102. if len(entrymap[exit.target]) != 1:
  103. continue
  104. try:
  105. index = exit.args.index(mallocop.result)
  106. except ValueError:
  107. continue
  108. target = exit.target
  109. mallocvars = {target.inputargs[index]: True}
  110. mallocnum += 1
  111. find_in_block(target, mallocvars)
  112. #if result:
  113. # print "found %s initializing stores in %s" % (len(result), graph.name)
  114. return result
  115. def find_clean_setarrayitems(collect_analyzer, graph):
  116. result = set()
  117. for block in graph.iterblocks():
  118. cache = set()
  119. for op in block.operations:
  120. if op.opname == 'getarrayitem':
  121. cache.add((op.args[0], op.result))
  122. elif op.opname == 'setarrayitem':
  123. if (op.args[0], op.args[2]) in cache:
  124. result.add(op)
  125. elif collect_analyzer.analyze(op):
  126. cache = set()
  127. return result
  128. class FrameworkGCTransformer(GCTransformer):
  129. root_stack_depth = None # for tests to override
  130. def __init__(self, translator):
  131. from pypy.rpython.memory.gc.base import choose_gc_from_config
  132. from pypy.rpython.memory.gc.base import ARRAY_TYPEID_MAP
  133. from pypy.rpython.memory.gc import inspector
  134. super(FrameworkGCTransformer, self).__init__(translator, inline=True)
  135. if hasattr(self, 'GC_PARAMS'):
  136. # for tests: the GC choice can be specified as class attributes
  137. from pypy.rpython.memory.gc.marksweep import MarkSweepGC
  138. GCClass = getattr(self, 'GCClass', MarkSweepGC)
  139. GC_PARAMS = self.GC_PARAMS
  140. else:
  141. # for regular translation: pick the GC from the config
  142. GCClass, GC_PARAMS = choose_gc_from_config(translator.config)
  143. if hasattr(translator, '_jit2gc'):
  144. self.layoutbuilder = translator._jit2gc['layoutbuilder']
  145. else:
  146. self.layoutbuilder = TransformerLayoutBuilder(translator, GCClass)
  147. self.layoutbuilder.transformer = self
  148. self.get_type_id = self.layoutbuilder.get_type_id
  149. # set up GCData with the llgroup from the layoutbuilder, which
  150. # will grow as more TYPE_INFO members are added to it
  151. gcdata = gctypelayout.GCData(self.layoutbuilder.type_info_group)
  152. # initialize the following two fields with a random non-NULL address,
  153. # to make the annotator happy. The fields are patched in finish()
  154. # to point to a real array.
  155. foo = lltype.malloc(lltype.FixedSizeArray(llmemory.Address, 1),
  156. immortal=True, zero=True)
  157. a_random_address = llmemory.cast_ptr_to_adr(foo)
  158. gcdata.static_root_start = a_random_address # patched in finish()
  159. gcdata.static_root_nongcend = a_random_address # patched in finish()
  160. gcdata.static_root_end = a_random_address # patched in finish()
  161. gcdata.max_type_id = 13 # patched in finish()
  162. gcdata.typeids_z = a_random_address # patched in finish()
  163. self.gcdata = gcdata
  164. self.malloc_fnptr_cache = {}
  165. gcdata.gc = GCClass(translator.config.translation, **GC_PARAMS)
  166. root_walker = self.build_root_walker()
  167. self.root_walker = root_walker
  168. gcdata.set_query_functions(gcdata.gc)
  169. gcdata.gc.set_root_walker(root_walker)
  170. self.num_pushs = 0
  171. self.write_barrier_calls = 0
  172. self.write_barrier_from_array_calls = 0
  173. def frameworkgc_setup():
  174. # run-time initialization code
  175. root_walker.setup_root_walker()
  176. gcdata.gc.setup()
  177. gcdata.gc.post_setup()
  178. def frameworkgc__teardown():
  179. # run-time teardown code for tests!
  180. gcdata.gc._teardown()
  181. bk = self.translator.annotator.bookkeeper
  182. r_typeid16 = rffi.platform.numbertype_to_rclass[TYPE_ID]
  183. s_typeid16 = annmodel.SomeInteger(knowntype=r_typeid16)
  184. # the point of this little dance is to not annotate
  185. # self.gcdata.static_root_xyz as constants. XXX is it still needed??
  186. data_classdef = bk.getuniqueclassdef(gctypelayout.GCData)
  187. data_classdef.generalize_attr(
  188. 'static_root_start',
  189. annmodel.SomeAddress())
  190. data_classdef.generalize_attr(
  191. 'static_root_nongcend',
  192. annmodel.SomeAddress())
  193. data_classdef.generalize_attr(
  194. 'static_root_end',
  195. annmodel.SomeAddress())
  196. data_classdef.generalize_attr(
  197. 'max_type_id',
  198. annmodel.SomeInteger())
  199. data_classdef.generalize_attr(
  200. 'typeids_z',
  201. annmodel.SomeAddress())
  202. annhelper = annlowlevel.MixLevelHelperAnnotator(self.translator.rtyper)
  203. def getfn(ll_function, args_s, s_result, inline=False,
  204. minimal_transform=True):
  205. graph = annhelper.getgraph(ll_function, args_s, s_result)
  206. if minimal_transform:
  207. self.need_minimal_transform(graph)
  208. if inline:
  209. self.graphs_to_inline[graph] = True
  210. return annhelper.graph2const(graph)
  211. self.frameworkgc_setup_ptr = getfn(frameworkgc_setup, [],
  212. annmodel.s_None)
  213. # for tests
  214. self.frameworkgc__teardown_ptr = getfn(frameworkgc__teardown, [],
  215. annmodel.s_None)
  216. if root_walker.need_root_stack:
  217. self.incr_stack_ptr = getfn(root_walker.incr_stack,
  218. [annmodel.SomeInteger()],
  219. annmodel.SomeAddress(),
  220. inline = True)
  221. self.decr_stack_ptr = getfn(root_walker.decr_stack,
  222. [annmodel.SomeInteger()],
  223. annmodel.SomeAddress(),
  224. inline = True)
  225. else:
  226. self.incr_stack_ptr = None
  227. self.decr_stack_ptr = None
  228. self.weakref_deref_ptr = self.inittime_helper(
  229. ll_weakref_deref, [llmemory.WeakRefPtr], llmemory.Address)
  230. classdef = bk.getuniqueclassdef(GCClass)
  231. s_gc = annmodel.SomeInstance(classdef)
  232. s_gcref = annmodel.SomePtr(llmemory.GCREF)
  233. malloc_fixedsize_clear_meth = GCClass.malloc_fixedsize_clear.im_func
  234. self.malloc_fixedsize_clear_ptr = getfn(
  235. malloc_fixedsize_clear_meth,
  236. [s_gc, s_typeid16,
  237. annmodel.SomeInteger(nonneg=True),
  238. annmodel.SomeBool(),
  239. annmodel.SomeBool(),
  240. annmodel.SomeBool()], s_gcref,
  241. inline = False)
  242. if hasattr(GCClass, 'malloc_fixedsize'):
  243. malloc_fixedsize_meth = GCClass.malloc_fixedsize.im_func
  244. self.malloc_fixedsize_ptr = getfn(
  245. malloc_fixedsize_meth,
  246. [s_gc, s_typeid16,
  247. annmodel.SomeInteger(nonneg=True),
  248. annmodel.SomeBool(),
  249. annmodel.SomeBool(),
  250. annmodel.SomeBool()], s_gcref,
  251. inline = False)
  252. else:
  253. malloc_fixedsize_meth = None
  254. self.malloc_fixedsize_ptr = self.malloc_fixedsize_clear_ptr
  255. ## self.malloc_varsize_ptr = getfn(
  256. ## GCClass.malloc_varsize.im_func,
  257. ## [s_gc] + [annmodel.SomeInteger(nonneg=True) for i in range(5)]
  258. ## + [annmodel.SomeBool()], s_gcref)
  259. self.malloc_varsize_clear_ptr = getfn(
  260. GCClass.malloc_varsize_clear.im_func,
  261. [s_gc, s_typeid16]
  262. + [annmodel.SomeInteger(nonneg=True) for i in range(4)], s_gcref)
  263. self.collect_ptr = getfn(GCClass.collect.im_func,
  264. [s_gc, annmodel.SomeInteger()], annmodel.s_None)
  265. self.can_move_ptr = getfn(GCClass.can_move.im_func,
  266. [s_gc, annmodel.SomeAddress()],
  267. annmodel.SomeBool())
  268. if hasattr(GCClass, 'shrink_array'):
  269. self.shrink_array_ptr = getfn(
  270. GCClass.shrink_array.im_func,
  271. [s_gc, annmodel.SomeAddress(),
  272. annmodel.SomeInteger(nonneg=True)], annmodel.s_Bool)
  273. else:
  274. self.shrink_array_ptr = None
  275. if hasattr(GCClass, 'assume_young_pointers'):
  276. # xxx should really be a noop for gcs without generations
  277. self.assume_young_pointers_ptr = getfn(
  278. GCClass.assume_young_pointers.im_func,
  279. [s_gc, annmodel.SomeAddress()],
  280. annmodel.s_None)
  281. if hasattr(GCClass, 'heap_stats'):
  282. self.heap_stats_ptr = getfn(GCClass.heap_stats.im_func,
  283. [s_gc], annmodel.SomePtr(lltype.Ptr(ARRAY_TYPEID_MAP)),
  284. minimal_transform=False)
  285. self.get_member_index_ptr = getfn(
  286. GCClass.get_member_index.im_func,
  287. [s_gc, annmodel.SomeInteger(knowntype=llgroup.r_halfword)],
  288. annmodel.SomeInteger())
  289. if hasattr(GCClass, 'writebarrier_before_copy'):
  290. self.wb_before_copy_ptr = \
  291. getfn(GCClass.writebarrier_before_copy.im_func,
  292. [s_gc] + [annmodel.SomeAddress()] * 2 +
  293. [annmodel.SomeInteger()] * 3, annmodel.SomeBool())
  294. elif GCClass.needs_write_barrier:
  295. raise NotImplementedError("GC needs write barrier, but does not provide writebarrier_before_copy functionality")
  296. # in some GCs we can inline the common case of
  297. # malloc_fixedsize(typeid, size, False, False, False)
  298. if getattr(GCClass, 'inline_simple_malloc', False):
  299. # make a copy of this function so that it gets annotated
  300. # independently and the constants are folded inside
  301. if malloc_fixedsize_meth is None:
  302. malloc_fast_meth = malloc_fixedsize_clear_meth
  303. self.malloc_fast_is_clearing = True
  304. else:
  305. malloc_fast_meth = malloc_fixedsize_meth
  306. self.malloc_fast_is_clearing = False
  307. malloc_fast = func_with_new_name(
  308. malloc_fast_meth,
  309. "malloc_fast")
  310. s_False = annmodel.SomeBool(); s_False.const = False
  311. self.malloc_fast_ptr = getfn(
  312. malloc_fast,
  313. [s_gc, s_typeid16,
  314. annmodel.SomeInteger(nonneg=True),
  315. s_False, s_False, s_False], s_gcref,
  316. inline = True)
  317. else:
  318. self.malloc_fast_ptr = None
  319. # in some GCs we can also inline the common case of
  320. # malloc_varsize(typeid, length, (3 constant sizes), True, False)
  321. if getattr(GCClass, 'inline_simple_malloc_varsize', False):
  322. # make a copy of this function so that it gets annotated
  323. # independently and the constants are folded inside
  324. malloc_varsize_clear_fast = func_with_new_name(
  325. GCClass.malloc_varsize_clear.im_func,
  326. "malloc_varsize_clear_fast")
  327. s_False = annmodel.SomeBool(); s_False.const = False
  328. self.malloc_varsize_clear_fast_ptr = getfn(
  329. malloc_varsize_clear_fast,
  330. [s_gc, s_typeid16,
  331. annmodel.SomeInteger(nonneg=True),
  332. annmodel.SomeInteger(nonneg=True),
  333. annmodel.SomeInteger(nonneg=True),
  334. annmodel.SomeInteger(nonneg=True)], s_gcref,
  335. inline = True)
  336. else:
  337. self.malloc_varsize_clear_fast_ptr = None
  338. if getattr(GCClass, 'malloc_varsize_nonmovable', False):
  339. malloc_nonmovable = func_with_new_name(
  340. GCClass.malloc_varsize_nonmovable.im_func,
  341. "malloc_varsize_nonmovable")
  342. self.malloc_varsize_nonmovable_ptr = getfn(
  343. malloc_nonmovable,
  344. [s_gc, s_typeid16,
  345. annmodel.SomeInteger(nonneg=True)], s_gcref)
  346. else:
  347. self.malloc_varsize_nonmovable_ptr = None
  348. if getattr(GCClass, 'raw_malloc_memory_pressure', False):
  349. def raw_malloc_memory_pressure_varsize(length, itemsize):
  350. totalmem = length * itemsize
  351. if totalmem > 0:
  352. gcdata.gc.raw_malloc_memory_pressure(totalmem)
  353. #else: probably an overflow -- the following rawmalloc
  354. # will fail then
  355. def raw_malloc_memory_pressure(sizehint):
  356. gcdata.gc.raw_malloc_memory_pressure(sizehint)
  357. self.raw_malloc_memory_pressure_varsize_ptr = getfn(
  358. raw_malloc_memory_pressure_varsize,
  359. [annmodel.SomeInteger(), annmodel.SomeInteger()],
  360. annmodel.s_None, minimal_transform = False)
  361. self.raw_malloc_memory_pressure_ptr = getfn(
  362. raw_malloc_memory_pressure,
  363. [annmodel.SomeInteger()],
  364. annmodel.s_None, minimal_transform = False)
  365. self.identityhash_ptr = getfn(GCClass.identityhash.im_func,
  366. [s_gc, s_gcref],
  367. annmodel.SomeInteger(),
  368. minimal_transform=False)
  369. if getattr(GCClass, 'obtain_free_space', False):
  370. self.obtainfreespace_ptr = getfn(GCClass.obtain_free_space.im_func,
  371. [s_gc, annmodel.SomeInteger()],
  372. annmodel.SomeAddress())
  373. if GCClass.moving_gc:
  374. self.id_ptr = getfn(GCClass.id.im_func,
  375. [s_gc, s_gcref], annmodel.SomeInteger(),
  376. inline = False,
  377. minimal_transform = False)
  378. else:
  379. self.id_ptr = None
  380. self.get_rpy_roots_ptr = getfn(inspector.get_rpy_roots,
  381. [s_gc],
  382. rgc.s_list_of_gcrefs(),
  383. minimal_transform=False)
  384. self.get_rpy_referents_ptr = getfn(inspector.get_rpy_referents,
  385. [s_gc, s_gcref],
  386. rgc.s_list_of_gcrefs(),
  387. minimal_transform=False)
  388. self.get_rpy_memory_usage_ptr = getfn(inspector.get_rpy_memory_usage,
  389. [s_gc, s_gcref],
  390. annmodel.SomeInteger(),
  391. minimal_transform=False)
  392. self.get_rpy_type_index_ptr = getfn(inspector.get_rpy_type_index,
  393. [s_gc, s_gcref],
  394. annmodel.SomeInteger(),
  395. minimal_transform=False)
  396. self.is_rpy_instance_ptr = getfn(inspector.is_rpy_instance,
  397. [s_gc, s_gcref],
  398. annmodel.SomeBool(),
  399. minimal_transform=False)
  400. self.dump_rpy_heap_ptr = getfn(inspector.dump_rpy_heap,
  401. [s_gc, annmodel.SomeInteger()],
  402. annmodel.s_Bool,
  403. minimal_transform=False)
  404. self.get_typeids_z_ptr = getfn(inspector.get_typeids_z,
  405. [s_gc],
  406. annmodel.SomePtr(
  407. lltype.Ptr(rgc.ARRAY_OF_CHAR)),
  408. minimal_transform=False)
  409. self.set_max_heap_size_ptr = getfn(GCClass.set_max_heap_size.im_func,
  410. [s_gc,
  411. annmodel.SomeInteger(nonneg=True)],
  412. annmodel.s_None)
  413. self.write_barrier_ptr = None
  414. self.write_barrier_from_array_ptr = None
  415. if GCClass.needs_write_barrier:
  416. self.write_barrier_ptr = getfn(GCClass.write_barrier.im_func,
  417. [s_gc,
  418. annmodel.SomeAddress(),
  419. annmodel.SomeAddress()],
  420. annmodel.s_None,
  421. inline=True)
  422. func = getattr(gcdata.gc, 'remember_young_pointer', None)
  423. if func is not None:
  424. # func should not be a bound method, but a real function
  425. assert isinstance(func, types.FunctionType)
  426. self.write_barrier_failing_case_ptr = getfn(func,
  427. [annmodel.SomeAddress(),
  428. annmodel.SomeAddress()],
  429. annmodel.s_None)
  430. func = getattr(GCClass, 'write_barrier_from_array', None)
  431. if func is not None:
  432. self.write_barrier_from_array_ptr = getfn(func.im_func,
  433. [s_gc,
  434. annmodel.SomeAddress(),
  435. annmodel.SomeAddress(),
  436. annmodel.SomeInteger()],
  437. annmodel.s_None,
  438. inline=True)
  439. func = getattr(gcdata.gc, 'remember_young_pointer_from_array3',
  440. None)
  441. if func is not None:
  442. # func should not be a bound method, but a real function
  443. assert isinstance(func, types.FunctionType)
  444. self.write_barrier_from_array_failing_case_ptr = \
  445. getfn(func,
  446. [annmodel.SomeAddress(),
  447. annmodel.SomeInteger(),
  448. annmodel.SomeAddress()],
  449. annmodel.s_None)
  450. self.statistics_ptr = getfn(GCClass.statistics.im_func,
  451. [s_gc, annmodel.SomeInteger()],
  452. annmodel.SomeInteger())
  453. # thread support
  454. if translator.config.translation.continuation:
  455. root_walker.need_stacklet_support(self, getfn)
  456. if translator.config.translation.thread:
  457. root_walker.need_thread_support(self, getfn)
  458. self.layoutbuilder.encode_type_shapes_now()
  459. annhelper.finish() # at this point, annotate all mix-level helpers
  460. annhelper.backend_optimize()
  461. self.collect_analyzer = CollectAnalyzer(self.translator)
  462. self.collect_analyzer.analyze_all()
  463. s_gc = self.translator.annotator.bookkeeper.valueoftype(GCClass)
  464. r_gc = self.translator.rtyper.getrepr(s_gc)
  465. self.c_const_gc = rmodel.inputconst(r_gc, self.gcdata.gc)
  466. s_gc_data = self.translator.annotator.bookkeeper.valueoftype(
  467. gctypelayout.GCData)
  468. r_gc_data = self.translator.rtyper.getrepr(s_gc_data)
  469. self.c_const_gcdata = rmodel.inputconst(r_gc_data, self.gcdata)
  470. self.malloc_zero_filled = GCClass.malloc_zero_filled
  471. HDR = self.HDR = self.gcdata.gc.gcheaderbuilder.HDR
  472. size_gc_header = self.gcdata.gc.gcheaderbuilder.size_gc_header
  473. vtableinfo = (HDR, size_gc_header, self.gcdata.gc.typeid_is_in_field)
  474. self.c_vtableinfo = rmodel.inputconst(lltype.Void, vtableinfo)
  475. tig = self.layoutbuilder.type_info_group._as_ptr()
  476. self.c_type_info_group = rmodel.inputconst(lltype.typeOf(tig), tig)
  477. sko = llmemory.sizeof(gcdata.TYPE_INFO)
  478. self.c_vtinfo_skip_offset = rmodel.inputconst(lltype.typeOf(sko), sko)
  479. def build_root_walker(self):
  480. from pypy.rpython.memory.gctransform import shadowstack
  481. return shadowstack.ShadowStackRootWalker(self)
  482. def consider_constant(self, TYPE, value):
  483. self.layoutbuilder.consider_constant(TYPE, value, self.gcdata.gc)
  484. #def get_type_id(self, TYPE):
  485. # this method is attached to the instance and redirects to
  486. # layoutbuilder.get_type_id().
  487. def special_funcptr_for_type(self, TYPE):
  488. return self.layoutbuilder.special_funcptr_for_type(TYPE)
  489. def gc_header_for(self, obj, needs_hash=False):
  490. hdr = self.gcdata.gc.gcheaderbuilder.header_of_object(obj)
  491. HDR = self.HDR
  492. withhash, flag = self.gcdata.gc.withhash_flag_is_in_field
  493. x = getattr(hdr, withhash)
  494. TYPE = lltype.typeOf(x)
  495. x = lltype.cast_primitive(lltype.Signed, x)
  496. if needs_hash:
  497. x |= flag # set the flag in the header
  498. else:
  499. x &= ~flag # clear the flag in the header
  500. x = lltype.cast_primitive(TYPE, x)
  501. setattr(hdr, withhash, x)
  502. return hdr
  503. def get_hash_offset(self, T):
  504. type_id = self.get_type_id(T)
  505. assert not self.gcdata.q_is_varsize(type_id)
  506. return self.gcdata.q_fixed_size(type_id)
  507. def finish_tables(self):
  508. group = self.layoutbuilder.close_table()
  509. log.info("assigned %s typeids" % (len(group.members), ))
  510. log.info("added %s push/pop stack root instructions" % (
  511. self.num_pushs, ))
  512. if self.write_barrier_ptr:
  513. log.info("inserted %s write barrier calls" % (
  514. self.write_barrier_calls, ))
  515. if self.write_barrier_from_array_ptr:
  516. log.info("inserted %s write_barrier_from_array calls" % (
  517. self.write_barrier_from_array_calls, ))
  518. # XXX because we call inputconst already in replace_malloc, we can't
  519. # modify the instance, we have to modify the 'rtyped instance'
  520. # instead. horrors. is there a better way?
  521. s_gcdata = self.translator.annotator.bookkeeper.immutablevalue(
  522. self.gcdata)
  523. r_gcdata = self.translator.rtyper.getrepr(s_gcdata)
  524. ll_instance = rmodel.inputconst(r_gcdata, self.gcdata).value
  525. addresses_of_static_ptrs = (
  526. self.layoutbuilder.addresses_of_static_ptrs_in_nongc +
  527. self.layoutbuilder.addresses_of_static_ptrs)
  528. log.info("found %s static roots" % (len(addresses_of_static_ptrs), ))
  529. ll_static_roots_inside = lltype.malloc(lltype.Array(llmemory.Address),
  530. len(addresses_of_static_ptrs),
  531. immortal=True)
  532. for i in range(len(addresses_of_static_ptrs)):
  533. ll_static_roots_inside[i] = addresses_of_static_ptrs[i]
  534. ll_instance.inst_static_root_start = llmemory.cast_ptr_to_adr(ll_static_roots_inside) + llmemory.ArrayItemsOffset(lltype.Array(llmemory.Address))
  535. ll_instance.inst_static_root_nongcend = ll_instance.inst_static_root_start + llmemory.sizeof(llmemory.Address) * len(self.layoutbuilder.addresses_of_static_ptrs_in_nongc)
  536. ll_instance.inst_static_root_end = ll_instance.inst_static_root_start + llmemory.sizeof(llmemory.Address) * len(addresses_of_static_ptrs)
  537. newgcdependencies = []
  538. newgcdependencies.append(ll_static_roots_inside)
  539. ll_instance.inst_max_type_id = len(group.members)
  540. typeids_z = self.write_typeid_list()
  541. ll_typeids_z = lltype.malloc(rgc.ARRAY_OF_CHAR,
  542. len(typeids_z),
  543. immortal=True)
  544. for i in range(len(typeids_z)):
  545. ll_typeids_z[i] = typeids_z[i]
  546. ll_instance.inst_typeids_z = llmemory.cast_ptr_to_adr(ll_typeids_z)
  547. newgcdependencies.append(ll_typeids_z)
  548. return newgcdependencies
  549. def get_finish_tables(self):
  550. # We must first make sure that the type_info_group's members
  551. # are all followed. Do it repeatedly while new members show up.
  552. # Once it is really done, do finish_tables().
  553. seen = 0
  554. while seen < len(self.layoutbuilder.type_info_group.members):
  555. curtotal = len(self.layoutbuilder.type_info_group.members)
  556. yield self.layoutbuilder.type_info_group.members[seen:curtotal]
  557. seen = curtotal
  558. yield self.finish_tables()
  559. def write_typeid_list(self):
  560. """write out the list of type ids together with some info"""
  561. from pypy.tool.udir import udir
  562. # XXX not ideal since it is not per compilation, but per run
  563. # XXX argh argh, this only gives the member index but not the
  564. # real typeid, which is a complete mess to obtain now...
  565. all_ids = self.layoutbuilder.id_of_type.items()
  566. all_ids = [(typeinfo.index, TYPE) for (TYPE, typeinfo) in all_ids]
  567. all_ids = dict(all_ids)
  568. f = udir.join("typeids.txt").open("w")
  569. for index in range(len(self.layoutbuilder.type_info_group.members)):
  570. f.write("member%-4d %s\n" % (index, all_ids.get(index, '?')))
  571. f.close()
  572. try:
  573. import zlib
  574. return zlib.compress(udir.join("typeids.txt").read(), 9)
  575. except ImportError:
  576. return ''
  577. def transform_graph(self, graph):
  578. func = getattr(graph, 'func', None)
  579. if func and getattr(func, '_gc_no_collect_', False):
  580. if self.collect_analyzer.analyze_direct_call(graph):
  581. raise Exception("'no_collect' function can trigger collection:"
  582. " %s" % func)
  583. if self.write_barrier_ptr:
  584. self.clean_sets = (
  585. find_initializing_stores(self.collect_analyzer, graph))
  586. if self.gcdata.gc.can_optimize_clean_setarrayitems():
  587. self.clean_sets = self.clean_sets.union(
  588. find_clean_setarrayitems(self.collect_analyzer, graph))
  589. super(FrameworkGCTransformer, self).transform_graph(graph)
  590. if self.write_barrier_ptr:
  591. self.clean_sets = None
  592. def gct_direct_call(self, hop):
  593. if self.collect_analyzer.analyze(hop.spaceop):
  594. livevars = self.push_roots(hop)
  595. self.default(hop)
  596. self.pop_roots(hop, livevars)
  597. else:
  598. self.default(hop)
  599. if hop.spaceop.opname == "direct_call":
  600. self.mark_call_cannotcollect(hop, hop.spaceop.args[0])
  601. def mark_call_cannotcollect(self, hop, name):
  602. pass
  603. gct_indirect_call = gct_direct_call
  604. def gct_fv_gc_malloc(self, hop, flags, TYPE, *args):
  605. op = hop.spaceop
  606. flavor = flags['flavor']
  607. PTRTYPE = op.result.concretetype
  608. assert PTRTYPE.TO == TYPE
  609. type_id = self.get_type_id(TYPE)
  610. c_type_id = rmodel.inputconst(TYPE_ID, type_id)
  611. info = self.layoutbuilder.get_info(type_id)
  612. c_size = rmodel.inputconst(lltype.Signed, info.fixedsize)
  613. kind_and_fptr = self.special_funcptr_for_type(TYPE)
  614. has_finalizer = (kind_and_fptr is not None and
  615. kind_and_fptr[0] == "finalizer")
  616. has_light_finalizer = (kind_and_fptr is not None and
  617. kind_and_fptr[0] == "light_finalizer")
  618. if has_light_finalizer:
  619. has_finalizer = True
  620. c_has_finalizer = rmodel.inputconst(lltype.Bool, has_finalizer)
  621. c_has_light_finalizer = rmodel.inputconst(lltype.Bool,
  622. has_light_finalizer)
  623. if not op.opname.endswith('_varsize') and not flags.get('varsize'):
  624. #malloc_ptr = self.malloc_fixedsize_ptr
  625. zero = flags.get('zero', False)
  626. if (self.malloc_fast_ptr is not None and
  627. not c_has_finalizer.value and
  628. (self.malloc_fast_is_clearing or not zero)):
  629. malloc_ptr = self.malloc_fast_ptr
  630. elif zero:
  631. malloc_ptr = self.malloc_fixedsize_clear_ptr
  632. else:
  633. malloc_ptr = self.malloc_fixedsize_ptr
  634. args = [self.c_const_gc, c_type_id, c_size,
  635. c_has_finalizer, c_has_light_finalizer,
  636. rmodel.inputconst(lltype.Bool, False)]
  637. else:
  638. assert not c_has_finalizer.value
  639. info_varsize = self.layoutbuilder.get_info_varsize(type_id)
  640. v_length = op.args[-1]
  641. c_ofstolength = rmodel.inputconst(lltype.Signed,
  642. info_varsize.ofstolength)
  643. c_varitemsize = rmodel.inputconst(lltype.Signed,
  644. info_varsize.varitemsize)
  645. if flags.get('nonmovable') and self.malloc_varsize_nonmovable_ptr:
  646. # we don't have tests for such cases, let's fail
  647. # explicitely
  648. malloc_ptr = self.malloc_varsize_nonmovable_ptr
  649. args = [self.c_const_gc, c_type_id, v_length]
  650. else:
  651. if self.malloc_varsize_clear_fast_ptr is not None:
  652. malloc_ptr = self.malloc_varsize_clear_fast_ptr
  653. else:
  654. malloc_ptr = self.malloc_varsize_clear_ptr
  655. args = [self.c_const_gc, c_type_id, v_length, c_size,
  656. c_varitemsize, c_ofstolength]
  657. livevars = self.push_roots(hop)
  658. v_result = hop.genop("direct_call", [malloc_ptr] + args,
  659. resulttype=llmemory.GCREF)
  660. self.pop_roots(hop, livevars)
  661. return v_result
  662. gct_fv_gc_malloc_varsize = gct_fv_gc_malloc
  663. def gct_gc__collect(self, hop):
  664. op = hop.spaceop
  665. if len(op.args) == 1:
  666. v_gen = op.args[0]
  667. else:
  668. # pick a number larger than expected different gc gens :-)
  669. v_gen = rmodel.inputconst(lltype.Signed, 9)
  670. livevars = self.push_roots(hop)
  671. hop.genop("direct_call", [self.collect_ptr, self.c_const_gc, v_gen],
  672. resultvar=op.result)
  673. self.pop_roots(hop, livevars)
  674. def gct_gc_can_move(self, hop):
  675. op = hop.spaceop
  676. v_addr = hop.genop('cast_ptr_to_adr',
  677. [op.args[0]], resulttype=llmemory.Address)
  678. hop.genop("direct_call", [self.can_move_ptr, self.c_const_gc, v_addr],
  679. resultvar=op.result)
  680. def gct_shrink_array(self, hop):
  681. if self.shrink_array_ptr is None:
  682. return GCTransformer.gct_shrink_array(self, hop)
  683. op = hop.spaceop
  684. v_addr = hop.genop('cast_ptr_to_adr',
  685. [op.args[0]], resulttype=llmemory.Address)
  686. v_length = op.args[1]
  687. hop.genop("direct_call", [self.shrink_array_ptr, self.c_const_gc,
  688. v_addr, v_length],
  689. resultvar=op.result)
  690. def gct_gc_assume_young_pointers(self, hop):
  691. if not hasattr(self, 'assume_young_pointers_ptr'):
  692. return
  693. op = hop.spaceop
  694. v_addr = op.args[0]
  695. if v_addr.concretetype != llmemory.Address:
  696. v_addr = hop.genop('cast_ptr_to_adr',
  697. [v_addr], resulttype=llmemory.Address)
  698. hop.genop("direct_call", [self.assume_young_pointers_ptr,
  699. self.c_const_gc, v_addr])
  700. def gct_gc_heap_stats(self, hop):
  701. if not hasattr(self, 'heap_stats_ptr'):
  702. return GCTransformer.gct_gc_heap_stats(self, hop)
  703. op = hop.spaceop
  704. livevars = self.push_roots(hop)
  705. hop.genop("direct_call", [self.heap_stats_ptr, self.c_const_gc],
  706. resultvar=op.result)
  707. self.pop_roots(hop, livevars)
  708. def gct_get_member_index(self, hop):
  709. op = hop.spaceop
  710. v_typeid = op.args[0]
  711. hop.genop("direct_call", [self.get_member_index_ptr, self.c_const_gc,
  712. v_typeid], resultvar=op.result)
  713. def _gc_adr_of_gc_attr(self, hop, attrname):
  714. if getattr(self.gcdata.gc, attrname, None) is None:
  715. raise NotImplementedError("gc_adr_of_%s only for generational gcs"
  716. % (attrname,))
  717. op = hop.spaceop
  718. ofs = llmemory.offsetof(self.c_const_gc.concretetype.TO,
  719. 'inst_' + attrname)
  720. c_ofs = rmodel.inputconst(lltype.Signed, ofs)
  721. v_gc_adr = hop.genop('cast_ptr_to_adr', [self.c_const_gc],
  722. resulttype=llmemory.Address)
  723. hop.genop('adr_add', [v_gc_adr, c_ofs], resultvar=op.result)
  724. def gct_gc_adr_of_nursery_free(self, hop):
  725. self._gc_adr_of_gc_attr(hop, 'nursery_free')
  726. def gct_gc_adr_of_nursery_top(self, hop):
  727. self._gc_adr_of_gc_attr(hop, 'nursery_top')
  728. def _gc_adr_of_gcdata_attr(self, hop, attrname):
  729. op = hop.spaceop
  730. ofs = llmemory.offsetof(self.c_const_gcdata.concretetype.TO,
  731. 'inst_' + attrname)
  732. c_ofs = rmodel.inputconst(lltype.Signed, ofs)
  733. v_gcdata_adr = hop.genop('cast_ptr_to_adr', [self.c_const_gcdata],
  734. resulttype=llmemory.Address)
  735. hop.genop('adr_add', [v_gcdata_adr, c_ofs], resultvar=op.result)
  736. def gct_gc_adr_of_root_stack_base(self, hop):
  737. self._gc_adr_of_gcdata_attr(hop, 'root_stack_base')
  738. def gct_gc_adr_of_root_stack_top(self, hop):
  739. self._gc_adr_of_gcdata_attr(hop, 'root_stack_top')
  740. def gct_gc_shadowstackref_new(self, hop):
  741. op = hop.spaceop
  742. livevars = self.push_roots(hop)
  743. hop.genop("direct_call", [self.root_walker.gc_shadowstackref_new_ptr],
  744. resultvar=op.result)
  745. self.pop_roots(hop, livevars)
  746. def gct_gc_shadowstackref_context(self, hop):
  747. op = hop.spaceop
  748. hop.genop("direct_call",
  749. [self.root_walker.gc_shadowstackref_context_ptr, op.args[0]],
  750. resultvar=op.result)
  751. def gct_gc_shadowstackref_destroy(self, hop):
  752. op = hop.spaceop
  753. hop.genop("direct_call",
  754. [self.root_walker.gc_shadowstackref_destroy_ptr, op.args[0]])
  755. def gct_gc_save_current_state_away(self, hop):
  756. op = hop.spaceop
  757. hop.genop("direct_call",
  758. [self.root_walker.gc_save_current_state_away_ptr,
  759. op.args[0], op.args[1]])
  760. def gct_gc_forget_current_state(self, hop):
  761. hop.genop("direct_call",
  762. [self.root_walker.gc_forget_current_state_ptr])
  763. def gct_gc_restore_state_from(self, hop):
  764. op = hop.spaceop
  765. hop.genop("direct_call",
  766. [self.root_walker.gc_restore_state_from_ptr,
  767. op.args[0]])
  768. def gct_gc_start_fresh_new_state(self, hop):
  769. hop.genop("direct_call",
  770. [self.root_walker.gc_start_fresh_new_state_ptr])
  771. def gct_gc_x_swap_pool(self, hop):
  772. raise NotImplementedError("old operation deprecated")
  773. def gct_gc_x_clone(self, hop):
  774. raise NotImplementedError("old operation deprecated")
  775. def gct_gc_x_size_header(self, hop):
  776. raise NotImplementedError("old operation deprecated")
  777. def gct_do_malloc_fixedsize_clear(self, hop):
  778. # used by the JIT (see pypy.jit.backend.llsupport.gc)
  779. op = hop.spaceop
  780. [v_typeid, v_size,
  781. v_has_finalizer, v_has_light_finalizer, v_contains_weakptr] = op.args
  782. livevars = self.push_roots(hop)
  783. hop.genop("direct_call",
  784. [self.malloc_fixedsize_clear_ptr, self.c_const_gc,
  785. v_typeid, v_size,
  786. v_has_finalizer, v_has_light_finalizer,
  787. v_contains_weakptr],
  788. resultvar=op.result)
  789. self.pop_roots(hop, livevars)
  790. def gct_do_malloc_varsize_clear(self, hop):
  791. # used by the JIT (see pypy.jit.backend.llsupport.gc)
  792. op = hop.spaceop
  793. [v_typeid, v_length, v_size, v_itemsize,
  794. v_offset_to_length] = op.args
  795. livevars = self.push_roots(hop)
  796. hop.genop("direct_call",
  797. [self.malloc_varsize_clear_ptr, self.c_const_gc,
  798. v_typeid, v_length, v_size, v_itemsize,
  799. v_offset_to_length],
  800. resultvar=op.result)
  801. self.pop_roots(hop, livevars)
  802. def gct_get_write_barrier_failing_case(self, hop):
  803. op = hop.spaceop
  804. hop.genop("same_as",
  805. [self.write_barrier_failing_case_ptr],
  806. resultvar=op.result)
  807. def gct_get_write_barrier_from_array_failing_case(self, hop):
  808. op = hop.spaceop
  809. v = getattr(self, 'write_barrier_from_array_failing_case_ptr',
  810. lltype.nullptr(op.result.concretetype.TO))
  811. hop.genop("same_as", [v], resultvar=op.result)
  812. def gct_zero_gc_pointers_inside(self, hop):
  813. if not self.malloc_zero_filled:
  814. v_ob = hop.spaceop.args[0]
  815. TYPE = v_ob.concretetype.TO
  816. gen_zero_gc_pointers(TYPE, v_ob, hop.llops)
  817. def gct_gc_writebarrier_before_copy(self, hop):
  818. op = hop.spaceop
  819. if not hasattr(self, 'wb_before_copy_ptr'):
  820. # no write barrier needed in that case
  821. hop.genop("same_as",
  822. [rmodel.inputconst(lltype.Bool, True)],
  823. resultvar=op.result)
  824. return
  825. source_addr = hop.genop('cast_ptr_to_adr', [op.args[0]],
  826. resulttype=llmemory.Address)
  827. dest_addr = hop.genop('cast_ptr_to_adr', [op.args[1]],
  828. resulttype=llmemory.Address)
  829. hop.genop('direct_call', [self.wb_before_copy_ptr, self.c_const_gc,
  830. source_addr, dest_addr] + op.args[2:],
  831. resultvar=op.result)
  832. def gct_weakref_create(self, hop):
  833. op = hop.spaceop
  834. type_id = self.get_type_id(WEAKREF)
  835. c_type_id = rmodel.inputconst(TYPE_ID, type_id)
  836. info = self.layoutbuilder.get_info(type_id)
  837. c_size = rmodel.inputconst(lltype.Signed, info.fixedsize)
  838. malloc_ptr = self.malloc_fixedsize_ptr
  839. c_false = rmodel.inputconst(lltype.Bool, False)
  840. c_has_weakptr = rmodel.inputconst(lltype.Bool, True)
  841. args = [self.c_const_gc, c_type_id, c_size,
  842. c_false, c_false, c_has_weakptr]
  843. # push and pop the current live variables *including* the argument
  844. # to the weakref_create operation, which must be kept alive and
  845. # moved if the GC needs to collect
  846. livevars = self.push_roots(hop, keep_current_args=True)
  847. v_result = hop.genop("direct_call", [malloc_ptr] + args,
  848. resulttype=llmemory.GCREF)
  849. v_result = hop.genop("cast_opaque_ptr", [v_result],
  850. resulttype=WEAKREFPTR)
  851. self.pop_roots(hop, livevars)
  852. # cast_ptr_to_adr must be done after malloc, as the GC pointer
  853. # might have moved just now.
  854. v_instance, = op.args
  855. v_addr = hop.genop("cast_ptr_to_adr", [v_instance],
  856. resulttype=llmemory.Address)
  857. hop.genop("bare_setfield",
  858. [v_result, rmodel.inputconst(lltype.Void, "weakptr"), v_addr])
  859. v_weakref = hop.genop("cast_ptr_to_weakrefptr", [v_result],
  860. resulttype=llmemory.WeakRefPtr)
  861. hop.cast_result(v_weakref)
  862. def gct_weakref_deref(self, hop):
  863. v_wref, = hop.spaceop.args
  864. v_addr = hop.genop("direct_call",
  865. [self.weakref_deref_ptr, v_wref],
  866. resulttype=llmemory.Address)
  867. hop.cast_result(v_addr)
  868. def gct_gc_identityhash(self, hop):
  869. livevars = self.push_roots(hop)
  870. [v_ptr] = hop.spaceop.args
  871. v_ptr = hop.genop("cast_opaque_ptr", [v_ptr],
  872. resulttype=llmemory.GCREF)
  873. hop.genop("direct_call",
  874. [self.identityhash_ptr, self.c_const_gc, v_ptr],
  875. resultvar=hop.spaceop.result)
  876. self.pop_roots(hop, livevars)
  877. def gct_gc_id(self, hop):
  878. if self.id_ptr is not None:
  879. livevars = self.push_roots(hop)
  880. [v_ptr] = hop.spaceop.args
  881. v_ptr = hop.genop("cast_opaque_ptr", [v_ptr],
  882. resulttype=llmemory.GCREF)
  883. hop.genop("direct_call", [self.id_ptr, self.c_const_gc, v_ptr],
  884. resultvar=hop.spaceop.result)
  885. self.pop_roots(hop, livevars)
  886. else:
  887. hop.rename('cast_ptr_to_int') # works nicely for non-moving GCs
  888. def gct_gc_obtain_free_space(self, hop):
  889. livevars = self.push_roots(hop)
  890. [v_number] = hop.spaceop.args
  891. hop.genop("direct_call",
  892. [self.obtainfreespace_ptr, self.c_const_gc, v_number],
  893. resultvar=hop.spaceop.result)
  894. self.pop_roots(hop, livevars)
  895. def gct_gc_set_max_heap_size(self, hop):
  896. [v_size] = hop.spaceop.args
  897. hop.genop("direct_call", [self.set_max_heap_size_ptr,
  898. self.c_const_gc,
  899. v_size])
  900. def gct_gc_thread_prepare(self, hop):
  901. pass # no effect any more
  902. def gct_gc_thread_run(self, hop):
  903. assert self.translator.config.translation.thread
  904. if hasattr(self.root_walker, 'thread_run_ptr'):
  905. livevars = self.push_roots(hop)
  906. hop.genop("direct_call", [self.root_walker.thread_run_ptr])
  907. self.pop_roots(hop, livevars)
  908. def gct_gc_thread_start(self, hop):
  909. assert self.translator.config.translation.thread
  910. if hasattr(self.root_walker, 'thread_start_ptr'):
  911. # only with asmgcc. Note that this is actually called after
  912. # the first gc_thread_run() in the new thread.
  913. hop.genop("direct_call", [self.root_walker.thread_start_ptr])
  914. def gct_gc_thread_die(self, hop):
  915. assert self.translator.config.translation.thread
  916. if hasattr(self.root_walker, 'thread_die_ptr'):
  917. livevars = self.push_roots(hop)
  918. hop.genop("direct_call", [self.root_walker.thread_die_ptr])
  919. self.pop_roots(hop, livevars)
  920. def gct_gc_thread_before_fork(self, hop):
  921. if (self.translator.config.translation.thread
  922. and hasattr(self.root_walker, 'thread_before_fork_ptr')):
  923. hop.genop("direct_call", [self.root_walker.thread_before_fork_ptr],
  924. resultvar=hop.spaceop.result)
  925. else:
  926. c_null = rmodel.inputconst(llmemory.Address, llmemory.NULL)
  927. hop.genop("same_as", [c_null],
  928. resultvar=hop.spaceop.result)
  929. def gct_gc_thread_after_fork(self, hop):
  930. if (self.translator.config.translation.thread
  931. and hasattr(self.root_walker, 'thread_after_fork_ptr')):
  932. livevars = self.push_roots(hop)
  933. hop.genop("direct_call", [self.root_walker.thread_after_fork_ptr]
  934. + hop.spaceop.args)
  935. self.pop_roots(hop, livevars)
  936. def gct_gc_get_type_info_group(self, hop):
  937. return hop.cast_result(self.c_type_info_group)
  938. def gct_gc_get_rpy_roots(self, hop):
  939. livevars = self.push_roots(hop)
  940. hop.genop("direct_call",
  941. [self.get_rpy_roots_ptr, self.c_const_gc],
  942. resultvar=hop.spaceop.result)
  943. self.pop_roots(hop, livevars)
  944. def gct_gc_get_rpy_referents(self, hop):
  945. livevars = self.push_roots(hop)
  946. [v_ptr] = hop.spaceop.args
  947. hop.genop("direct_call",
  948. [self.get_rpy_referents_ptr, self.c_const_gc, v_ptr],
  949. resultvar=hop.spaceop.result)
  950. self.pop_roots(hop, livevars)
  951. def gct_gc_get_rpy_memory_usage(self, hop):
  952. livevars = self.push_roots(hop)
  953. [v_ptr] = hop.spaceop.args
  954. hop.genop("direct_call",
  955. [self.get_rpy_memory_usage_ptr, self.c_const_gc, v_ptr],
  956. resultvar=hop.spaceop.result)
  957. self.pop_roots(hop, livevars)
  958. def gct_gc_get_rpy_type_index(self, hop):
  959. livevars = self.push_roots(hop)
  960. [v_ptr] = hop.spaceop.args
  961. hop.genop("direct_call",
  962. [self.get_rpy_type_index_ptr, self.c_const_gc, v_ptr],
  963. resultvar=hop.spaceop.result)
  964. self.pop_roots(hop, livevars)
  965. def gct_gc_is_rpy_instance(self, hop):
  966. livevars = self.push_roots(hop)
  967. [v_ptr] = hop.spaceop.args
  968. hop.genop("direct_call",
  969. [self.is_rpy_instance_ptr, self.c_const_gc, v_ptr],
  970. resultvar=hop.spaceop.result)
  971. self.pop_roots(hop, livevars)
  972. def gct_gc_dump_rpy_heap(self, hop):
  973. livevars = self.push_roots(hop)
  974. [v_fd] = hop.spaceop.args
  975. hop.genop("direct_call",
  976. [self.dump_rpy_heap_ptr, self.c_const_gc, v_fd],
  977. resultvar=hop.spaceop.result)
  978. self.pop_roots(hop, livevars)
  979. def gct_gc_typeids_z(self, hop):
  980. livevars = self.push_roots(hop)
  981. hop.genop("direct_call",
  982. [se

Large files files are truncated, but you can click here to view the full file