PageRenderTime 47ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/translator/c/gc.py

https://bitbucket.org/pypy/pypy/
Python | 418 lines | 356 code | 48 blank | 14 comment | 13 complexity | a7f399601ae753f3758ca5458a1ea381 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import sys
  2. from pypy.objspace.flow.model import Constant
  3. from pypy.translator.c.support import cdecl
  4. from pypy.translator.c.node import ContainerNode
  5. from pypy.rpython.lltypesystem.lltype import \
  6. typeOf, Ptr, ContainerType, RttiStruct, \
  7. RuntimeTypeInfo, getRuntimeTypeInfo, top_container
  8. from pypy.rpython.memory.gctransform import \
  9. refcounting, boehm, framework, asmgcroot
  10. from pypy.rpython.lltypesystem import lltype, llmemory
  11. from pypy.translator.tool.cbuild import ExternalCompilationInfo
  12. class BasicGcPolicy(object):
  13. stores_hash_at_the_end = False
  14. def __init__(self, db, thread_enabled=False):
  15. self.db = db
  16. self.thread_enabled = thread_enabled
  17. def common_gcheader_definition(self, defnode):
  18. if defnode.db.gctransformer is not None:
  19. return defnode.db.gctransformer.HDR
  20. return None
  21. def common_gcheader_initdata(self, defnode):
  22. if defnode.db.gctransformer is not None:
  23. raise NotImplementedError
  24. return None
  25. def struct_gcheader_definition(self, defnode):
  26. return self.common_gcheader_definition(defnode)
  27. def struct_gcheader_initdata(self, defnode):
  28. return self.common_gcheader_initdata(defnode)
  29. def array_gcheader_definition(self, defnode):
  30. return self.common_gcheader_definition(defnode)
  31. def array_gcheader_initdata(self, defnode):
  32. return self.common_gcheader_initdata(defnode)
  33. def compilation_info(self):
  34. if not self.db:
  35. return ExternalCompilationInfo()
  36. gct = self.db.gctransformer
  37. return ExternalCompilationInfo(
  38. pre_include_bits=['/* using %s */' % (gct.__class__.__name__,),
  39. '#define MALLOC_ZERO_FILLED %d' % (gct.malloc_zero_filled,),
  40. ],
  41. post_include_bits=['typedef void *GC_hidden_pointer;']
  42. )
  43. def get_prebuilt_hash(self, obj):
  44. return None
  45. def need_no_typeptr(self):
  46. return False
  47. def gc_startup_code(self):
  48. return []
  49. def struct_setup(self, structdefnode, rtti):
  50. return None
  51. def array_setup(self, arraydefnode):
  52. return None
  53. def rtti_type(self):
  54. return ''
  55. def OP_GC_PUSH_ALIVE_PYOBJ(self, funcgen, op):
  56. expr = funcgen.expr(op.args[0])
  57. if expr == 'NULL':
  58. return ''
  59. return 'Py_XINCREF(%s);' % expr
  60. def OP_GC_POP_ALIVE_PYOBJ(self, funcgen, op):
  61. expr = funcgen.expr(op.args[0])
  62. return 'Py_XDECREF(%s);' % expr
  63. def OP_GC_SET_MAX_HEAP_SIZE(self, funcgen, op):
  64. return ''
  65. def OP_GC_THREAD_PREPARE(self, funcgen, op):
  66. return ''
  67. def OP_GC_THREAD_RUN(self, funcgen, op):
  68. return ''
  69. def OP_GC_THREAD_START(self, funcgen, op):
  70. return ''
  71. def OP_GC_THREAD_DIE(self, funcgen, op):
  72. return ''
  73. def OP_GC_THREAD_BEFORE_FORK(self, funcgen, op):
  74. return '%s = NULL;' % funcgen.expr(op.result)
  75. def OP_GC_THREAD_AFTER_FORK(self, funcgen, op):
  76. return ''
  77. def OP_GC_ASSUME_YOUNG_POINTERS(self, funcgen, op):
  78. return ''
  79. def OP_GC_STACK_BOTTOM(self, funcgen, op):
  80. return ''
  81. class RefcountingInfo:
  82. static_deallocator = None
  83. from pypy.rlib.objectmodel import CDefinedIntSymbolic
  84. class RefcountingGcPolicy(BasicGcPolicy):
  85. transformerclass = refcounting.RefcountingGCTransformer
  86. def common_gcheader_initdata(self, defnode):
  87. if defnode.db.gctransformer is not None:
  88. gct = defnode.db.gctransformer
  89. top = top_container(defnode.obj)
  90. return gct.gcheaderbuilder.header_of_object(top)._obj
  91. return None
  92. # for structs
  93. def struct_setup(self, structdefnode, rtti):
  94. if rtti is not None:
  95. transformer = structdefnode.db.gctransformer
  96. fptr = transformer.static_deallocation_funcptr_for_type(
  97. structdefnode.STRUCT)
  98. structdefnode.gcinfo = RefcountingInfo()
  99. structdefnode.gcinfo.static_deallocator = structdefnode.db.get(fptr)
  100. # for arrays
  101. def array_setup(self, arraydefnode):
  102. pass
  103. # for rtti node
  104. def rtti_type(self):
  105. return 'void (@)(void *)' # void dealloc_xx(struct xx *)
  106. def rtti_node_factory(self):
  107. return RefcountingRuntimeTypeInfo_OpaqueNode
  108. # zero malloc impl
  109. def OP_GC_CALL_RTTI_DESTRUCTOR(self, funcgen, op):
  110. args = [funcgen.expr(v) for v in op.args]
  111. line = '%s(%s);' % (args[0], ', '.join(args[1:]))
  112. return line
  113. def OP_GC_FREE(self, funcgen, op):
  114. args = [funcgen.expr(v) for v in op.args]
  115. return 'OP_FREE(%s);' % (args[0], )
  116. def OP_GC__COLLECT(self, funcgen, op):
  117. return ''
  118. def OP_GC__DISABLE_FINALIZERS(self, funcgen, op):
  119. return ''
  120. def OP_GC__ENABLE_FINALIZERS(self, funcgen, op):
  121. return ''
  122. class RefcountingRuntimeTypeInfo_OpaqueNode(ContainerNode):
  123. nodekind = 'refcnt rtti'
  124. globalcontainer = True
  125. typename = 'void (@)(void *)'
  126. _funccodegen_owner = None
  127. def __init__(self, db, T, obj):
  128. assert T == RuntimeTypeInfo
  129. assert isinstance(obj.about, RttiStruct)
  130. self.db = db
  131. self.T = T
  132. self.obj = obj
  133. defnode = db.gettypedefnode(obj.about)
  134. self.implementationtypename = 'void (@)(void *)'
  135. self.name = defnode.gcinfo.static_deallocator
  136. def getptrname(self):
  137. return '((void (*)(void *)) %s)' % (self.name,)
  138. def enum_dependencies(self):
  139. return []
  140. def implementation(self):
  141. return []
  142. class BoehmInfo:
  143. finalizer = None
  144. class BoehmGcPolicy(BasicGcPolicy):
  145. transformerclass = boehm.BoehmGCTransformer
  146. def common_gcheader_initdata(self, defnode):
  147. if defnode.db.gctransformer is not None:
  148. hdr = lltype.malloc(defnode.db.gctransformer.HDR, immortal=True)
  149. hdr.hash = lltype.identityhash_nocache(defnode.obj._as_ptr())
  150. return hdr._obj
  151. return None
  152. def array_setup(self, arraydefnode):
  153. pass
  154. def struct_setup(self, structdefnode, rtti):
  155. pass
  156. def rtti_type(self):
  157. return BoehmGcRuntimeTypeInfo_OpaqueNode.typename
  158. def rtti_node_factory(self):
  159. return BoehmGcRuntimeTypeInfo_OpaqueNode
  160. def compilation_info(self):
  161. eci = BasicGcPolicy.compilation_info(self)
  162. from pypy.rpython.tool.rffi_platform import configure_boehm
  163. eci = eci.merge(configure_boehm())
  164. pre_include_bits = []
  165. if sys.platform.startswith('linux'):
  166. pre_include_bits += ["#define _REENTRANT 1",
  167. "#define GC_LINUX_THREADS 1"]
  168. if sys.platform != "win32" and not sys.platform.startswith("openbsd"):
  169. # GC_REDIRECT_TO_LOCAL is not supported on Win32 by gc6.8
  170. pre_include_bits += ["#define GC_REDIRECT_TO_LOCAL 1"]
  171. eci = eci.merge(ExternalCompilationInfo(
  172. pre_include_bits=pre_include_bits,
  173. post_include_bits=['#define USING_BOEHM_GC'],
  174. ))
  175. return eci
  176. def gc_startup_code(self):
  177. if sys.platform == 'win32':
  178. pass # yield 'assert(GC_all_interior_pointers == 0);'
  179. else:
  180. yield 'GC_all_interior_pointers = 0;'
  181. yield 'boehm_gc_startup_code();'
  182. def get_real_weakref_type(self):
  183. return boehm.WEAKLINK
  184. def convert_weakref_to(self, ptarget):
  185. return boehm.convert_weakref_to(ptarget)
  186. def OP_GC__COLLECT(self, funcgen, op):
  187. return 'GC_gcollect();'
  188. def OP_GC_SET_MAX_HEAP_SIZE(self, funcgen, op):
  189. nbytes = funcgen.expr(op.args[0])
  190. return 'GC_set_max_heap_size(%s);' % (nbytes,)
  191. def GC_KEEPALIVE(self, funcgen, v):
  192. return 'pypy_asm_keepalive(%s);' % funcgen.expr(v)
  193. class BoehmGcRuntimeTypeInfo_OpaqueNode(ContainerNode):
  194. nodekind = 'boehm rtti'
  195. globalcontainer = True
  196. typename = 'char @'
  197. _funccodegen_owner = None
  198. def __init__(self, db, T, obj):
  199. assert T == RuntimeTypeInfo
  200. assert isinstance(obj.about, RttiStruct)
  201. self.db = db
  202. self.T = T
  203. self.obj = obj
  204. defnode = db.gettypedefnode(obj.about)
  205. self.implementationtypename = self.typename
  206. self.name = self.db.namespace.uniquename('g_rtti_v_'+ defnode.barename)
  207. def getptrname(self):
  208. return '(&%s)' % (self.name,)
  209. def enum_dependencies(self):
  210. return []
  211. def implementation(self):
  212. yield 'char %s /* uninitialized */;' % self.name
  213. class FrameworkGcRuntimeTypeInfo_OpaqueNode(BoehmGcRuntimeTypeInfo_OpaqueNode):
  214. nodekind = 'framework rtti'
  215. # to get an idea how it looks like with no refcount/gc at all
  216. class NoneGcPolicy(BoehmGcPolicy):
  217. gc_startup_code = RefcountingGcPolicy.gc_startup_code.im_func
  218. def compilation_info(self):
  219. eci = BasicGcPolicy.compilation_info(self)
  220. eci = eci.merge(ExternalCompilationInfo(
  221. post_include_bits=['#define USING_NO_GC_AT_ALL'],
  222. ))
  223. return eci
  224. class FrameworkGcPolicy(BasicGcPolicy):
  225. transformerclass = framework.FrameworkGCTransformer
  226. stores_hash_at_the_end = True
  227. def struct_setup(self, structdefnode, rtti):
  228. if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'):
  229. destrptr = rtti._obj.destructor_funcptr
  230. # make sure this is seen by the database early, i.e. before
  231. # finish_helpers() on the gctransformer
  232. self.db.get(destrptr)
  233. # the following, on the other hand, will only discover ll_finalizer
  234. # helpers. The get() sees and records a delayed pointer. It is
  235. # still important to see it so that it can be followed as soon as
  236. # the mixlevelannotator resolves it.
  237. gctransf = self.db.gctransformer
  238. TYPE = structdefnode.STRUCT
  239. kind_and_fptr = gctransf.special_funcptr_for_type(TYPE)
  240. if kind_and_fptr:
  241. self.db.get(kind_and_fptr[1])
  242. def array_setup(self, arraydefnode):
  243. pass
  244. def rtti_type(self):
  245. return FrameworkGcRuntimeTypeInfo_OpaqueNode.typename
  246. def rtti_node_factory(self):
  247. return FrameworkGcRuntimeTypeInfo_OpaqueNode
  248. def gc_startup_code(self):
  249. fnptr = self.db.gctransformer.frameworkgc_setup_ptr.value
  250. yield '%s();' % (self.db.get(fnptr),)
  251. def get_real_weakref_type(self):
  252. return framework.WEAKREF
  253. def convert_weakref_to(self, ptarget):
  254. return framework.convert_weakref_to(ptarget)
  255. def OP_GC_RELOAD_POSSIBLY_MOVED(self, funcgen, op):
  256. if isinstance(op.args[1], Constant):
  257. return '/* %s */' % (op,)
  258. else:
  259. args = [funcgen.expr(v) for v in op.args]
  260. return '%s = %s; /* for moving GCs */' % (args[1], args[0])
  261. def common_gcheader_initdata(self, defnode):
  262. o = top_container(defnode.obj)
  263. needs_hash = self.get_prebuilt_hash(o) is not None
  264. hdr = defnode.db.gctransformer.gc_header_for(o, needs_hash)
  265. return hdr._obj
  266. def get_prebuilt_hash(self, obj):
  267. # for prebuilt objects that need to have their hash stored and
  268. # restored. Note that only structures that are StructNodes all
  269. # the way have their hash stored (and not e.g. structs with var-
  270. # sized arrays at the end). 'obj' must be the top_container.
  271. TYPE = typeOf(obj)
  272. if not isinstance(TYPE, lltype.GcStruct):
  273. return None
  274. if TYPE._is_varsize():
  275. return None
  276. return getattr(obj, '_hash_cache_', None)
  277. def need_no_typeptr(self):
  278. config = self.db.translator.config
  279. return config.translation.gcremovetypeptr
  280. def OP_GC_GETTYPEPTR_GROUP(self, funcgen, op):
  281. # expands to a number of steps, as per rpython/lltypesystem/opimpl.py,
  282. # all implemented by a single call to a C macro.
  283. [v_obj, c_grpptr, c_skipoffset, c_vtableinfo] = op.args
  284. typename = funcgen.db.gettype(op.result.concretetype)
  285. tid_field = c_vtableinfo.value[2]
  286. # Fish out the C name of the tid field.
  287. HDR = self.db.gctransformer.HDR
  288. hdr_node = self.db.gettypedefnode(HDR)
  289. fieldname = hdr_node.c_struct_field_name(tid_field)
  290. return (
  291. '%s = (%s)_OP_GET_NEXT_GROUP_MEMBER(%s, (pypy_halfword_t)%s->'
  292. '_gcheader.%s, %s);'
  293. % (funcgen.expr(op.result),
  294. cdecl(typename, ''),
  295. funcgen.expr(c_grpptr),
  296. funcgen.expr(v_obj),
  297. fieldname,
  298. funcgen.expr(c_skipoffset)))
  299. def OP_GC_ASSUME_YOUNG_POINTERS(self, funcgen, op):
  300. raise Exception("the FramewokGCTransformer should handle this")
  301. class AsmGcRootFrameworkGcPolicy(FrameworkGcPolicy):
  302. transformerclass = asmgcroot.AsmGcRootFrameworkGCTransformer
  303. def GC_KEEPALIVE(self, funcgen, v):
  304. return 'pypy_asm_keepalive(%s);' % funcgen.expr(v)
  305. def OP_GC_STACK_BOTTOM(self, funcgen, op):
  306. return 'pypy_asm_stack_bottom();'
  307. name_to_gcpolicy = {
  308. 'boehm': BoehmGcPolicy,
  309. 'ref': RefcountingGcPolicy,
  310. 'none': NoneGcPolicy,
  311. 'framework': FrameworkGcPolicy,
  312. 'framework+asmgcroot': AsmGcRootFrameworkGcPolicy,
  313. }