PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/rpython/memory/gcwrapper.py

https://bitbucket.org/alex_gaynor/pypy-postgresql/
Python | 245 lines | 202 code | 33 blank | 10 comment | 47 complexity | b7cfbcfd9e44d8e0dacbcc66f67b2902 MD5 | raw file
  1. from pypy.rpython.lltypesystem import lltype, llmemory, llheap
  2. from pypy.rpython import llinterp
  3. from pypy.rpython.annlowlevel import llhelper
  4. from pypy.rpython.memory import gctypelayout
  5. from pypy.objspace.flow.model import Constant
  6. class GCManagedHeap(object):
  7. def __init__(self, llinterp, flowgraphs, gc_class, GC_PARAMS={}):
  8. translator = llinterp.typer.annotator.translator
  9. config = translator.config.translation
  10. self.gc = gc_class(config,
  11. chunk_size = 10,
  12. translated_to_c = False,
  13. **GC_PARAMS)
  14. self.gc.set_root_walker(LLInterpRootWalker(self))
  15. self.gc.DEBUG = True
  16. self.llinterp = llinterp
  17. self.prepare_graphs(flowgraphs)
  18. self.gc.setup()
  19. self.has_write_barrier_from_array = hasattr(self.gc,
  20. 'write_barrier_from_array')
  21. def prepare_graphs(self, flowgraphs):
  22. lltype2vtable = self.llinterp.typer.lltype2vtable
  23. layoutbuilder = DirectRunLayoutBuilder(self.gc.__class__,
  24. lltype2vtable,
  25. self.llinterp)
  26. self.get_type_id = layoutbuilder.get_type_id
  27. layoutbuilder.initialize_gc_query_function(self.gc)
  28. constants = collect_constants(flowgraphs)
  29. for obj in constants:
  30. TYPE = lltype.typeOf(obj)
  31. layoutbuilder.consider_constant(TYPE, obj, self.gc)
  32. self.constantroots = layoutbuilder.addresses_of_static_ptrs
  33. self.constantrootsnongc = layoutbuilder.addresses_of_static_ptrs_in_nongc
  34. self._all_prebuilt_gc = layoutbuilder.all_prebuilt_gc
  35. # ____________________________________________________________
  36. #
  37. # Interface for the llinterp
  38. #
  39. def malloc(self, TYPE, n=None, flavor='gc', zero=False,
  40. track_allocation=True):
  41. if flavor == 'gc':
  42. typeid = self.get_type_id(TYPE)
  43. addr = self.gc.malloc(typeid, n, zero=zero)
  44. result = llmemory.cast_adr_to_ptr(addr, lltype.Ptr(TYPE))
  45. if not self.gc.malloc_zero_filled:
  46. gctypelayout.zero_gc_pointers(result)
  47. return result
  48. else:
  49. return lltype.malloc(TYPE, n, flavor=flavor, zero=zero,
  50. track_allocation=track_allocation)
  51. def malloc_nonmovable(self, TYPE, n=None, zero=False):
  52. typeid = self.get_type_id(TYPE)
  53. if not self.gc.can_malloc_nonmovable():
  54. return lltype.nullptr(TYPE)
  55. addr = self.gc.malloc_nonmovable(typeid, n, zero=zero)
  56. result = llmemory.cast_adr_to_ptr(addr, lltype.Ptr(TYPE))
  57. if not self.gc.malloc_zero_filled:
  58. gctypelayout.zero_gc_pointers(result)
  59. return result
  60. def shrink_array(self, p, smallersize):
  61. if hasattr(self.gc, 'shrink_array'):
  62. addr = llmemory.cast_ptr_to_adr(p)
  63. return self.gc.shrink_array(addr, smallersize)
  64. return False
  65. def free(self, TYPE, flavor='gc', track_allocation=True):
  66. assert flavor != 'gc'
  67. return lltype.free(TYPE, flavor=flavor,
  68. track_allocation=track_allocation)
  69. def setfield(self, obj, fieldname, fieldvalue):
  70. STRUCT = lltype.typeOf(obj).TO
  71. addr = llmemory.cast_ptr_to_adr(obj)
  72. addr += llmemory.offsetof(STRUCT, fieldname)
  73. self.setinterior(obj, addr, getattr(STRUCT, fieldname), fieldvalue)
  74. def setarrayitem(self, array, index, newitem):
  75. ARRAY = lltype.typeOf(array).TO
  76. addr = llmemory.cast_ptr_to_adr(array)
  77. addr += llmemory.itemoffsetof(ARRAY, index)
  78. self.setinterior(array, addr, ARRAY.OF, newitem, (index,))
  79. def setinterior(self, toplevelcontainer, inneraddr, INNERTYPE, newvalue,
  80. offsets=()):
  81. if (lltype.typeOf(toplevelcontainer).TO._gckind == 'gc' and
  82. isinstance(INNERTYPE, lltype.Ptr) and INNERTYPE.TO._gckind == 'gc'):
  83. #
  84. wb = True
  85. if self.has_write_barrier_from_array:
  86. for index in offsets:
  87. if type(index) is not str:
  88. assert (type(index) is int # <- fast path
  89. or lltype.typeOf(index) == lltype.Signed)
  90. self.gc.write_barrier_from_array(
  91. llmemory.cast_ptr_to_adr(newvalue),
  92. llmemory.cast_ptr_to_adr(toplevelcontainer),
  93. index)
  94. wb = False
  95. break
  96. #
  97. if wb:
  98. self.gc.write_barrier(
  99. llmemory.cast_ptr_to_adr(newvalue),
  100. llmemory.cast_ptr_to_adr(toplevelcontainer))
  101. llheap.setinterior(toplevelcontainer, inneraddr, INNERTYPE, newvalue)
  102. def collect(self, *gen):
  103. self.gc.collect(*gen)
  104. def can_move(self, addr):
  105. return self.gc.can_move(addr)
  106. def weakref_create_getlazy(self, objgetter):
  107. # we have to be lazy in reading the llinterp variable containing
  108. # the 'obj' pointer, because the gc.malloc() call below could
  109. # move it around
  110. type_id = self.get_type_id(gctypelayout.WEAKREF)
  111. addr = self.gc.malloc(type_id, None, zero=False)
  112. result = llmemory.cast_adr_to_ptr(addr, gctypelayout.WEAKREFPTR)
  113. result.weakptr = llmemory.cast_ptr_to_adr(objgetter())
  114. return llmemory.cast_ptr_to_weakrefptr(result)
  115. def weakref_deref(self, PTRTYPE, obj):
  116. addr = gctypelayout.ll_weakref_deref(obj)
  117. return llmemory.cast_adr_to_ptr(addr, PTRTYPE)
  118. def gc_id(self, ptr):
  119. ptr = lltype.cast_opaque_ptr(llmemory.GCREF, ptr)
  120. return self.gc.id(ptr)
  121. def writebarrier_before_copy(self, source, dest):
  122. if self.gc.needs_write_barrier:
  123. source_addr = llmemory.cast_ptr_to_adr(source)
  124. dest_addr = llmemory.cast_ptr_to_adr(dest)
  125. return self.gc.writebarrier_before_copy(source_addr, dest_addr)
  126. else:
  127. return True
  128. def pyobjectptr(self, klass):
  129. raise NotImplementedError(klass)
  130. # ____________________________________________________________
  131. class LLInterpRootWalker:
  132. _alloc_flavor_ = 'raw'
  133. def __init__(self, gcheap):
  134. self.gcheap = gcheap
  135. def walk_roots(self, collect_stack_root,
  136. collect_static_in_prebuilt_nongc,
  137. collect_static_in_prebuilt_gc):
  138. gcheap = self.gcheap
  139. gc = gcheap.gc
  140. if collect_static_in_prebuilt_gc:
  141. for addrofaddr in gcheap.constantroots:
  142. if self.gcheap.gc.points_to_valid_gc_object(addrofaddr):
  143. collect_static_in_prebuilt_gc(gc, addrofaddr)
  144. if collect_static_in_prebuilt_nongc:
  145. for addrofaddr in gcheap.constantrootsnongc:
  146. if self.gcheap.gc.points_to_valid_gc_object(addrofaddr):
  147. collect_static_in_prebuilt_nongc(gc, addrofaddr)
  148. if collect_stack_root:
  149. for addrofaddr in gcheap.llinterp.find_roots():
  150. if self.gcheap.gc.points_to_valid_gc_object(addrofaddr):
  151. collect_stack_root(gc, addrofaddr)
  152. def _walk_prebuilt_gc(self, collect): # debugging only! not RPython
  153. for obj in self.gcheap._all_prebuilt_gc:
  154. collect(llmemory.cast_ptr_to_adr(obj._as_ptr()))
  155. class DirectRunLayoutBuilder(gctypelayout.TypeLayoutBuilder):
  156. def __init__(self, GCClass, lltype2vtable, llinterp):
  157. self.llinterp = llinterp
  158. super(DirectRunLayoutBuilder, self).__init__(GCClass, lltype2vtable)
  159. def make_finalizer_funcptr_for_type(self, TYPE):
  160. from pypy.rpython.memory.gctransform.support import get_rtti, \
  161. type_contains_pyobjs
  162. rtti = get_rtti(TYPE)
  163. if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'):
  164. destrptr = rtti._obj.destructor_funcptr
  165. DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0]
  166. destrgraph = destrptr._obj.graph
  167. else:
  168. return lltype.nullptr(gctypelayout.GCData.FINALIZERTYPE.TO)
  169. assert not type_contains_pyobjs(TYPE), "not implemented"
  170. def ll_finalizer(addr):
  171. try:
  172. v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG)
  173. self.llinterp.eval_graph(destrgraph, [v], recursive=True)
  174. except llinterp.LLException:
  175. raise RuntimeError(
  176. "a finalizer raised an exception, shouldn't happen")
  177. return llhelper(gctypelayout.GCData.FINALIZERTYPE, ll_finalizer)
  178. def collect_constants(graphs):
  179. constants = {}
  180. def collect_args(args):
  181. for arg in args:
  182. if (isinstance(arg, Constant) and
  183. arg.concretetype is not lltype.Void):
  184. reccollect(constants, arg.value)
  185. for graph in graphs:
  186. for block in graph.iterblocks():
  187. collect_args(block.inputargs)
  188. for op in block.operations:
  189. collect_args(op.args)
  190. for link in graph.iterlinks():
  191. collect_args(link.args)
  192. if hasattr(link, "llexitcase"):
  193. reccollect(constants, link.llexitcase)
  194. return constants
  195. def reccollect(constants, llvalue):
  196. if (isinstance(llvalue, lltype._abstract_ptr)
  197. and llvalue._obj is not None and llvalue._obj not in constants
  198. and not isinstance(llvalue._obj, int)):
  199. TYPE = llvalue._T
  200. constants[llvalue._obj] = True
  201. if isinstance(TYPE, lltype.Struct):
  202. for name in TYPE._names:
  203. reccollect(constants, getattr(llvalue, name))
  204. elif isinstance(TYPE, lltype.Array):
  205. for llitem in llvalue:
  206. reccollect(constants, llitem)
  207. parent, parentindex = lltype.parentlink(llvalue._obj)
  208. if parent is not None:
  209. reccollect(constants, parent._as_ptr())
  210. def prepare_graphs_and_create_gc(llinterp, GCClass, GC_PARAMS={}):
  211. flowgraphs = llinterp.typer.annotator.translator.graphs[:]
  212. llinterp.heap = GCManagedHeap(llinterp, flowgraphs, GCClass, GC_PARAMS)