PageRenderTime 53ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/rpython/memory/gc/base.py

https://github.com/lalitjsraks/pypy
Python | 372 lines | 302 code | 25 blank | 45 comment | 12 complexity | f1c5e042dc01a5e6b5c8da46e119f473 MD5 | raw file
  1. from pypy.rpython.lltypesystem import lltype, llmemory, llarena
  2. from pypy.rlib.debug import ll_assert
  3. from pypy.rpython.memory.gcheader import GCHeaderBuilder
  4. from pypy.rpython.memory.support import DEFAULT_CHUNK_SIZE
  5. from pypy.rpython.memory.support import get_address_stack, get_address_deque
  6. from pypy.rpython.memory.support import AddressDict
  7. from pypy.rpython.lltypesystem.llmemory import NULL, raw_malloc_usage
  8. TYPEID_MAP = lltype.GcStruct('TYPEID_MAP', ('count', lltype.Signed),
  9. ('size', lltype.Signed),
  10. ('links', lltype.Array(lltype.Signed)))
  11. ARRAY_TYPEID_MAP = lltype.GcArray(lltype.Ptr(TYPEID_MAP))
  12. class GCBase(object):
  13. _alloc_flavor_ = "raw"
  14. moving_gc = False
  15. needs_write_barrier = False
  16. malloc_zero_filled = False
  17. prebuilt_gc_objects_are_static_roots = True
  18. object_minimal_size = 0
  19. def __init__(self, config, chunk_size=DEFAULT_CHUNK_SIZE):
  20. self.gcheaderbuilder = GCHeaderBuilder(self.HDR)
  21. self.AddressStack = get_address_stack(chunk_size)
  22. self.AddressDeque = get_address_deque(chunk_size)
  23. self.AddressDict = AddressDict
  24. self.config = config
  25. def setup(self):
  26. # all runtime mutable values' setup should happen here
  27. # and in its overriden versions! for the benefit of test_transformed_gc
  28. self.finalizer_lock_count = 0
  29. self.run_finalizers = self.AddressDeque()
  30. def _teardown(self):
  31. pass
  32. def can_malloc_nonmovable(self):
  33. return not self.moving_gc
  34. # The following flag enables costly consistency checks after each
  35. # collection. It is automatically set to True by test_gc.py. The
  36. # checking logic is translatable, so the flag can be set to True
  37. # here before translation.
  38. DEBUG = False
  39. def set_query_functions(self, is_varsize, has_gcptr_in_varsize,
  40. is_gcarrayofgcptr,
  41. getfinalizer,
  42. offsets_to_gc_pointers,
  43. fixed_size, varsize_item_sizes,
  44. varsize_offset_to_variable_part,
  45. varsize_offset_to_length,
  46. varsize_offsets_to_gcpointers_in_var_part,
  47. weakpointer_offset,
  48. member_index):
  49. self.getfinalizer = getfinalizer
  50. self.is_varsize = is_varsize
  51. self.has_gcptr_in_varsize = has_gcptr_in_varsize
  52. self.is_gcarrayofgcptr = is_gcarrayofgcptr
  53. self.offsets_to_gc_pointers = offsets_to_gc_pointers
  54. self.fixed_size = fixed_size
  55. self.varsize_item_sizes = varsize_item_sizes
  56. self.varsize_offset_to_variable_part = varsize_offset_to_variable_part
  57. self.varsize_offset_to_length = varsize_offset_to_length
  58. self.varsize_offsets_to_gcpointers_in_var_part = varsize_offsets_to_gcpointers_in_var_part
  59. self.weakpointer_offset = weakpointer_offset
  60. self.member_index = member_index
  61. def get_member_index(self, type_id):
  62. return self.member_index(type_id)
  63. def set_root_walker(self, root_walker):
  64. self.root_walker = root_walker
  65. def write_barrier(self, newvalue, addr_struct):
  66. pass
  67. def statistics(self, index):
  68. return -1
  69. def size_gc_header(self, typeid=0):
  70. return self.gcheaderbuilder.size_gc_header
  71. def header(self, addr):
  72. addr -= self.gcheaderbuilder.size_gc_header
  73. return llmemory.cast_adr_to_ptr(addr, lltype.Ptr(self.HDR))
  74. def _get_size_for_typeid(self, obj, typeid):
  75. size = self.fixed_size(typeid)
  76. if self.is_varsize(typeid):
  77. lenaddr = obj + self.varsize_offset_to_length(typeid)
  78. length = lenaddr.signed[0]
  79. size += length * self.varsize_item_sizes(typeid)
  80. size = llarena.round_up_for_allocation(size)
  81. # XXX maybe we should parametrize round_up_for_allocation()
  82. # per GC; if we do, we also need to fix the call in
  83. # gctypelayout.encode_type_shape()
  84. return size
  85. def get_size(self, obj):
  86. return self._get_size_for_typeid(obj, self.get_type_id(obj))
  87. def malloc(self, typeid, length=0, zero=False):
  88. """For testing. The interface used by the gctransformer is
  89. the four malloc_[fixed,var]size[_clear]() functions.
  90. """
  91. # Rules about fallbacks in case of missing malloc methods:
  92. # * malloc_fixedsize_clear() and malloc_varsize_clear() are mandatory
  93. # * malloc_fixedsize() and malloc_varsize() fallback to the above
  94. # XXX: as of r49360, gctransformer.framework never inserts calls
  95. # to malloc_varsize(), but always uses malloc_varsize_clear()
  96. size = self.fixed_size(typeid)
  97. needs_finalizer = bool(self.getfinalizer(typeid))
  98. contains_weakptr = self.weakpointer_offset(typeid) >= 0
  99. assert not (needs_finalizer and contains_weakptr)
  100. if self.is_varsize(typeid):
  101. assert not contains_weakptr
  102. assert not needs_finalizer
  103. itemsize = self.varsize_item_sizes(typeid)
  104. offset_to_length = self.varsize_offset_to_length(typeid)
  105. if zero or not hasattr(self, 'malloc_varsize'):
  106. malloc_varsize = self.malloc_varsize_clear
  107. else:
  108. malloc_varsize = self.malloc_varsize
  109. ref = malloc_varsize(typeid, length, size, itemsize,
  110. offset_to_length, True)
  111. else:
  112. if zero or not hasattr(self, 'malloc_fixedsize'):
  113. malloc_fixedsize = self.malloc_fixedsize_clear
  114. else:
  115. malloc_fixedsize = self.malloc_fixedsize
  116. ref = malloc_fixedsize(typeid, size, True, needs_finalizer,
  117. contains_weakptr)
  118. # lots of cast and reverse-cast around...
  119. return llmemory.cast_ptr_to_adr(ref)
  120. def malloc_nonmovable(self, typeid, length=0, zero=False):
  121. return self.malloc(typeid, length, zero)
  122. def id(self, ptr):
  123. return lltype.cast_ptr_to_int(ptr)
  124. def can_move(self, addr):
  125. return False
  126. def set_max_heap_size(self, size):
  127. pass
  128. def x_swap_pool(self, newpool):
  129. return newpool
  130. def x_clone(self, clonedata):
  131. raise RuntimeError("no support for x_clone in the GC")
  132. def trace(self, obj, callback, arg):
  133. """Enumerate the locations inside the given obj that can contain
  134. GC pointers. For each such location, callback(pointer, arg) is
  135. called, where 'pointer' is an address inside the object.
  136. Typically, 'callback' is a bound method and 'arg' can be None.
  137. """
  138. typeid = self.get_type_id(obj)
  139. if self.is_gcarrayofgcptr(typeid):
  140. # a performance shortcut for GcArray(gcptr)
  141. length = (obj + llmemory.gcarrayofptr_lengthoffset).signed[0]
  142. item = obj + llmemory.gcarrayofptr_itemsoffset
  143. while length > 0:
  144. if self.points_to_valid_gc_object(item):
  145. callback(item, arg)
  146. item += llmemory.gcarrayofptr_singleitemoffset
  147. length -= 1
  148. return
  149. offsets = self.offsets_to_gc_pointers(typeid)
  150. i = 0
  151. while i < len(offsets):
  152. item = obj + offsets[i]
  153. if self.points_to_valid_gc_object(item):
  154. callback(item, arg)
  155. i += 1
  156. if self.has_gcptr_in_varsize(typeid):
  157. item = obj + self.varsize_offset_to_variable_part(typeid)
  158. length = (obj + self.varsize_offset_to_length(typeid)).signed[0]
  159. offsets = self.varsize_offsets_to_gcpointers_in_var_part(typeid)
  160. itemlength = self.varsize_item_sizes(typeid)
  161. while length > 0:
  162. j = 0
  163. while j < len(offsets):
  164. itemobj = item + offsets[j]
  165. if self.points_to_valid_gc_object(itemobj):
  166. callback(itemobj, arg)
  167. j += 1
  168. item += itemlength
  169. length -= 1
  170. trace._annspecialcase_ = 'specialize:arg(2)'
  171. def points_to_valid_gc_object(self, addr):
  172. return self.is_valid_gc_object(addr.address[0])
  173. def is_valid_gc_object(self, addr):
  174. return (addr != NULL and
  175. (not self.config.taggedpointers or
  176. llmemory.cast_adr_to_int(addr) & 1 == 0))
  177. def debug_check_consistency(self):
  178. """To use after a collection. If self.DEBUG is set, this
  179. enumerates all roots and traces all objects to check if we didn't
  180. accidentally free a reachable object or forgot to update a pointer
  181. to an object that moved.
  182. """
  183. if self.DEBUG:
  184. from pypy.rlib.objectmodel import we_are_translated
  185. from pypy.rpython.memory.support import AddressDict
  186. self._debug_seen = AddressDict()
  187. self._debug_pending = self.AddressStack()
  188. if not we_are_translated():
  189. self.root_walker._walk_prebuilt_gc(self._debug_record)
  190. callback = GCBase._debug_callback
  191. self.root_walker.walk_roots(callback, callback, callback)
  192. pending = self._debug_pending
  193. while pending.non_empty():
  194. obj = pending.pop()
  195. self.trace(obj, self._debug_callback2, None)
  196. self._debug_seen.delete()
  197. self._debug_pending.delete()
  198. def _debug_record(self, obj):
  199. seen = self._debug_seen
  200. if not seen.contains(obj):
  201. seen.add(obj)
  202. self.debug_check_object(obj)
  203. self._debug_pending.append(obj)
  204. def _debug_callback(self, root):
  205. obj = root.address[0]
  206. ll_assert(bool(obj), "NULL address from walk_roots()")
  207. self._debug_record(obj)
  208. def _debug_callback2(self, pointer, ignored):
  209. obj = pointer.address[0]
  210. ll_assert(bool(obj), "NULL address from self.trace()")
  211. self._debug_record(obj)
  212. def debug_check_object(self, obj):
  213. pass
  214. def execute_finalizers(self):
  215. self.finalizer_lock_count += 1
  216. try:
  217. while self.run_finalizers.non_empty():
  218. if self.finalizer_lock_count > 1:
  219. # the outer invocation of execute_finalizers() will do it
  220. break
  221. obj = self.run_finalizers.popleft()
  222. finalizer = self.getfinalizer(self.get_type_id(obj))
  223. finalizer(obj)
  224. finally:
  225. self.finalizer_lock_count -= 1
  226. class MovingGCBase(GCBase):
  227. moving_gc = True
  228. def setup(self):
  229. GCBase.setup(self)
  230. self.objects_with_id = self.AddressDict()
  231. self.id_free_list = self.AddressStack()
  232. self.next_free_id = 1
  233. def can_move(self, addr):
  234. return True
  235. def id(self, ptr):
  236. # Default implementation for id(), assuming that "external" objects
  237. # never move. Overriden in the HybridGC.
  238. obj = llmemory.cast_ptr_to_adr(ptr)
  239. # is it a tagged pointer? or an external object?
  240. if not self.is_valid_gc_object(obj) or self._is_external(obj):
  241. return llmemory.cast_adr_to_int(obj)
  242. # tagged pointers have ids of the form 2n + 1
  243. # external objects have ids of the form 4n (due to word alignment)
  244. # self._compute_id returns addresses of the form 2n + 1
  245. # if we multiply by 2, we get ids of the form 4n + 2, thus we get no
  246. # clashes
  247. return llmemory.cast_adr_to_int(self._compute_id(obj)) * 2
  248. def _next_id(self):
  249. # return an id not currently in use (as an address instead of an int)
  250. if self.id_free_list.non_empty():
  251. result = self.id_free_list.pop() # reuse a dead id
  252. else:
  253. # make up a fresh id number
  254. result = llmemory.cast_int_to_adr(self.next_free_id)
  255. self.next_free_id += 2 # only odd numbers, to make lltype
  256. # and llmemory happy and to avoid
  257. # clashes with real addresses
  258. return result
  259. def _compute_id(self, obj):
  260. # look if the object is listed in objects_with_id
  261. result = self.objects_with_id.get(obj)
  262. if not result:
  263. result = self._next_id()
  264. self.objects_with_id.setitem(obj, result)
  265. return result
  266. def update_objects_with_id(self):
  267. old = self.objects_with_id
  268. new_objects_with_id = self.AddressDict(old.length())
  269. old.foreach(self._update_object_id_FAST, new_objects_with_id)
  270. old.delete()
  271. self.objects_with_id = new_objects_with_id
  272. def _update_object_id(self, obj, id, new_objects_with_id):
  273. # safe version (used by subclasses)
  274. if self.surviving(obj):
  275. newobj = self.get_forwarding_address(obj)
  276. new_objects_with_id.setitem(newobj, id)
  277. else:
  278. self.id_free_list.append(id)
  279. def _update_object_id_FAST(self, obj, id, new_objects_with_id):
  280. # unsafe version, assumes that the new_objects_with_id is large enough
  281. if self.surviving(obj):
  282. newobj = self.get_forwarding_address(obj)
  283. new_objects_with_id.insertclean(newobj, id)
  284. else:
  285. self.id_free_list.append(id)
  286. def choose_gc_from_config(config):
  287. """Return a (GCClass, GC_PARAMS) from the given config object.
  288. """
  289. if config.translation.gctransformer != "framework": # for tests
  290. config.translation.gc = "marksweep" # crash if inconsistent
  291. classes = {"marksweep": "marksweep.MarkSweepGC",
  292. "statistics": "marksweep.PrintingMarkSweepGC",
  293. "semispace": "semispace.SemiSpaceGC",
  294. "generation": "generation.GenerationGC",
  295. "hybrid": "hybrid.HybridGC",
  296. "markcompact" : "markcompact.MarkCompactGC",
  297. }
  298. try:
  299. modulename, classname = classes[config.translation.gc].split('.')
  300. except KeyError:
  301. raise ValueError("unknown value for translation.gc: %r" % (
  302. config.translation.gc,))
  303. module = __import__("pypy.rpython.memory.gc." + modulename,
  304. globals(), locals(), [classname])
  305. GCClass = getattr(module, classname)
  306. return GCClass, GCClass.TRANSLATION_PARAMS
  307. def read_from_env(varname):
  308. import os
  309. value = os.environ.get(varname)
  310. if value:
  311. realvalue = value[:-1]
  312. if value[-1] in 'kK':
  313. factor = 1024
  314. elif value[-1] in 'mM':
  315. factor = 1024*1024
  316. elif value[-1] in 'gG':
  317. factor = 1024*1024*1024
  318. else:
  319. factor = 1
  320. realvalue = value
  321. try:
  322. return int(float(realvalue) * factor)
  323. except ValueError:
  324. pass
  325. return -1