PageRenderTime 25ms CodeModel.GetById 45ms RepoModel.GetById 5ms app.codeStats 0ms

/pypy/translator/c/gc.py

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