PageRenderTime 34ms CodeModel.GetById 16ms 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
  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. [self.get_typeids_z_ptr, self.c_const_gc],
  983. resultvar=hop.spaceop.result)
  984. self.pop_roots(hop, livevars)
  985. def gct_malloc_nonmovable_varsize(self, hop):
  986. TYPE = hop.spaceop.result.concretetype
  987. if self.gcdata.gc.can_malloc_nonmovable():
  988. return self.gct_malloc_varsize(hop, {'nonmovable':True})
  989. c = rmodel.inputconst(TYPE, lltype.nullptr(TYPE.TO))
  990. return hop.cast_result(c)
  991. def gct_malloc_nonmovable(self, hop):
  992. TYPE = hop.spaceop.result.concretetype
  993. if self.gcdata.gc.can_malloc_nonmovable():
  994. return self.gct_malloc(hop, {'nonmovable':True})
  995. c = rmodel.inputconst(TYPE, lltype.nullptr(TYPE.TO))
  996. return hop.cast_result(c)
  997. def _set_into_gc_array_part(self, op):
  998. if op.opname == 'setarrayitem':
  999. return op.args[1]
  1000. if op.opname == 'setinteriorfield':
  1001. for v in op.args[1:-1]:
  1002. if v.concretetype is not lltype.Void:
  1003. return v
  1004. return None
  1005. def transform_generic_set(self, hop):
  1006. from pypy.objspace.flow.model import Constant
  1007. opname = hop.spaceop.opname
  1008. v_struct = hop.spaceop.args[0]
  1009. v_newvalue = hop.spaceop.args[-1]
  1010. assert opname in ('setfield', 'setarrayitem', 'setinteriorfield')
  1011. assert isinstance(v_newvalue.concretetype, lltype.Ptr)
  1012. # XXX for some GCs the skipping if the newvalue is a constant won't be
  1013. # ok
  1014. if (self.write_barrier_ptr is not None
  1015. and not isinstance(v_newvalue, Constant)
  1016. and v_struct.concretetype.TO._gckind == "gc"
  1017. and hop.spaceop not in self.clean_sets):
  1018. v_newvalue = hop.genop("cast_ptr_to_adr", [v_newvalue],
  1019. resulttype = llmemory.Address)
  1020. v_structaddr = hop.genop("cast_ptr_to_adr", [v_struct],
  1021. resulttype = llmemory.Address)
  1022. if (self.write_barrier_from_array_ptr is not None and
  1023. self._set_into_gc_array_part(hop.spaceop) is not None):
  1024. self.write_barrier_from_array_calls += 1
  1025. v_index = self._set_into_gc_array_part(hop.spaceop)
  1026. assert v_index.concretetype == lltype.Signed
  1027. hop.genop("direct_call", [self.write_barrier_from_array_ptr,
  1028. self.c_const_gc,
  1029. v_newvalue,
  1030. v_structaddr,
  1031. v_index])
  1032. else:
  1033. self.write_barrier_calls += 1
  1034. hop.genop("direct_call", [self.write_barrier_ptr,
  1035. self.c_const_gc,
  1036. v_newvalue,
  1037. v_structaddr])
  1038. hop.rename('bare_' + opname)
  1039. def transform_getfield_typeptr(self, hop):
  1040. # this would become quite a lot of operations, even if it compiles
  1041. # to C code that is just as efficient as "obj->typeptr". To avoid
  1042. # that, we just generate a single custom operation instead.
  1043. hop.genop('gc_gettypeptr_group', [hop.spaceop.args[0],
  1044. self.c_type_info_group,
  1045. self.c_vtinfo_skip_offset,
  1046. self.c_vtableinfo],
  1047. resultvar = hop.spaceop.result)
  1048. def transform_setfield_typeptr(self, hop):
  1049. # replace such a setfield with an assertion that the typeptr is right
  1050. # (xxx not very useful right now, so disabled)
  1051. if 0:
  1052. v_new = hop.spaceop.args[2]
  1053. v_old = hop.genop('gc_gettypeptr_group', [hop.spaceop.args[0],
  1054. self.c_type_info_group,
  1055. self.c_vtinfo_skip_offset,
  1056. self.c_vtableinfo],
  1057. resulttype = v_new.concretetype)
  1058. v_eq = hop.genop("ptr_eq", [v_old, v_new],
  1059. resulttype = lltype.Bool)
  1060. c_errmsg = rmodel.inputconst(lltype.Void,
  1061. "setfield_typeptr: wrong type")
  1062. hop.genop('debug_assert', [v_eq, c_errmsg])
  1063. def gct_getfield(self, hop):
  1064. if (hop.spaceop.args[1].value == 'typeptr' and
  1065. hop.spaceop.args[0].concretetype.TO._hints.get('typeptr') and
  1066. self.translator.config.translation.gcremovetypeptr):
  1067. self.transform_getfield_typeptr(hop)
  1068. else:
  1069. GCTransformer.gct_getfield(self, hop)
  1070. def gct_setfield(self, hop):
  1071. if (hop.spaceop.args[1].value == 'typeptr' and
  1072. hop.spaceop.args[0].concretetype.TO._hints.get('typeptr') and
  1073. self.translator.config.translation.gcremovetypeptr):
  1074. self.transform_setfield_typeptr(hop)
  1075. else:
  1076. GCTransformer.gct_setfield(self, hop)
  1077. def var_needs_set_transform(self, var):
  1078. return var_needsgc(var)
  1079. def push_alive_nopyobj(self, var, llops):
  1080. pass
  1081. def pop_alive_nopyobj(self, var, llops):
  1082. pass
  1083. def get_livevars_for_roots(self, hop, keep_current_args=False):
  1084. if self.gcdata.gc.moving_gc and not keep_current_args:
  1085. # moving GCs don't borrow, so the caller does not need to keep
  1086. # the arguments alive
  1087. livevars = [var for var in hop.livevars_after_op()
  1088. if not var_ispyobj(var)]
  1089. else:
  1090. livevars = hop.livevars_after_op() + hop.current_op_keeps_alive()
  1091. livevars = [var for var in livevars if not var_ispyobj(var)]
  1092. return livevars
  1093. def push_roots(self, hop, keep_current_args=False):
  1094. if self.incr_stack_ptr is None:
  1095. return
  1096. livevars = self.get_livevars_for_roots(hop, keep_current_args)
  1097. self.num_pushs += len(livevars)
  1098. if not livevars:
  1099. return []
  1100. c_len = rmodel.inputconst(lltype.Signed, len(livevars) )
  1101. base_addr = hop.genop("direct_call", [self.incr_stack_ptr, c_len ],
  1102. resulttype=llmemory.Address)
  1103. c_type = rmodel.inputconst(lltype.Void, llmemory.Address)
  1104. for k,var in enumerate(livevars):
  1105. c_k = rmodel.inputconst(lltype.Signed, k)
  1106. v_adr = gen_cast(hop.llops, llmemory.Address, var)
  1107. hop.genop("raw_store", [base_addr, c_type, c_k, v_adr])
  1108. return livevars
  1109. def pop_roots(self, hop, livevars):
  1110. if self.decr_stack_ptr is None:
  1111. return
  1112. if not livevars:
  1113. return
  1114. c_len = rmodel.inputconst(lltype.Signed, len(livevars) )
  1115. base_addr = hop.genop("direct_call", [self.decr_stack_ptr, c_len ],
  1116. resulttype=llmemory.Address)
  1117. if self.gcdata.gc.moving_gc:
  1118. # for moving collectors, reload the roots into the local variables
  1119. c_type = rmodel.inputconst(lltype.Void, llmemory.Address)
  1120. for k,var in enumerate(livevars):
  1121. c_k = rmodel.inputconst(lltype.Signed, k)
  1122. v_newaddr = hop.genop("raw_load", [base_addr, c_type, c_k],
  1123. resulttype=llmemory.Address)
  1124. hop.genop("gc_reload_possibly_moved", [v_newaddr, var])
  1125. def compute_borrowed_vars(self, graph):
  1126. # XXX temporary workaround, should be done more correctly
  1127. if self.gcdata.gc.moving_gc:
  1128. return lambda v: False
  1129. return super(FrameworkGCTransformer, self).compute_borrowed_vars(graph)
  1130. class TransformerLayoutBuilder(gctypelayout.TypeLayoutBuilder):
  1131. def __init__(self, translator, GCClass=None):
  1132. if GCClass is None:
  1133. from pypy.rpython.memory.gc.base import choose_gc_from_config
  1134. GCClass, _ = choose_gc_from_config(translator.config)
  1135. if translator.config.translation.gcremovetypeptr:
  1136. lltype2vtable = translator.rtyper.lltype2vtable
  1137. else:
  1138. lltype2vtable = None
  1139. self.translator = translator
  1140. super(TransformerLayoutBuilder, self).__init__(GCClass, lltype2vtable)
  1141. def has_finalizer(self, TYPE):
  1142. rtti = get_rtti(TYPE)
  1143. return rtti is not None and getattr(rtti._obj, 'destructor_funcptr',
  1144. None)
  1145. def has_light_finalizer(self, TYPE):
  1146. special = self.special_funcptr_for_type(TYPE)
  1147. return special is not None and special[0] == 'light_finalizer'
  1148. def has_custom_trace(self, TYPE):
  1149. rtti = get_rtti(TYPE)
  1150. return rtti is not None and getattr(rtti._obj, 'custom_trace_funcptr',
  1151. None)
  1152. def make_finalizer_funcptr_for_type(self, TYPE):
  1153. if not self.has_finalizer(TYPE):
  1154. return None, False
  1155. rtti = get_rtti(TYPE)
  1156. destrptr = rtti._obj.destructor_funcptr
  1157. DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0]
  1158. assert not type_contains_pyobjs(TYPE), "not implemented"
  1159. typename = TYPE.__name__
  1160. def ll_finalizer(addr, ignored):
  1161. v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG)
  1162. ll_call_destructor(destrptr, v, typename)
  1163. return llmemory.NULL
  1164. fptr = self.transformer.annotate_finalizer(ll_finalizer,
  1165. [llmemory.Address, llmemory.Address], llmemory.Address)
  1166. g = destrptr._obj.graph
  1167. light = not FinalizerAnalyzer(self.translator).analyze_light_finalizer(g)
  1168. return fptr, light
  1169. def make_custom_trace_funcptr_for_type(self, TYPE):
  1170. if not self.has_custom_trace(TYPE):
  1171. return None
  1172. rtti = get_rtti(TYPE)
  1173. fptr = rtti._obj.custom_trace_funcptr
  1174. if not hasattr(fptr._obj, 'graph'):
  1175. ll_func = fptr._obj._callable
  1176. fptr = self.transformer.annotate_finalizer(ll_func,
  1177. [llmemory.Address, llmemory.Address], llmemory.Address)
  1178. return fptr
  1179. def gen_zero_gc_pointers(TYPE, v, llops, previous_steps=None):
  1180. if previous_steps is None:
  1181. previous_steps = []
  1182. assert isinstance(TYPE, lltype.Struct)
  1183. for name in TYPE._names:
  1184. c_name = rmodel.inputconst(lltype.Void, name)
  1185. FIELD = getattr(TYPE, name)
  1186. if isinstance(FIELD, lltype.Ptr) and FIELD._needsgc():
  1187. c_null = rmodel.inputconst(FIELD, lltype.nullptr(FIELD.TO))
  1188. if not previous_steps:
  1189. llops.genop('bare_setfield', [v, c_name, c_null])
  1190. else:
  1191. llops.genop('bare_setinteriorfield',
  1192. [v] + previous_steps + [c_name, c_null])
  1193. elif isinstance(FIELD, lltype.Struct):
  1194. gen_zero_gc_pointers(FIELD, v, llops, previous_steps + [c_name])
  1195. # ____________________________________________________________
  1196. sizeofaddr = llmemory.sizeof(llmemory.Address)
  1197. class BaseRootWalker(object):
  1198. need_root_stack = False
  1199. thread_setup = None
  1200. def __init__(self, gctransformer):
  1201. self.gcdata = gctransformer.gcdata
  1202. self.gc = self.gcdata.gc
  1203. def _freeze_(self):
  1204. return True
  1205. def setup_root_walker(self):
  1206. if self.thread_setup is not None:
  1207. self.thread_setup()
  1208. def walk_roots(self, collect_stack_root,
  1209. collect_static_in_prebuilt_nongc,
  1210. collect_static_in_prebuilt_gc):
  1211. gcdata = self.gcdata
  1212. gc = self.gc
  1213. if collect_static_in_prebuilt_nongc:
  1214. addr = gcdata.static_root_start
  1215. end = gcdata.static_root_nongcend
  1216. while addr != end:
  1217. result = addr.address[0]
  1218. if gc.points_to_valid_gc_object(result):
  1219. collect_static_in_prebuilt_nongc(gc, result)
  1220. addr += sizeofaddr
  1221. if collect_static_in_prebuilt_gc:
  1222. addr = gcdata.static_root_nongcend
  1223. end = gcdata.static_root_end
  1224. while addr != end:
  1225. result = addr.address[0]
  1226. if gc.points_to_valid_gc_object(result):
  1227. collect_static_in_prebuilt_gc(gc, result)
  1228. addr += sizeofaddr
  1229. if collect_stack_root:
  1230. self.walk_stack_roots(collect_stack_root) # abstract
  1231. def need_stacklet_support(self):
  1232. raise Exception("%s does not support stacklets" % (
  1233. self.__class__.__name__,))
  1234. def need_thread_support(self, gctransformer, getfn):
  1235. raise Exception("%s does not support threads" % (
  1236. self.__class__.__name__,))